about summary refs log tree commit diff
path: root/src
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2022-10-30 08:52:35 +0000
committerbors <bors@rust-lang.org>2022-10-30 08:52:35 +0000
commit962bf63dbfcb190bd752e2dbff7d133ab1101f5c (patch)
tree0d0567de3defda59316b51e53e7687b36025df6f /src
parentc162fd36d250f1a76e00ffa55b9d827d0db7e0bc (diff)
parent0b49a5d17354c3b0980c3148f8291e429fc9a194 (diff)
downloadrust-962bf63dbfcb190bd752e2dbff7d133ab1101f5c.tar.gz
rust-962bf63dbfcb190bd752e2dbff7d133ab1101f5c.zip
Auto merge of #2639 - RalfJung:rustup, r=RalfJung
Rustup
Diffstat (limited to 'src')
-rw-r--r--src/bootstrap/doc.rs66
-rw-r--r--src/bootstrap/test.rs10
-rwxr-xr-xsrc/ci/docker/host-x86_64/x86_64-gnu-tools/checktools.sh6
m---------src/doc/book0
m---------src/doc/reference0
m---------src/doc/rust-by-example0
m---------src/doc/rustc-dev-guide0
-rw-r--r--src/doc/unstable-book/src/language-features/arbitrary-enum-discriminant.md37
-rw-r--r--src/librustdoc/clean/auto_trait.rs2
-rw-r--r--src/librustdoc/clean/blanket_impl.rs2
-rw-r--r--src/librustdoc/clean/inline.rs47
-rw-r--r--src/librustdoc/clean/mod.rs150
-rw-r--r--src/librustdoc/clean/types.rs12
-rw-r--r--src/librustdoc/core.rs8
-rw-r--r--src/librustdoc/formats/cache.rs18
-rw-r--r--src/librustdoc/html/format.rs2
-rw-r--r--src/librustdoc/html/highlight.rs4
-rw-r--r--src/librustdoc/html/render/mod.rs15
-rw-r--r--src/librustdoc/html/sources.rs9
-rw-r--r--src/librustdoc/html/static/css/rustdoc.css139
-rw-r--r--src/librustdoc/html/static/css/themes/ayu.css12
-rw-r--r--src/librustdoc/html/static/css/themes/dark.css14
-rw-r--r--src/librustdoc/html/static/css/themes/light.css14
-rw-r--r--src/librustdoc/html/static/js/main.js2
-rw-r--r--src/librustdoc/html/templates/page.html34
-rw-r--r--src/librustdoc/passes/check_doc_test_visibility.rs4
-rw-r--r--src/librustdoc/passes/collect_intra_doc_links.rs4
-rw-r--r--src/librustdoc/passes/html_tags.rs55
-rw-r--r--src/librustdoc/passes/strip_private.rs2
-rw-r--r--src/librustdoc/passes/stripper.rs44
-rw-r--r--src/librustdoc/visit_ast.rs16
-rw-r--r--src/librustdoc/visit_lib.rs24
-rw-r--r--src/rustdoc-json-types/lib.rs5
-rw-r--r--src/test/codegen/mir-inlined-line-numbers.rs25
-rw-r--r--src/test/run-make-fulldeps/foreign-rust-exceptions/Makefile11
-rw-r--r--src/test/run-make-fulldeps/foreign-rust-exceptions/bar.rs7
-rw-r--r--src/test/run-make-fulldeps/foreign-rust-exceptions/foo.rs13
-rw-r--r--src/test/run-make-fulldeps/obtain-borrowck/driver.rs12
-rw-r--r--src/test/rustdoc-gui/notable-trait.goml39
-rw-r--r--src/test/rustdoc-gui/source-code-page.goml44
-rw-r--r--src/test/rustdoc-json/reexport/reexport_method_from_private_module.rs28
-rw-r--r--src/test/rustdoc-ui/invalid-html-self-closing-tag.rs70
-rw-r--r--src/test/rustdoc-ui/invalid-html-self-closing-tag.stderr80
-rw-r--r--src/test/rustdoc/async-trait.rs16
-rw-r--r--src/test/rustdoc/auxiliary/async-trait-dep.rs9
-rw-r--r--src/test/rustdoc/auxiliary/masked.rs4
-rw-r--r--src/test/rustdoc/auxiliary/reexport-doc-aux.rs5
-rw-r--r--src/test/rustdoc/doc-notable_trait_box_is_not_an_iterator.rs38
-rw-r--r--src/test/rustdoc/masked.rs1
-rw-r--r--src/test/rustdoc/reexport-doc.rs8
-rw-r--r--src/test/ui-fulldeps/session-diagnostic/diagnostic-derive.rs38
-rw-r--r--src/test/ui-fulldeps/session-diagnostic/diagnostic-derive.stderr20
-rw-r--r--src/test/ui-fulldeps/session-diagnostic/subdiagnostic-derive.rs45
-rw-r--r--src/test/ui-fulldeps/session-diagnostic/subdiagnostic-derive.stderr32
-rw-r--r--src/test/ui/associated-types/cache/project-fn-ret-invariant.oneuse.stderr10
-rw-r--r--src/test/ui/associated-types/cache/project-fn-ret-invariant.rs2
-rw-r--r--src/test/ui/async-await/async-fn-nonsend.stderr2
-rw-r--r--src/test/ui/async-await/in-trait/async-associated-types.rs24
-rw-r--r--src/test/ui/async-await/in-trait/async-associated-types.stderr57
-rw-r--r--src/test/ui/async-await/in-trait/async-associated-types2.rs30
-rw-r--r--src/test/ui/async-await/in-trait/async-example-desugared-boxed-in-trait.rs21
-rw-r--r--src/test/ui/async-await/in-trait/async-example-desugared-boxed-in-trait.stderr17
-rw-r--r--src/test/ui/async-await/in-trait/async-example-desugared-boxed.rs24
-rw-r--r--src/test/ui/async-await/in-trait/async-example-desugared-in-trait.rs21
-rw-r--r--src/test/ui/async-await/in-trait/async-example-desugared.rs23
-rw-r--r--src/test/ui/async-await/in-trait/async-example.rs32
-rw-r--r--src/test/ui/async-await/in-trait/async-generics-and-bounds.rs21
-rw-r--r--src/test/ui/async-await/in-trait/async-generics-and-bounds.stderr37
-rw-r--r--src/test/ui/async-await/in-trait/async-generics.rs18
-rw-r--r--src/test/ui/async-await/in-trait/async-generics.stderr37
-rw-r--r--src/test/ui/async-await/in-trait/async-lifetimes-and-bounds.rs20
-rw-r--r--src/test/ui/async-await/in-trait/async-lifetimes-and-bounds.stderr23
-rw-r--r--src/test/ui/async-await/in-trait/async-lifetimes.rs18
-rw-r--r--src/test/ui/async-await/in-trait/async-lifetimes.stderr23
-rw-r--r--src/test/ui/async-await/in-trait/async-recursive-generic.rs21
-rw-r--r--src/test/ui/async-await/in-trait/async-recursive-generic.stderr12
-rw-r--r--src/test/ui/async-await/in-trait/async-recursive.rs21
-rw-r--r--src/test/ui/async-await/in-trait/async-recursive.stderr12
-rw-r--r--src/test/ui/async-await/in-trait/fn-not-async-err.rs17
-rw-r--r--src/test/ui/async-await/in-trait/fn-not-async-err.stderr17
-rw-r--r--src/test/ui/async-await/in-trait/fn-not-async-err2.rs21
-rw-r--r--src/test/ui/async-await/in-trait/fn-not-async-err2.stderr12
-rw-r--r--src/test/ui/async-await/issue-98634.rs50
-rw-r--r--src/test/ui/async-await/issue-98634.stderr60
-rw-r--r--src/test/ui/async-await/issues/issue-72312.stderr13
-rw-r--r--src/test/ui/async-await/multiple-lifetimes/ret-impl-trait-one.stderr2
-rw-r--r--src/test/ui/borrowck/issue-103624.rs31
-rw-r--r--src/test/ui/borrowck/issue-103624.stderr35
-rw-r--r--src/test/ui/cast/issue-88621.rs2
-rw-r--r--src/test/ui/cast/issue-88621.stderr2
-rw-r--r--src/test/ui/cfg/cfg-method-receiver-ok.rs14
-rw-r--r--src/test/ui/cfg/cfg-method-receiver.rs3
-rw-r--r--src/test/ui/cfg/cfg-method-receiver.stderr14
-rw-r--r--src/test/ui/coercion/coerce-block-tail-26978.rs11
-rw-r--r--src/test/ui/coercion/coerce-block-tail-26978.stderr16
-rw-r--r--src/test/ui/coercion/coerce-block-tail-57749.rs35
-rw-r--r--src/test/ui/coercion/coerce-block-tail-57749.stderr14
-rw-r--r--src/test/ui/coercion/coerce-block-tail-83783.rs13
-rw-r--r--src/test/ui/coercion/coerce-block-tail-83783.stderr12
-rw-r--r--src/test/ui/coercion/coerce-block-tail-83850.rs7
-rw-r--r--src/test/ui/coercion/coerce-block-tail-83850.stderr19
-rw-r--r--src/test/ui/coercion/coerce-block-tail.rs6
-rw-r--r--src/test/ui/coercion/coerce-block-tail.stderr16
-rw-r--r--src/test/ui/coercion/issue-36007.rs20
-rw-r--r--src/test/ui/coherence/coherence-default-trait-impl.stderr12
-rw-r--r--src/test/ui/consts/unnormalized-param-env.rs31
-rw-r--r--src/test/ui/dropck/dropck-eyepatch-implies-unsafe-impl.stderr12
-rw-r--r--src/test/ui/dyn-star/no-explicit-dyn-star-cast.rs13
-rw-r--r--src/test/ui/dyn-star/no-explicit-dyn-star-cast.stderr28
-rw-r--r--src/test/ui/dyn-star/no-explicit-dyn-star.rs8
-rw-r--r--src/test/ui/dyn-star/no-explicit-dyn-star.stderr9
-rw-r--r--src/test/ui/enum-discriminant/arbitrary_enum_discriminant-no-repr.rs1
-rw-r--r--src/test/ui/enum-discriminant/arbitrary_enum_discriminant-no-repr.stderr2
-rw-r--r--src/test/ui/enum-discriminant/arbitrary_enum_discriminant.rs2
-rw-r--r--src/test/ui/enum-discriminant/discriminant_value.rs2
-rw-r--r--src/test/ui/enum-discriminant/feature-gate-arbitrary_enum_discriminant.rs10
-rw-r--r--src/test/ui/enum-discriminant/feature-gate-arbitrary_enum_discriminant.stderr36
-rw-r--r--src/test/ui/enum-discriminant/issue-70453-generics-in-discr-ice-2.rs2
-rw-r--r--src/test/ui/enum-discriminant/issue-70453-polymorphic-ctfe.rs2
-rw-r--r--src/test/ui/enum-discriminant/issue-70509-partial_eq.rs2
-rw-r--r--src/test/ui/enum-discriminant/issue-70509-partial_eq.stderr2
-rw-r--r--src/test/ui/error-codes/E0199.stderr6
-rw-r--r--src/test/ui/error-codes/E0200.stderr6
-rw-r--r--src/test/ui/generic-associated-types/issue-87258_a.stderr2
-rw-r--r--src/test/ui/impl-trait/hidden-lifetimes.stderr4
-rw-r--r--src/test/ui/impl-trait/in-trait/early.rs23
-rw-r--r--src/test/ui/impl-trait/issue-103599.rs10
-rw-r--r--src/test/ui/impl-trait/issue-103599.stderr14
-rw-r--r--src/test/ui/impl-trait/multiple-lifetimes/ordinary-bounds-unrelated.stderr2
-rw-r--r--src/test/ui/impl-trait/multiple-lifetimes/ordinary-bounds-unsuited.stderr2
-rw-r--r--src/test/ui/impl-trait/must_outlive_least_region_or_bound.stderr14
-rw-r--r--src/test/ui/impl-trait/region-escape-via-bound.stderr2
-rw-r--r--src/test/ui/impl-trait/static-return-lifetime-infered.stderr8
-rw-r--r--src/test/ui/intrinsics/panic-uninitialized-zeroed.rs2
-rw-r--r--src/test/ui/lifetimes/lifetime-elision-return-type-requires-explicit-lifetime.rs6
-rw-r--r--src/test/ui/lifetimes/lifetime-elision-return-type-requires-explicit-lifetime.stderr14
-rw-r--r--src/test/ui/lint/inline-trait-and-foreign-items.stderr2
-rw-r--r--src/test/ui/lint/no-coverage.stderr2
-rw-r--r--src/test/ui/macros/macro_rules-unmatchable-literals.rs14
-rw-r--r--src/test/ui/macros/macro_rules-unmatchable-literals.stderr14
-rw-r--r--src/test/ui/macros/macros-nonfatal-errors.rs2
-rw-r--r--src/test/ui/marker_trait_attr/overlap-marker-trait-with-static-lifetime.rs10
-rw-r--r--src/test/ui/marker_trait_attr/overlap-marker-trait-with-underscore-lifetime.rs9
-rw-r--r--src/test/ui/marker_trait_attr/overlap-marker-trait-with-underscore-lifetime.stderr31
-rw-r--r--src/test/ui/marker_trait_attr/overlap-marker-trait.rs3
-rw-r--r--src/test/ui/marker_trait_attr/overlap-marker-trait.stderr4
-rw-r--r--src/test/ui/marker_trait_attr/overlap-permitted-for-annotated-marker-traits.rs3
-rw-r--r--src/test/ui/nll/closure-requirements/propagate-approximated-shorter-to-static-comparing-against-free.stderr15
-rw-r--r--src/test/ui/nll/ty-outlives/impl-trait-captures.stderr2
-rw-r--r--src/test/ui/nll/user-annotations/adt-nullary-enums.stderr16
-rw-r--r--src/test/ui/parser/issue-103425.rs15
-rw-r--r--src/test/ui/parser/issue-103425.stderr29
-rw-r--r--src/test/ui/parser/issues/issue-17383.rs7
-rw-r--r--src/test/ui/parser/issues/issue-17383.stderr15
-rw-r--r--src/test/ui/parser/tag-variant-disr-non-nullary.rs12
-rw-r--r--src/test/ui/parser/tag-variant-disr-non-nullary.stderr25
-rw-r--r--src/test/ui/privacy/access_levels.rs75
-rw-r--r--src/test/ui/privacy/access_levels.stderr134
-rw-r--r--src/test/ui/privacy/effective_visibilities.rs75
-rw-r--r--src/test/ui/privacy/effective_visibilities.stderr134
-rw-r--r--src/test/ui/resolve/issue-23305.rs2
-rw-r--r--src/test/ui/resolve/issue-23305.stderr16
-rw-r--r--src/test/ui/resolve/resolve-self-in-impl.rs9
-rw-r--r--src/test/ui/resolve/resolve-self-in-impl.stderr74
-rw-r--r--src/test/ui/rfc-2632-const-trait-impl/issue-102985.rs3
-rw-r--r--src/test/ui/rfc-2632-const-trait-impl/issue-102985.stderr19
-rw-r--r--src/test/ui/rfc-2632-const-trait-impl/issue-103677.rs5
-rw-r--r--src/test/ui/rfc-2632-const-trait-impl/super-traits-fail-2.nn.stderr4
-rw-r--r--src/test/ui/rfc-2632-const-trait-impl/super-traits-fail-2.ny.stderr4
-rw-r--r--src/test/ui/rfc-2632-const-trait-impl/super-traits-fail-3.nn.stderr8
-rw-r--r--src/test/ui/rfc-2632-const-trait-impl/super-traits-fail-3.ny.stderr4
-rw-r--r--src/test/ui/rfc-2632-const-trait-impl/super-traits-fail-3.yn.stderr4
-rw-r--r--src/test/ui/save-analysis/issue-68621.stderr2
-rw-r--r--src/test/ui/self/arbitrary_self_types_pin_lifetime_impl_trait-async.stderr2
-rw-r--r--src/test/ui/self/arbitrary_self_types_pin_lifetime_impl_trait.stderr2
-rw-r--r--src/test/ui/suggestions/format-borrow.stderr16
-rw-r--r--src/test/ui/suggestions/issue-102354.rs10
-rw-r--r--src/test/ui/suggestions/issue-102354.stderr24
-rw-r--r--src/test/ui/suggestions/issue-102892.rs25
-rw-r--r--src/test/ui/suggestions/issue-102892.stderr57
-rw-r--r--src/test/ui/suggestions/lifetimes/missing-lifetimes-in-signature.stderr2
-rw-r--r--src/test/ui/suggestions/lifetimes/trait-object-nested-in-impl-trait.stderr4
-rw-r--r--src/test/ui/traits/safety-trait-impl-cc.stderr6
-rw-r--r--src/test/ui/traits/safety-trait-impl.stderr12
-rw-r--r--src/test/ui/transmutability/enums/should_order_correctly.rs1
-rw-r--r--src/test/ui/transmutability/enums/should_respect_endianness.rs1
-rw-r--r--src/test/ui/transmutability/enums/should_respect_endianness.stderr4
-rw-r--r--src/test/ui/type-alias-impl-trait/issue-101750.rs37
-rw-r--r--src/test/ui/type/issue-94187-verbose-type-name.rs13
-rw-r--r--src/test/ui/wf/issue-103573.rs22
-rw-r--r--src/test/ui/wf/issue-103573.stderr14
m---------src/tools/cargo0
-rw-r--r--src/tools/clippy/clippy_lints/src/casts/ptr_as_ptr.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/copy_iterator.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/default_union_representation.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/dereference.rs26
-rw-r--r--src/tools/clippy/clippy_lints/src/derivable_impls.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/derive.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/doc.rs14
-rw-r--r--src/tools/clippy/clippy_lints/src/empty_enum.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/enum_variants.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/escape.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/exhaustive_items.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/fallible_impl_from.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/format_args.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/from_over_into.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/functions/must_use.rs24
-rw-r--r--src/tools/clippy/clippy_lints/src/functions/not_unsafe_ptr_arg_deref.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/functions/result.rs14
-rw-r--r--src/tools/clippy/clippy_lints/src/implicit_hasher.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/inherent_to_string.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/iter_not_returning_iterator.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/large_enum_variant.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/len_zero.rs12
-rw-r--r--src/tools/clippy/clippy_lints/src/let_if_seq.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/lib.register_all.rs1
-rw-r--r--src/tools/clippy/clippy_lints/src/lib.register_pedantic.rs1
-rw-r--r--src/tools/clippy/clippy_lints/src/lib.register_style.rs1
-rw-r--r--src/tools/clippy/clippy_lints/src/lifetimes.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/manual_non_exhaustive.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/mod.rs12
-rw-r--r--src/tools/clippy/clippy_lints/src/missing_doc.rs10
-rw-r--r--src/tools/clippy/clippy_lints/src/missing_inline.rs10
-rw-r--r--src/tools/clippy/clippy_lints/src/mut_key.rs12
-rw-r--r--src/tools/clippy/clippy_lints/src/needless_pass_by_value.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/new_without_default.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/non_copy_const.rs6
-rw-r--r--src/tools/clippy/clippy_lints/src/non_send_fields_in_send_ty.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/only_used_in_recursion.rs16
-rw-r--r--src/tools/clippy/clippy_lints/src/operators/op_ref.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/partialeq_ne_impl.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/pass_by_ref_or_value.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/ptr.rs8
-rw-r--r--src/tools/clippy/clippy_lints/src/question_mark.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/redundant_pub_crate.rs8
-rw-r--r--src/tools/clippy/clippy_lints/src/return_self_not_must_use.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/same_name_method.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/self_named_constructors.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/trailing_empty_array.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/transmute/transmute_undefined_repr.rs165
-rw-r--r--src/tools/clippy/clippy_lints/src/transmute/utils.rs3
-rw-r--r--src/tools/clippy/clippy_lints/src/types/mod.rs8
-rw-r--r--src/tools/clippy/clippy_lints/src/types/redundant_allocation.rs18
-rw-r--r--src/tools/clippy/clippy_lints/src/types/vec_box.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/unnecessary_wraps.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/unused_self.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/unwrap_in_result.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/upper_case_acronyms.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/use_self.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/wildcard_imports.rs6
-rw-r--r--src/tools/clippy/clippy_utils/src/lib.rs2
-rw-r--r--src/tools/clippy/clippy_utils/src/ty.rs4
-rw-r--r--src/tools/compiletest/src/common.rs8
-rw-r--r--src/tools/compiletest/src/main.rs8
-rw-r--r--src/tools/compiletest/src/runtest.rs35
-rwxr-xr-xsrc/tools/miri/miri2
-rw-r--r--src/tools/miri/rust-version2
-rw-r--r--src/tools/miri/src/stacked_borrows/mod.rs7
-rw-r--r--src/tools/rust-analyzer/.github/workflows/publish.yml6
-rw-r--r--src/tools/rust-analyzer/crates/flycheck/src/lib.rs82
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/macro_expansion_tests/builtin_derive_macro.rs36
-rw-r--r--src/tools/rust-analyzer/crates/hir-expand/src/builtin_derive_macro.rs86
-rw-r--r--src/tools/rust-analyzer/crates/hir-expand/src/mod_path.rs1
-rw-r--r--src/tools/rust-analyzer/crates/hir-expand/src/name.rs2
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/infer.rs13
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/infer/expr.rs99
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/method_resolution.rs18
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/tests/traits.rs92
-rw-r--r--src/tools/rust-analyzer/crates/hir/src/diagnostics.rs14
-rw-r--r--src/tools/rust-analyzer/crates/hir/src/lib.rs38
-rw-r--r--src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_constant.rs12
-rw-r--r--src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_default_from_enum_variant.rs5
-rw-r--r--src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_default_from_new.rs61
-rw-r--r--src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_delegate_methods.rs8
-rw-r--r--src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_deref.rs12
-rw-r--r--src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_documentation_template.rs52
-rw-r--r--src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_enum_is_method.rs18
-rw-r--r--src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_enum_projection_method.rs39
-rw-r--r--src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_from_impl_for_enum.rs19
-rw-r--r--src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_function.rs34
-rw-r--r--src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_getter.rs325
-rw-r--r--src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_impl.rs2
-rw-r--r--src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_new.rs16
-rw-r--r--src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_setter.rs21
-rw-r--r--src/tools/rust-analyzer/crates/ide-assists/src/utils.rs12
-rw-r--r--src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/incorrect_try_expr.rs37
-rw-r--r--src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/not_implemented.rs35
-rw-r--r--src/tools/rust-analyzer/crates/ide-diagnostics/src/lib.rs4
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/hover/tests.rs22
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/lib.rs14
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/parent_module.rs18
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/static_index.rs4
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/status.rs2
-rw-r--r--src/tools/rust-analyzer/crates/project-model/Cargo.toml4
-rw-r--r--src/tools/rust-analyzer/crates/project-model/src/build_scripts.rs380
-rw-r--r--src/tools/rust-analyzer/crates/project-model/src/cargo_workspace.rs52
-rw-r--r--src/tools/rust-analyzer/crates/project-model/src/lib.rs18
-rw-r--r--src/tools/rust-analyzer/crates/project-model/src/sysroot.rs18
-rw-r--r--src/tools/rust-analyzer/crates/project-model/src/workspace.rs69
-rw-r--r--src/tools/rust-analyzer/crates/rust-analyzer/src/cargo_target_spec.rs2
-rw-r--r--src/tools/rust-analyzer/crates/rust-analyzer/src/cli/scip.rs107
-rw-r--r--src/tools/rust-analyzer/crates/rust-analyzer/src/config.rs79
-rw-r--r--src/tools/rust-analyzer/crates/rust-analyzer/src/dispatch.rs4
-rw-r--r--src/tools/rust-analyzer/crates/rust-analyzer/src/global_state.rs10
-rw-r--r--src/tools/rust-analyzer/crates/rust-analyzer/src/handlers.rs16
-rw-r--r--src/tools/rust-analyzer/crates/rust-analyzer/src/lsp_utils.rs10
-rw-r--r--src/tools/rust-analyzer/crates/rust-analyzer/src/main_loop.rs184
-rw-r--r--src/tools/rust-analyzer/crates/rust-analyzer/src/reload.rs75
-rw-r--r--src/tools/rust-analyzer/crates/syntax/src/ast/edit_in_place.rs5
-rw-r--r--src/tools/rust-analyzer/crates/syntax/src/lib.rs2
-rw-r--r--src/tools/rust-analyzer/crates/test-utils/src/minicore.rs39
-rw-r--r--src/tools/rust-analyzer/docs/user/generated_config.adoc38
-rw-r--r--src/tools/rust-analyzer/editors/code/package-lock.json64
-rw-r--r--src/tools/rust-analyzer/editors/code/package.json65
-rw-r--r--src/tools/rust-analyzer/editors/code/src/ast_inspector.ts8
-rw-r--r--src/tools/rust-analyzer/editors/code/src/bootstrap.ts148
-rw-r--r--src/tools/rust-analyzer/editors/code/src/client.ts65
-rw-r--r--src/tools/rust-analyzer/editors/code/src/commands.ts190
-rw-r--r--src/tools/rust-analyzer/editors/code/src/config.ts191
-rw-r--r--src/tools/rust-analyzer/editors/code/src/ctx.ts224
-rw-r--r--src/tools/rust-analyzer/editors/code/src/main.ts475
-rw-r--r--src/tools/rust-analyzer/editors/code/src/run.ts4
-rw-r--r--src/version2
323 files changed, 5302 insertions, 2681 deletions
diff --git a/src/bootstrap/doc.rs b/src/bootstrap/doc.rs
index 7bdd226cb69..ea06caf9c33 100644
--- a/src/bootstrap/doc.rs
+++ b/src/bootstrap/doc.rs
@@ -228,7 +228,7 @@ impl Step for TheBook {
         }
 
         // build the version info page and CSS
-        builder.ensure(Standalone { compiler, target });
+        let shared_assets = builder.ensure(SharedAssets { target });
 
         // build the redirect pages
         builder.info(&format!("Documenting book redirect pages ({})", target));
@@ -237,7 +237,7 @@ impl Step for TheBook {
             let path = file.path();
             let path = path.to_str().unwrap();
 
-            invoke_rustdoc(builder, compiler, target, path);
+            invoke_rustdoc(builder, compiler, &shared_assets, target, path);
         }
 
         if builder.was_invoked_explicitly::<Self>(Kind::Doc) {
@@ -251,6 +251,7 @@ impl Step for TheBook {
 fn invoke_rustdoc(
     builder: &Builder<'_>,
     compiler: Compiler,
+    shared_assets: &SharedAssetsPaths,
     target: TargetSelection,
     markdown: &str,
 ) {
@@ -260,7 +261,6 @@ fn invoke_rustdoc(
 
     let header = builder.src.join("src/doc/redirect.inc");
     let footer = builder.src.join("src/doc/footer.inc");
-    let version_info = out.join("version_info.html");
 
     let mut cmd = builder.rustdoc_cmd(compiler);
 
@@ -269,7 +269,7 @@ fn invoke_rustdoc(
     cmd.arg("--html-after-content")
         .arg(&footer)
         .arg("--html-before-content")
-        .arg(&version_info)
+        .arg(&shared_assets.version_info)
         .arg("--html-in-header")
         .arg(&header)
         .arg("--markdown-no-toc")
@@ -300,7 +300,7 @@ impl Step for Standalone {
 
     fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
         let builder = run.builder;
-        run.path("src/doc").default_condition(builder.config.docs)
+        run.path("src/doc").alias("standalone").default_condition(builder.config.docs)
     }
 
     fn make_run(run: RunConfig<'_>) {
@@ -325,21 +325,11 @@ impl Step for Standalone {
         let out = builder.doc_out(target);
         t!(fs::create_dir_all(&out));
 
+        let version_info = builder.ensure(SharedAssets { target: self.target }).version_info;
+
         let favicon = builder.src.join("src/doc/favicon.inc");
         let footer = builder.src.join("src/doc/footer.inc");
         let full_toc = builder.src.join("src/doc/full-toc.inc");
-        t!(fs::copy(builder.src.join("src/doc/rust.css"), out.join("rust.css")));
-
-        let version_input = builder.src.join("src/doc/version_info.html.template");
-        let version_info = out.join("version_info.html");
-
-        if !builder.config.dry_run && !up_to_date(&version_input, &version_info) {
-            let info = t!(fs::read_to_string(&version_input))
-                .replace("VERSION", &builder.rust_release())
-                .replace("SHORT_HASH", builder.rust_info.sha_short().unwrap_or(""))
-                .replace("STAMP", builder.rust_info.sha().unwrap_or(""));
-            t!(fs::write(&version_info, &info));
-        }
 
         for file in t!(fs::read_dir(builder.src.join("src/doc"))) {
             let file = t!(file);
@@ -401,6 +391,45 @@ impl Step for Standalone {
     }
 }
 
+#[derive(Debug, Clone)]
+pub struct SharedAssetsPaths {
+    pub version_info: PathBuf,
+}
+
+#[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)]
+pub struct SharedAssets {
+    target: TargetSelection,
+}
+
+impl Step for SharedAssets {
+    type Output = SharedAssetsPaths;
+    const DEFAULT: bool = false;
+
+    fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
+        // Other tasks depend on this, no need to execute it on its own
+        run.never()
+    }
+
+    // Generate shared resources used by other pieces of documentation.
+    fn run(self, builder: &Builder<'_>) -> Self::Output {
+        let out = builder.doc_out(self.target);
+
+        let version_input = builder.src.join("src").join("doc").join("version_info.html.template");
+        let version_info = out.join("version_info.html");
+        if !builder.config.dry_run && !up_to_date(&version_input, &version_info) {
+            let info = t!(fs::read_to_string(&version_input))
+                .replace("VERSION", &builder.rust_release())
+                .replace("SHORT_HASH", builder.rust_info.sha_short().unwrap_or(""))
+                .replace("STAMP", builder.rust_info.sha().unwrap_or(""));
+            t!(fs::write(&version_info, &info));
+        }
+
+        builder.copy(&builder.src.join("src").join("doc").join("rust.css"), &out.join("rust.css"));
+
+        SharedAssetsPaths { version_info }
+    }
+}
+
 #[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)]
 pub struct Std {
     pub stage: u32,
@@ -429,7 +458,8 @@ impl Step for Std {
         let target = self.target;
         let out = builder.doc_out(target);
         t!(fs::create_dir_all(&out));
-        t!(fs::copy(builder.src.join("src/doc/rust.css"), out.join("rust.css")));
+
+        builder.ensure(SharedAssets { target: self.target });
 
         let index_page = builder.src.join("src/doc/index.md").into_os_string();
         let mut extra_args = vec![
diff --git a/src/bootstrap/test.rs b/src/bootstrap/test.rs
index ebac73d8aad..7edd3c12041 100644
--- a/src/bootstrap/test.rs
+++ b/src/bootstrap/test.rs
@@ -1418,7 +1418,7 @@ note: if you're sure you want to do this, please open an issue as to why. In the
         }
         let mut flags = if is_rustdoc { Vec::new() } else { vec!["-Crpath".to_string()] };
         flags.push(format!("-Cdebuginfo={}", builder.config.rust_debuginfo_level_tests));
-        flags.push(builder.config.cmd.rustc_args().join(" "));
+        flags.extend(builder.config.cmd.rustc_args().iter().map(|s| s.to_string()));
 
         if let Some(linker) = builder.linker(target) {
             cmd.arg("--linker").arg(linker);
@@ -1427,12 +1427,16 @@ note: if you're sure you want to do this, please open an issue as to why. In the
         let mut hostflags = flags.clone();
         hostflags.push(format!("-Lnative={}", builder.test_helpers_out(compiler.host).display()));
         hostflags.extend(builder.lld_flags(compiler.host));
-        cmd.arg("--host-rustcflags").arg(hostflags.join(" "));
+        for flag in hostflags {
+            cmd.arg("--host-rustcflags").arg(flag);
+        }
 
         let mut targetflags = flags;
         targetflags.push(format!("-Lnative={}", builder.test_helpers_out(target).display()));
         targetflags.extend(builder.lld_flags(target));
-        cmd.arg("--target-rustcflags").arg(targetflags.join(" "));
+        for flag in targetflags {
+            cmd.arg("--target-rustcflags").arg(flag);
+        }
 
         cmd.arg("--python").arg(builder.python());
 
diff --git a/src/ci/docker/host-x86_64/x86_64-gnu-tools/checktools.sh b/src/ci/docker/host-x86_64/x86_64-gnu-tools/checktools.sh
index 80a066cac29..d8738455610 100755
--- a/src/ci/docker/host-x86_64/x86_64-gnu-tools/checktools.sh
+++ b/src/ci/docker/host-x86_64/x86_64-gnu-tools/checktools.sh
@@ -27,6 +27,10 @@ python3 "$X_PY" test --stage 2 src/tools/rustfmt
 python3 "$X_PY" test --stage 2 src/tools/miri
 # We natively run this script on x86_64-unknown-linux-gnu and x86_64-pc-windows-msvc.
 # Also cover some other targets (on both of these hosts) via cross-testing.
-python3 "$X_PY" test --stage 2 src/tools/miri --target i686-pc-windows-msvc
+#
+# Currently disabled -- we end up pulling in a cross-compile of LLVM (maybe
+# just overly eager sanity checks), but in any case this won't work when
+# building LLVM as of this comment.
+#python3 "$X_PY" test --stage 2 src/tools/miri --target i686-pc-windows-msvc
 #FIXME(https://github.com/rust-lang/rust/issues/103519): macOS testing is currently disabled
 # python3 "$X_PY" test --stage 2 src/tools/miri --target aarch64-apple-darwin
diff --git a/src/doc/book b/src/doc/book
-Subproject f1e5ad844d0c61738006cdef26227beeb136948
+Subproject aa5ee485bd6bd80d205da7c82fcdd776f92fdd5
diff --git a/src/doc/reference b/src/doc/reference
-Subproject f6ed74f582bddcec73f753eafaab3749c4f7df6
+Subproject 4ea7c5def38ac81df33a9e48e5637a82a5ac404
diff --git a/src/doc/rust-by-example b/src/doc/rust-by-example
-Subproject 5e7b296d6c345addbd748f242aae28c42555c01
+Subproject 03491f33375c5a2a1661c7fa4be671fe95ce124
diff --git a/src/doc/rustc-dev-guide b/src/doc/rustc-dev-guide
-Subproject 7518c3445dc02df0d196f5f84e568d633c5141f
+Subproject 51a37ad19a15709d0601afbac6581f5aea6a45d
diff --git a/src/doc/unstable-book/src/language-features/arbitrary-enum-discriminant.md b/src/doc/unstable-book/src/language-features/arbitrary-enum-discriminant.md
deleted file mode 100644
index e0bb782270e..00000000000
--- a/src/doc/unstable-book/src/language-features/arbitrary-enum-discriminant.md
+++ /dev/null
@@ -1,37 +0,0 @@
-# `arbitrary_enum_discriminant`
-
-The tracking issue for this feature is: [#60553]
-
-[#60553]: https://github.com/rust-lang/rust/issues/60553
-
-------------------------
-
-The `arbitrary_enum_discriminant` feature permits tuple-like and
-struct-like enum variants with `#[repr(<int-type>)]` to have explicit discriminants.
-
-## Examples
-
-```rust
-#![feature(arbitrary_enum_discriminant)]
-
-#[allow(dead_code)]
-#[repr(u8)]
-enum Enum {
-    Unit = 3,
-    Tuple(u16) = 2,
-    Struct {
-        a: u8,
-        b: u16,
-    } = 1,
-}
-
-impl Enum {
-    fn tag(&self) -> u8 {
-        unsafe { *(self as *const Self as *const u8) }
-    }
-}
-
-assert_eq!(3, Enum::Unit.tag());
-assert_eq!(2, Enum::Tuple(5).tag());
-assert_eq!(1, Enum::Struct{a: 7, b: 11}.tag());
-```
diff --git a/src/librustdoc/clean/auto_trait.rs b/src/librustdoc/clean/auto_trait.rs
index efa9242a467..764a6d3aa48 100644
--- a/src/librustdoc/clean/auto_trait.rs
+++ b/src/librustdoc/clean/auto_trait.rs
@@ -148,7 +148,7 @@ where
             })
             .collect();
         // We are only interested in case the type *doesn't* implement the Sized trait.
-        if !ty.is_sized(tcx.at(rustc_span::DUMMY_SP), param_env) {
+        if !ty.is_sized(tcx, param_env) {
             // In case `#![no_core]` is used, `sized_trait` returns nothing.
             if let Some(item) = tcx.lang_items().sized_trait().and_then(|sized_trait_did| {
                 self.generate_for_trait(ty, sized_trait_did, param_env, item_def_id, &f, true)
diff --git a/src/librustdoc/clean/blanket_impl.rs b/src/librustdoc/clean/blanket_impl.rs
index 7c59e785752..8b63c3db3c3 100644
--- a/src/librustdoc/clean/blanket_impl.rs
+++ b/src/librustdoc/clean/blanket_impl.rs
@@ -20,7 +20,7 @@ impl<'a, 'tcx> BlanketImplFinder<'a, 'tcx> {
         trace!("get_blanket_impls({:?})", ty);
         let mut impls = Vec::new();
         for trait_def_id in cx.tcx.all_traits() {
-            if !cx.cache.access_levels.is_public(trait_def_id)
+            if !cx.cache.effective_visibilities.is_directly_public(trait_def_id)
                 || cx.generated_synthetics.get(&(ty.0, trait_def_id)).is_some()
             {
                 continue;
diff --git a/src/librustdoc/clean/inline.rs b/src/librustdoc/clean/inline.rs
index 432d318907f..b9f787729c1 100644
--- a/src/librustdoc/clean/inline.rs
+++ b/src/librustdoc/clean/inline.rs
@@ -55,12 +55,39 @@ pub(crate) fn try_inline(
     let mut ret = Vec::new();
 
     debug!("attrs={:?}", attrs);
-    let attrs_clone = attrs;
+
+    let attrs_without_docs = attrs.map(|attrs| {
+        attrs.into_iter().filter(|a| a.doc_str().is_none()).cloned().collect::<Vec<_>>()
+    });
+    // We need this ugly code because:
+    //
+    // ```
+    // attrs_without_docs.map(|a| a.as_slice())
+    // ```
+    //
+    // will fail because it returns a temporary slice and:
+    //
+    // ```
+    // attrs_without_docs.map(|s| {
+    //     vec = s.as_slice();
+    //     vec
+    // })
+    // ```
+    //
+    // will fail because we're moving an uninitialized variable into a closure.
+    let vec;
+    let attrs_without_docs = match attrs_without_docs {
+        Some(s) => {
+            vec = s;
+            Some(vec.as_slice())
+        }
+        None => None,
+    };
 
     let kind = match res {
         Res::Def(DefKind::Trait, did) => {
             record_extern_fqn(cx, did, ItemType::Trait);
-            build_impls(cx, Some(parent_module), did, attrs, &mut ret);
+            build_impls(cx, Some(parent_module), did, attrs_without_docs, &mut ret);
             clean::TraitItem(Box::new(build_external_trait(cx, did)))
         }
         Res::Def(DefKind::Fn, did) => {
@@ -69,27 +96,27 @@ pub(crate) fn try_inline(
         }
         Res::Def(DefKind::Struct, did) => {
             record_extern_fqn(cx, did, ItemType::Struct);
-            build_impls(cx, Some(parent_module), did, attrs, &mut ret);
+            build_impls(cx, Some(parent_module), did, attrs_without_docs, &mut ret);
             clean::StructItem(build_struct(cx, did))
         }
         Res::Def(DefKind::Union, did) => {
             record_extern_fqn(cx, did, ItemType::Union);
-            build_impls(cx, Some(parent_module), did, attrs, &mut ret);
+            build_impls(cx, Some(parent_module), did, attrs_without_docs, &mut ret);
             clean::UnionItem(build_union(cx, did))
         }
         Res::Def(DefKind::TyAlias, did) => {
             record_extern_fqn(cx, did, ItemType::Typedef);
-            build_impls(cx, Some(parent_module), did, attrs, &mut ret);
+            build_impls(cx, Some(parent_module), did, attrs_without_docs, &mut ret);
             clean::TypedefItem(build_type_alias(cx, did))
         }
         Res::Def(DefKind::Enum, did) => {
             record_extern_fqn(cx, did, ItemType::Enum);
-            build_impls(cx, Some(parent_module), did, attrs, &mut ret);
+            build_impls(cx, Some(parent_module), did, attrs_without_docs, &mut ret);
             clean::EnumItem(build_enum(cx, did))
         }
         Res::Def(DefKind::ForeignTy, did) => {
             record_extern_fqn(cx, did, ItemType::ForeignType);
-            build_impls(cx, Some(parent_module), did, attrs, &mut ret);
+            build_impls(cx, Some(parent_module), did, attrs_without_docs, &mut ret);
             clean::ForeignTypeItem
         }
         // Never inline enum variants but leave them shown as re-exports.
@@ -123,7 +150,7 @@ pub(crate) fn try_inline(
         _ => return None,
     };
 
-    let (attrs, cfg) = merge_attrs(cx, Some(parent_module), load_attrs(cx, did), attrs_clone);
+    let (attrs, cfg) = merge_attrs(cx, Some(parent_module), load_attrs(cx, did), attrs);
     cx.inlined.insert(did.into());
     let mut item = clean::Item::from_def_id_and_attrs_and_parts(
         did,
@@ -347,7 +374,7 @@ pub(crate) fn build_impl(
     if !did.is_local() {
         if let Some(traitref) = associated_trait {
             let did = traitref.def_id;
-            if !cx.cache.access_levels.is_public(did) {
+            if !cx.cache.effective_visibilities.is_directly_public(did) {
                 return;
             }
 
@@ -376,7 +403,7 @@ pub(crate) fn build_impl(
     // reachable in rustdoc generated documentation
     if !did.is_local() {
         if let Some(did) = for_.def_id(&cx.cache) {
-            if !cx.cache.access_levels.is_public(did) {
+            if !cx.cache.effective_visibilities.is_directly_public(did) {
                 return;
             }
 
diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs
index d86a2682641..64a18757b26 100644
--- a/src/librustdoc/clean/mod.rs
+++ b/src/librustdoc/clean/mod.rs
@@ -415,6 +415,16 @@ fn clean_projection<'tcx>(
     cx: &mut DocContext<'tcx>,
     def_id: Option<DefId>,
 ) -> Type {
+    if cx.tcx.def_kind(ty.item_def_id) == DefKind::ImplTraitPlaceholder {
+        let bounds = cx
+            .tcx
+            .explicit_item_bounds(ty.item_def_id)
+            .iter()
+            .map(|(bound, _)| EarlyBinder(*bound).subst(cx.tcx, ty.substs))
+            .collect::<Vec<_>>();
+        return clean_middle_opaque_bounds(cx, bounds);
+    }
+
     let trait_ = clean_trait_ref_with_bindings(cx, ty.trait_ref(cx.tcx), ThinVec::new());
     let self_type = clean_middle_ty(ty.self_ty(), cx, None);
     let self_def_id = if let Some(def_id) = def_id {
@@ -1032,7 +1042,7 @@ fn clean_poly_trait_ref<'tcx>(
 }
 
 fn clean_trait_item<'tcx>(trait_item: &hir::TraitItem<'tcx>, cx: &mut DocContext<'tcx>) -> Item {
-    let local_did = trait_item.def_id.to_def_id();
+    let local_did = trait_item.owner_id.to_def_id();
     cx.with_param_env(local_did, |cx| {
         let inner = match trait_item.kind {
             hir::TraitItemKind::Const(ty, Some(default)) => AssocConstItem(
@@ -1084,7 +1094,7 @@ pub(crate) fn clean_impl_item<'tcx>(
     impl_: &hir::ImplItem<'tcx>,
     cx: &mut DocContext<'tcx>,
 ) -> Item {
-    let local_did = impl_.def_id.to_def_id();
+    let local_did = impl_.owner_id.to_def_id();
     cx.with_param_env(local_did, |cx| {
         let inner = match impl_.kind {
             hir::ImplItemKind::Const(ty, expr) => {
@@ -1093,7 +1103,7 @@ pub(crate) fn clean_impl_item<'tcx>(
             }
             hir::ImplItemKind::Fn(ref sig, body) => {
                 let m = clean_function(cx, sig, impl_.generics, body);
-                let defaultness = cx.tcx.impl_defaultness(impl_.def_id);
+                let defaultness = cx.tcx.impl_defaultness(impl_.owner_id);
                 MethodItem(m, Some(defaultness))
             }
             hir::ImplItemKind::Type(hir_ty) => {
@@ -1110,7 +1120,7 @@ pub(crate) fn clean_impl_item<'tcx>(
         let mut what_rustc_thinks =
             Item::from_def_id_and_parts(local_did, Some(impl_.ident.name), inner, cx);
 
-        let impl_ref = cx.tcx.impl_trait_ref(cx.tcx.local_parent(impl_.def_id.def_id));
+        let impl_ref = cx.tcx.impl_trait_ref(cx.tcx.local_parent(impl_.owner_id.def_id));
 
         // Trait impl items always inherit the impl's visibility --
         // we don't want to show `pub`.
@@ -1421,7 +1431,7 @@ fn maybe_expand_private_type_alias<'tcx>(
     let Res::Def(DefKind::TyAlias, def_id) = path.res else { return None };
     // Substitute private type aliases
     let def_id = def_id.as_local()?;
-    let alias = if !cx.cache.access_levels.is_exported(def_id.to_def_id()) {
+    let alias = if !cx.cache.effective_visibilities.is_exported(def_id.to_def_id()) {
         &cx.tcx.hir().expect_item(def_id).kind
     } else {
         return None;
@@ -1720,59 +1730,7 @@ pub(crate) fn clean_middle_ty<'tcx>(
                 .iter()
                 .map(|(bound, _)| EarlyBinder(*bound).subst(cx.tcx, substs))
                 .collect::<Vec<_>>();
-            let mut regions = vec![];
-            let mut has_sized = false;
-            let mut bounds = bounds
-                .iter()
-                .filter_map(|bound| {
-                    let bound_predicate = bound.kind();
-                    let trait_ref = match bound_predicate.skip_binder() {
-                        ty::PredicateKind::Trait(tr) => bound_predicate.rebind(tr.trait_ref),
-                        ty::PredicateKind::TypeOutlives(ty::OutlivesPredicate(_ty, reg)) => {
-                            if let Some(r) = clean_middle_region(reg) {
-                                regions.push(GenericBound::Outlives(r));
-                            }
-                            return None;
-                        }
-                        _ => return None,
-                    };
-
-                    if let Some(sized) = cx.tcx.lang_items().sized_trait() {
-                        if trait_ref.def_id() == sized {
-                            has_sized = true;
-                            return None;
-                        }
-                    }
-
-                    let bindings: ThinVec<_> = bounds
-                        .iter()
-                        .filter_map(|bound| {
-                            if let ty::PredicateKind::Projection(proj) = bound.kind().skip_binder()
-                            {
-                                if proj.projection_ty.trait_ref(cx.tcx) == trait_ref.skip_binder() {
-                                    Some(TypeBinding {
-                                        assoc: projection_to_path_segment(proj.projection_ty, cx),
-                                        kind: TypeBindingKind::Equality {
-                                            term: clean_middle_term(proj.term, cx),
-                                        },
-                                    })
-                                } else {
-                                    None
-                                }
-                            } else {
-                                None
-                            }
-                        })
-                        .collect();
-
-                    Some(clean_poly_trait_ref_with_bindings(cx, trait_ref, bindings))
-                })
-                .collect::<Vec<_>>();
-            bounds.extend(regions);
-            if !has_sized && !bounds.is_empty() {
-                bounds.insert(0, GenericBound::maybe_sized(cx));
-            }
-            ImplTrait(bounds)
+            clean_middle_opaque_bounds(cx, bounds)
         }
 
         ty::Closure(..) => panic!("Closure"),
@@ -1785,6 +1743,64 @@ pub(crate) fn clean_middle_ty<'tcx>(
     }
 }
 
+fn clean_middle_opaque_bounds<'tcx>(
+    cx: &mut DocContext<'tcx>,
+    bounds: Vec<ty::Predicate<'tcx>>,
+) -> Type {
+    let mut regions = vec![];
+    let mut has_sized = false;
+    let mut bounds = bounds
+        .iter()
+        .filter_map(|bound| {
+            let bound_predicate = bound.kind();
+            let trait_ref = match bound_predicate.skip_binder() {
+                ty::PredicateKind::Trait(tr) => bound_predicate.rebind(tr.trait_ref),
+                ty::PredicateKind::TypeOutlives(ty::OutlivesPredicate(_ty, reg)) => {
+                    if let Some(r) = clean_middle_region(reg) {
+                        regions.push(GenericBound::Outlives(r));
+                    }
+                    return None;
+                }
+                _ => return None,
+            };
+
+            if let Some(sized) = cx.tcx.lang_items().sized_trait() {
+                if trait_ref.def_id() == sized {
+                    has_sized = true;
+                    return None;
+                }
+            }
+
+            let bindings: ThinVec<_> = bounds
+                .iter()
+                .filter_map(|bound| {
+                    if let ty::PredicateKind::Projection(proj) = bound.kind().skip_binder() {
+                        if proj.projection_ty.trait_ref(cx.tcx) == trait_ref.skip_binder() {
+                            Some(TypeBinding {
+                                assoc: projection_to_path_segment(proj.projection_ty, cx),
+                                kind: TypeBindingKind::Equality {
+                                    term: clean_middle_term(proj.term, cx),
+                                },
+                            })
+                        } else {
+                            None
+                        }
+                    } else {
+                        None
+                    }
+                })
+                .collect();
+
+            Some(clean_poly_trait_ref_with_bindings(cx, trait_ref, bindings))
+        })
+        .collect::<Vec<_>>();
+    bounds.extend(regions);
+    if !has_sized && !bounds.is_empty() {
+        bounds.insert(0, GenericBound::maybe_sized(cx));
+    }
+    ImplTrait(bounds)
+}
+
 pub(crate) fn clean_field<'tcx>(field: &hir::FieldDef<'tcx>, cx: &mut DocContext<'tcx>) -> Item {
     let def_id = cx.tcx.hir().local_def_id(field.hir_id).to_def_id();
     clean_field_with_def_id(def_id, field.ident.name, clean_ty(field.ty, cx), cx)
@@ -1942,7 +1958,7 @@ fn clean_maybe_renamed_item<'tcx>(
 ) -> Vec<Item> {
     use hir::ItemKind;
 
-    let def_id = item.def_id.to_def_id();
+    let def_id = item.owner_id.to_def_id();
     let mut name = renamed.unwrap_or_else(|| cx.tcx.hir().name(item.hir_id()));
     cx.with_param_env(def_id, |cx| {
         let kind = match item.kind {
@@ -2084,11 +2100,11 @@ fn clean_extern_crate<'tcx>(
     cx: &mut DocContext<'tcx>,
 ) -> Vec<Item> {
     // this is the ID of the `extern crate` statement
-    let cnum = cx.tcx.extern_mod_stmt_cnum(krate.def_id.def_id).unwrap_or(LOCAL_CRATE);
+    let cnum = cx.tcx.extern_mod_stmt_cnum(krate.owner_id.def_id).unwrap_or(LOCAL_CRATE);
     // this is the ID of the crate itself
     let crate_def_id = cnum.as_def_id();
     let attrs = cx.tcx.hir().attrs(krate.hir_id());
-    let ty_vis = cx.tcx.visibility(krate.def_id);
+    let ty_vis = cx.tcx.visibility(krate.owner_id);
     let please_inline = ty_vis.is_public()
         && attrs.iter().any(|a| {
             a.has_name(sym::doc)
@@ -2106,7 +2122,7 @@ fn clean_extern_crate<'tcx>(
         if let Some(items) = inline::try_inline(
             cx,
             cx.tcx.parent_module(krate.hir_id()).to_def_id(),
-            Some(krate.def_id.to_def_id()),
+            Some(krate.owner_id.to_def_id()),
             res,
             name,
             Some(attrs),
@@ -2142,11 +2158,11 @@ fn clean_use_statement<'tcx>(
         return Vec::new();
     }
 
-    let visibility = cx.tcx.visibility(import.def_id);
+    let visibility = cx.tcx.visibility(import.owner_id);
     let attrs = cx.tcx.hir().attrs(import.hir_id());
     let inline_attr = attrs.lists(sym::doc).get_word_attr(sym::inline);
     let pub_underscore = visibility.is_public() && name == kw::Underscore;
-    let current_mod = cx.tcx.parent_module_from_def_id(import.def_id.def_id);
+    let current_mod = cx.tcx.parent_module_from_def_id(import.owner_id.def_id);
 
     // The parent of the module in which this import resides. This
     // is the same as `current_mod` if that's already the top
@@ -2217,7 +2233,7 @@ fn clean_use_statement<'tcx>(
         }
         if !denied {
             let mut visited = FxHashSet::default();
-            let import_def_id = import.def_id.to_def_id();
+            let import_def_id = import.owner_id.to_def_id();
 
             if let Some(mut items) = inline::try_inline(
                 cx,
@@ -2240,7 +2256,7 @@ fn clean_use_statement<'tcx>(
         Import::new_simple(name, resolve_use_source(cx, path), true)
     };
 
-    vec![Item::from_def_id_and_parts(import.def_id.to_def_id(), None, ImportItem(inner), cx)]
+    vec![Item::from_def_id_and_parts(import.owner_id.to_def_id(), None, ImportItem(inner), cx)]
 }
 
 fn clean_maybe_renamed_foreign_item<'tcx>(
@@ -2248,7 +2264,7 @@ fn clean_maybe_renamed_foreign_item<'tcx>(
     item: &hir::ForeignItem<'tcx>,
     renamed: Option<Symbol>,
 ) -> Item {
-    let def_id = item.def_id.to_def_id();
+    let def_id = item.owner_id.to_def_id();
     cx.with_param_env(def_id, |cx| {
         let kind = match item.kind {
             hir::ForeignItemKind::Fn(decl, names, generics) => {
diff --git a/src/librustdoc/clean/types.rs b/src/librustdoc/clean/types.rs
index 4c130b2ffec..cd1f972dce8 100644
--- a/src/librustdoc/clean/types.rs
+++ b/src/librustdoc/clean/types.rs
@@ -240,13 +240,13 @@ impl ExternalCrate {
                     let item = tcx.hir().item(id);
                     match item.kind {
                         hir::ItemKind::Mod(_) => {
-                            as_keyword(Res::Def(DefKind::Mod, id.def_id.to_def_id()))
+                            as_keyword(Res::Def(DefKind::Mod, id.owner_id.to_def_id()))
                         }
                         hir::ItemKind::Use(path, hir::UseKind::Single)
-                            if tcx.visibility(id.def_id).is_public() =>
+                            if tcx.visibility(id.owner_id).is_public() =>
                         {
                             as_keyword(path.res.expect_non_local())
-                                .map(|(_, prim)| (id.def_id.to_def_id(), prim))
+                                .map(|(_, prim)| (id.owner_id.to_def_id(), prim))
                         }
                         _ => None,
                     }
@@ -308,14 +308,14 @@ impl ExternalCrate {
                     let item = tcx.hir().item(id);
                     match item.kind {
                         hir::ItemKind::Mod(_) => {
-                            as_primitive(Res::Def(DefKind::Mod, id.def_id.to_def_id()))
+                            as_primitive(Res::Def(DefKind::Mod, id.owner_id.to_def_id()))
                         }
                         hir::ItemKind::Use(path, hir::UseKind::Single)
-                            if tcx.visibility(id.def_id).is_public() =>
+                            if tcx.visibility(id.owner_id).is_public() =>
                         {
                             as_primitive(path.res.expect_non_local()).map(|(_, prim)| {
                                 // Pretend the primitive is local.
-                                (id.def_id.to_def_id(), prim)
+                                (id.owner_id.to_def_id(), prim)
                             })
                         }
                         _ => None,
diff --git a/src/librustdoc/core.rs b/src/librustdoc/core.rs
index 8232353f915..3e5f42b7a80 100644
--- a/src/librustdoc/core.rs
+++ b/src/librustdoc/core.rs
@@ -1,6 +1,7 @@
 use rustc_ast::NodeId;
 use rustc_data_structures::fx::{FxHashMap, FxHashSet};
 use rustc_data_structures::sync::{self, Lrc};
+use rustc_data_structures::unord::UnordSet;
 use rustc_errors::emitter::{Emitter, EmitterWriter};
 use rustc_errors::json::JsonEmitter;
 use rustc_feature::UnstableFeatures;
@@ -288,8 +289,7 @@ pub(crate) fn create_config(
             providers.typeck_item_bodies = |_, _| {};
             // hack so that `used_trait_imports` won't try to call typeck
             providers.used_trait_imports = |_, _| {
-                static EMPTY_SET: LazyLock<FxHashSet<LocalDefId>> =
-                    LazyLock::new(FxHashSet::default);
+                static EMPTY_SET: LazyLock<UnordSet<LocalDefId>> = LazyLock::new(UnordSet::default);
                 &EMPTY_SET
             };
             // In case typeck does end up being called, don't ICE in case there were name resolution errors
@@ -348,7 +348,7 @@ pub(crate) fn run_global_ctxt(
 
     let auto_traits =
         tcx.all_traits().filter(|&trait_def_id| tcx.trait_is_auto(trait_def_id)).collect();
-    let access_levels = tcx.privacy_access_levels(()).map_id(Into::into);
+    let effective_visibilities = tcx.effective_visibilities(()).map_id(Into::into);
 
     let mut ctxt = DocContext {
         tcx,
@@ -361,7 +361,7 @@ pub(crate) fn run_global_ctxt(
         impl_trait_bounds: Default::default(),
         generated_synthetics: Default::default(),
         auto_traits,
-        cache: Cache::new(access_levels, render_options.document_private),
+        cache: Cache::new(effective_visibilities, render_options.document_private),
         inlined: FxHashSet::default(),
         output_format,
         render_options,
diff --git a/src/librustdoc/formats/cache.rs b/src/librustdoc/formats/cache.rs
index 2e428cfddcf..afe2264e8bf 100644
--- a/src/librustdoc/formats/cache.rs
+++ b/src/librustdoc/formats/cache.rs
@@ -2,7 +2,7 @@ use std::mem;
 
 use rustc_data_structures::fx::{FxHashMap, FxHashSet};
 use rustc_hir::def_id::{CrateNum, DefId};
-use rustc_middle::middle::privacy::AccessLevels;
+use rustc_middle::middle::privacy::EffectiveVisibilities;
 use rustc_middle::ty::{self, TyCtxt};
 use rustc_span::Symbol;
 
@@ -77,8 +77,8 @@ pub(crate) struct Cache {
 
     // Note that external items for which `doc(hidden)` applies to are shown as
     // non-reachable while local items aren't. This is because we're reusing
-    // the access levels from the privacy check pass.
-    pub(crate) access_levels: AccessLevels<DefId>,
+    // the effective visibilities from the privacy check pass.
+    pub(crate) effective_visibilities: EffectiveVisibilities<DefId>,
 
     /// The version of the crate being documented, if given from the `--crate-version` flag.
     pub(crate) crate_version: Option<String>,
@@ -132,8 +132,11 @@ struct CacheBuilder<'a, 'tcx> {
 }
 
 impl Cache {
-    pub(crate) fn new(access_levels: AccessLevels<DefId>, document_private: bool) -> Self {
-        Cache { access_levels, document_private, ..Cache::default() }
+    pub(crate) fn new(
+        effective_visibilities: EffectiveVisibilities<DefId>,
+        document_private: bool,
+    ) -> Self {
+        Cache { effective_visibilities, document_private, ..Cache::default() }
     }
 
     /// Populates the `Cache` with more data. The returned `Crate` will be missing some data that was
@@ -381,7 +384,10 @@ impl<'a, 'tcx> DocFolder for CacheBuilder<'a, 'tcx> {
                     // paths map if there was already an entry present and we're
                     // not a public item.
                     if !self.cache.paths.contains_key(&item.item_id.expect_def_id())
-                        || self.cache.access_levels.is_public(item.item_id.expect_def_id())
+                        || self
+                            .cache
+                            .effective_visibilities
+                            .is_directly_public(item.item_id.expect_def_id())
                     {
                         self.cache.paths.insert(
                             item.item_id.expect_def_id(),
diff --git a/src/librustdoc/html/format.rs b/src/librustdoc/html/format.rs
index 7d00002d05b..92e7f2739af 100644
--- a/src/librustdoc/html/format.rs
+++ b/src/librustdoc/html/format.rs
@@ -659,7 +659,7 @@ pub(crate) fn href_with_root_path(
     }
 
     if !did.is_local()
-        && !cache.access_levels.is_public(did)
+        && !cache.effective_visibilities.is_directly_public(did)
         && !cache.document_private
         && !cache.primitive_locations.values().any(|&id| id == did)
     {
diff --git a/src/librustdoc/html/highlight.rs b/src/librustdoc/html/highlight.rs
index 5e28204b21d..28136cc48d6 100644
--- a/src/librustdoc/html/highlight.rs
+++ b/src/librustdoc/html/highlight.rs
@@ -72,8 +72,12 @@ pub(crate) fn render_source_with_highlighting(
     line_numbers: Buffer,
     href_context: HrefContext<'_, '_, '_>,
     decoration_info: DecorationInfo,
+    extra: Option<&str>,
 ) {
     write_header(out, "", Some(line_numbers), Tooltip::None);
+    if let Some(extra) = extra {
+        out.push_str(extra);
+    }
     write_code(out, src, Some(href_context), Some(decoration_info));
     write_footer(out, None);
 }
diff --git a/src/librustdoc/html/render/mod.rs b/src/librustdoc/html/render/mod.rs
index eeec6f8fee7..27dea8ec0b3 100644
--- a/src/librustdoc/html/render/mod.rs
+++ b/src/librustdoc/html/render/mod.rs
@@ -1276,6 +1276,15 @@ fn notable_traits_decl(decl: &clean::FnDecl, cx: &Context<'_>) -> String {
 
     if let Some((did, ty)) = decl.output.as_return().and_then(|t| Some((t.def_id(cx.cache())?, t)))
     {
+        // Box has pass-through impls for Read, Write, Iterator, and Future when the
+        // boxed type implements one of those. We don't want to treat every Box return
+        // as being notably an Iterator (etc), though, so we exempt it. Pin has the same
+        // issue, with a pass-through impl for Future.
+        if Some(did) == cx.tcx().lang_items().owned_box()
+            || Some(did) == cx.tcx().lang_items().pin_type()
+        {
+            return "".to_string();
+        }
         if let Some(impls) = cx.cache().impls.get(&did) {
             for i in impls {
                 let impl_ = i.inner_impl();
@@ -2860,10 +2869,6 @@ fn render_call_locations(w: &mut Buffer, cx: &mut Context<'_>, item: &clean::Ite
             write!(w, r#"<span class="prev">&pr;</span> <span class="next">&sc;</span>"#);
         }
 
-        if needs_expansion {
-            write!(w, r#"<span class="expand">&varr;</span>"#);
-        }
-
         // Look for the example file in the source map if it exists, otherwise return a dummy span
         let file_span = (|| {
             let source_map = tcx.sess.source_map();
@@ -2897,7 +2902,7 @@ fn render_call_locations(w: &mut Buffer, cx: &mut Context<'_>, item: &clean::Ite
             cx,
             &root_path,
             highlight::DecorationInfo(decoration_info),
-            sources::SourceContext::Embedded { offset: line_min },
+            sources::SourceContext::Embedded { offset: line_min, needs_expansion },
         );
         write!(w, "</div></div>");
 
diff --git a/src/librustdoc/html/sources.rs b/src/librustdoc/html/sources.rs
index 7ab65bff346..8a01c01049d 100644
--- a/src/librustdoc/html/sources.rs
+++ b/src/librustdoc/html/sources.rs
@@ -258,7 +258,7 @@ where
 
 pub(crate) enum SourceContext {
     Standalone,
-    Embedded { offset: usize },
+    Embedded { offset: usize, needs_expansion: bool },
 }
 
 /// Wrapper struct to render the source code of a file. This will do things like
@@ -274,14 +274,18 @@ pub(crate) fn print_src(
 ) {
     let lines = s.lines().count();
     let mut line_numbers = Buffer::empty_from(buf);
+    let extra;
     line_numbers.write_str("<pre class=\"src-line-numbers\">");
     match source_context {
         SourceContext::Standalone => {
+            extra = None;
             for line in 1..=lines {
                 writeln!(line_numbers, "<span id=\"{0}\">{0}</span>", line)
             }
         }
-        SourceContext::Embedded { offset } => {
+        SourceContext::Embedded { offset, needs_expansion } => {
+            extra =
+                if needs_expansion { Some(r#"<span class="expand">&varr;</span>"#) } else { None };
             for line in 1..=lines {
                 writeln!(line_numbers, "<span>{0}</span>", line + offset)
             }
@@ -297,5 +301,6 @@ pub(crate) fn print_src(
         line_numbers,
         highlight::HrefContext { context, file_span, root_path, current_href },
         decoration_info,
+        extra,
     );
 }
diff --git a/src/librustdoc/html/static/css/rustdoc.css b/src/librustdoc/html/static/css/rustdoc.css
index 173553ed477..330bdb45465 100644
--- a/src/librustdoc/html/static/css/rustdoc.css
+++ b/src/librustdoc/html/static/css/rustdoc.css
@@ -292,10 +292,6 @@ p:last-child {
 	margin: 0;
 }
 
-summary {
-	outline: none;
-}
-
 /* Fix some style changes due to normalize.css 8 */
 
 button {
@@ -497,9 +493,7 @@ ul.block, .block li {
 .sidebar h2 {
 	overflow-wrap: anywhere;
 	padding: 0;
-	margin: 0;
-	margin-top: 0.7rem;
-	margin-bottom: 0.7rem;
+	margin: 0.7rem 0;
 }
 
 .sidebar h3 {
@@ -549,47 +543,46 @@ ul.block, .block li {
 	margin-bottom: 0px;
 }
 
-pre.example-line-numbers {
+.rustdoc .example-wrap > pre {
+	margin: 0;
+	flex-grow: 1;
+	overflow-x: auto;
+}
+
+.rustdoc .example-wrap > pre.example-line-numbers,
+.rustdoc .example-wrap > pre.src-line-numbers {
+	flex-grow: 0;
 	overflow: initial;
+	text-align: right;
+	-webkit-user-select: none;
+	-moz-user-select: none;
+	-ms-user-select: none;
+	user-select: none;
+}
+
+.example-line-numbers {
 	border: 1px solid;
 	padding: 13px 8px;
-	text-align: right;
 	border-top-left-radius: 5px;
 	border-bottom-left-radius: 5px;
+	border-color: var(--example-line-numbers-border-color);
 }
 
-.src-line-numbers {
-	text-align: right;
-}
-.rustdoc:not(.source) .example-wrap > pre:not(.example-line-numbers) {
-	width: 100%;
-	overflow-x: auto;
+.src-line-numbers span {
+	cursor: pointer;
+	color: var(--src-line-numbers-span-color);
 }
-
-.rustdoc:not(.source) .example-wrap > pre.src-line-numbers {
-	width: auto;
-	overflow-x: visible;
+.src-line-numbers .line-highlighted {
+	background-color: var(--src-line-number-highlighted-background-color);
 }
-
-.rustdoc .example-wrap > pre {
-	margin: 0;
+.src-line-numbers :target {
+	background-color: transparent;
 }
 
 .search-loading {
 	text-align: center;
 }
 
-.content > .example-wrap pre.src-line-numbers {
-	position: relative;
-	-webkit-user-select: none;
-	-moz-user-select: none;
-	-ms-user-select: none;
-	user-select: none;
-}
-.src-line-numbers span {
-	cursor: pointer;
-}
-
 .docblock-short {
 	overflow-wrap: break-word;
 	overflow-wrap: anywhere;
@@ -688,13 +681,16 @@ nav.sub {
 	display: flex;
 	align-items: center;
 }
-nav.sub form {
+.search-form {
+	position: relative;
+	display: flex;
+	height: 34px;
 	flex-grow: 1;
 }
 .source nav.sub {
 	margin: 0 0 15px 0;
 }
-.source nav.sub form {
+.source .search-form {
 	margin-left: 32px;
 }
 
@@ -785,11 +781,6 @@ table,
 	padding-right: 1.25rem;
 }
 
-.search-container {
-	position: relative;
-	display: flex;
-	height: 34px;
-}
 .search-results-title {
 	margin-top: 0;
 	white-space: nowrap;
@@ -810,10 +801,8 @@ table,
 }
 #crate-search {
 	min-width: 115px;
-	padding: 0;
 	/* keep these two in sync with "@-moz-document url-prefix()" below */
-	padding-left: 4px;
-	padding-right: 23px;
+	padding: 0 23px 0 4px;
 	/* prevents the <select> from overflowing the containing div in case it's shrunk */
 	max-width: 100%;
 	/* contents can overflow because of max-width limit, then show ellipsis */
@@ -865,17 +854,12 @@ so that we can apply CSS-filters to change the arrow color in themes */
 	   -webkit-appearance: textfield for search inputs. That
 	   causes rounded corners and no border on iOS Safari. */
 	-webkit-appearance: none;
-	/* Override Normalize.css: we have margins and do
-	 not want to overflow - the `moz` attribute is necessary
-	 until Firefox 29, too early to drop at this point */
-	-moz-box-sizing: border-box !important;
-	box-sizing: border-box !important;
 	outline: none;
 	border: 1px solid var(--border-color);
 	border-radius: 2px;
 	padding: 8px;
 	font-size: 1rem;
-	width: 100%;
+	flex-grow: 1;
 	background-color: var(--button-background-color);
 	color: var(--search-color);
 }
@@ -1302,7 +1286,7 @@ h3.variant {
 	content: "\00a0\00a0\00a0";
 }
 
-.notable-traits .notable, .notable-traits .docblock {
+.notable-traits .docblock {
 	margin: 0;
 }
 
@@ -1538,6 +1522,8 @@ details.rustdoc-toggle > summary.hideme {
 
 details.rustdoc-toggle > summary {
 	list-style: none;
+	/* focus outline is shown on `::before` instead of this */
+	outline: none;
 }
 details.rustdoc-toggle > summary::-webkit-details-marker,
 details.rustdoc-toggle > summary::marker {
@@ -1585,6 +1571,15 @@ details.rustdoc-toggle > summary:hover::before {
 	opacity: 1;
 }
 
+details.rustdoc-toggle > summary:focus-visible::before {
+	/* The SVG is black, and gets turned white using a filter in the dark themes.
+	   Do the same with the outline.
+	   The dotted 1px style is copied from Firefox's focus ring style.
+	*/
+	outline: 1px dotted #000;
+	outline-offset: 1px;
+}
+
 details.rustdoc-toggle.top-doc > summary,
 details.rustdoc-toggle.top-doc > summary::before,
 details.rustdoc-toggle.non-exhaustive > summary,
@@ -1720,7 +1715,6 @@ in storage.js
 		/* Hide the sidebar offscreen while not in use. Doing this instead of display: none means
 		   the sidebar stays visible for screen readers, which is useful for navigation. */
 		left: -1000px;
-		margin-left: 0;
 		margin: 0;
 		padding: 0;
 		z-index: 11;
@@ -1773,9 +1767,7 @@ in storage.js
 	.mobile-topbar .logo-container > img {
 		max-width: 35px;
 		max-height: 35px;
-		margin-left: 20px;
-		margin-top: 5px;
-		margin-bottom: 5px;
+		margin: 5px 0 5px 20px;
 	}
 
 	.mobile-topbar {
@@ -1953,7 +1945,7 @@ in storage.js
 		flex-direction: column;
 	}
 
-	nav.sub form {
+	.search-form {
 		align-self: stretch;
 	}
 
@@ -2024,49 +2016,36 @@ in storage.js
 	padding-bottom: 0;
 }
 
-.scraped-example:not(.expanded) .code-wrapper pre.src-line-numbers {
-	overflow-x: hidden;
-}
-
-.scraped-example .code-wrapper .prev {
+.scraped-example .code-wrapper .next,
+.scraped-example .code-wrapper .prev,
+.scraped-example .code-wrapper .expand {
 	position: absolute;
 	top: 0.25em;
-	right: 2.25em;
-	z-index: 100;
+	z-index: 1;
 	cursor: pointer;
 }
-
+.scraped-example .code-wrapper .prev {
+	right: 2.25em;
+}
 .scraped-example .code-wrapper .next {
-	position: absolute;
-	top: 0.25em;
 	right: 1.25em;
-	z-index: 100;
-	cursor: pointer;
 }
-
 .scraped-example .code-wrapper .expand {
-	position: absolute;
-	top: 0.25em;
 	right: 0.25em;
-	z-index: 100;
-	cursor: pointer;
 }
 
-.scraped-example:not(.expanded) .code-wrapper:before {
+.scraped-example:not(.expanded) .code-wrapper:before,
+.scraped-example:not(.expanded) .code-wrapper:after {
 	content: " ";
 	width: 100%;
 	height: 5px;
 	position: absolute;
-	z-index: 100;
+	z-index: 1;
+}
+.scraped-example:not(.expanded) .code-wrapper:before {
 	top: 0;
 }
-
 .scraped-example:not(.expanded) .code-wrapper:after {
-	content: " ";
-	width: 100%;
-	height: 5px;
-	position: absolute;
-	z-index: 100;
 	bottom: 0;
 }
 
diff --git a/src/librustdoc/html/static/css/themes/ayu.css b/src/librustdoc/html/static/css/themes/ayu.css
index 33817c16808..fdfdb3e1966 100644
--- a/src/librustdoc/html/static/css/themes/ayu.css
+++ b/src/librustdoc/html/static/css/themes/ayu.css
@@ -55,6 +55,9 @@ Original by Dempfi (https://github.com/dempfi/ayu)
 	--code-highlight-question-mark-color: #ff9011;
 	--code-highlight-comment-color: #788797;
 	--code-highlight-doc-comment-color: #a1ac88;
+	--example-line-numbers-border-color: none;
+	--src-line-numbers-span-color: #5c6773;
+	--src-line-number-highlighted-background-color: rgba(255, 236, 164, 0.06);
 }
 
 .slider {
@@ -112,10 +115,8 @@ pre, .rustdoc.source .example-wrap {
 	color: #ff7733;
 }
 
-.src-line-numbers span { color: #5c6773; }
 .src-line-numbers .line-highlighted {
 	color: #708090;
-	background-color: rgba(255, 236, 164, 0.06);
 	padding-right: 4px;
 	border-right: 1px solid #ffb44c;
 }
@@ -170,13 +171,6 @@ details.rustdoc-toggle > summary::before {
 	color: #788797;
 }
 
-.src-line-numbers :target { background-color: transparent; }
-
-pre.example-line-numbers {
-	color: #5c67736e;
-	border: none;
-}
-
 a.test-arrow {
 	font-size: 100%;
 	color: #788797;
diff --git a/src/librustdoc/html/static/css/themes/dark.css b/src/librustdoc/html/static/css/themes/dark.css
index d88710288b9..361d3d4a225 100644
--- a/src/librustdoc/html/static/css/themes/dark.css
+++ b/src/librustdoc/html/static/css/themes/dark.css
@@ -50,6 +50,9 @@
 	--code-highlight-question-mark-color: #ff9011;
 	--code-highlight-comment-color: #8d8d8b;
 	--code-highlight-doc-comment-color: #8ca375;
+	--example-line-numbers-border-color: #4a4949;
+	--src-line-numbers-span-color: #3b91e2;
+	--src-line-number-highlighted-background-color: #0a042f;
 }
 
 .slider {
@@ -69,11 +72,6 @@ input:focus + .slider {
 		drop-shadow(0 -1px 0 #fff)
 }
 
-.src-line-numbers span { color: #3B91E2; }
-.src-line-numbers .line-highlighted {
-	background-color: #0a042f !important;
-}
-
 .content .item-info::before { color: #ccc; }
 
 body.source .example-wrap pre.rust a {
@@ -95,12 +93,6 @@ details.rustdoc-toggle > summary::before {
 	filter: invert(69%) sepia(60%) saturate(6613%) hue-rotate(184deg) brightness(100%) contrast(91%);
 }
 
-.src-line-numbers :target { background-color: transparent; }
-
-pre.example-line-numbers {
-	border-color: #4a4949;
-}
-
 a.test-arrow {
 	color: #dedede;
 	background-color: rgba(78, 139, 202, 0.2);
diff --git a/src/librustdoc/html/static/css/themes/light.css b/src/librustdoc/html/static/css/themes/light.css
index cadc71dab95..5eb4bbcf834 100644
--- a/src/librustdoc/html/static/css/themes/light.css
+++ b/src/librustdoc/html/static/css/themes/light.css
@@ -50,6 +50,9 @@
 	--code-highlight-question-mark-color: #ff9011;
 	--code-highlight-comment-color: #8e908c;
 	--code-highlight-doc-comment-color: #4d4d4c;
+	--example-line-numbers-border-color: #c7c7c7;
+	--src-line-numbers-span-color: #c67e2d;
+	--src-line-number-highlighted-background-color: #fdffd3;
 }
 
 .slider {
@@ -68,11 +71,6 @@ input:focus + .slider {
 	 */
 }
 
-.src-line-numbers span { color: #c67e2d; }
-.src-line-numbers .line-highlighted {
-	background-color: #FDFFD3 !important;
-}
-
 .content .item-info::before { color: #ccc; }
 
 body.source .example-wrap pre.rust a {
@@ -90,12 +88,6 @@ body.source .example-wrap pre.rust a {
 	filter: invert(44%) sepia(18%) saturate(23%) hue-rotate(317deg) brightness(96%) contrast(93%);
 }
 
-.src-line-numbers :target { background-color: transparent; }
-
-pre.example-line-numbers {
-	border-color: #c7c7c7;
-}
-
 a.test-arrow {
 	color: #f5f5f5;
 	background-color: rgba(78, 139, 202, 0.2);
diff --git a/src/librustdoc/html/static/js/main.js b/src/librustdoc/html/static/js/main.js
index 0b816eace64..33480fa41cf 100644
--- a/src/librustdoc/html/static/js/main.js
+++ b/src/librustdoc/html/static/js/main.js
@@ -932,7 +932,7 @@ function loadCss(cssFileName) {
      * Hide all the popover menus.
      */
     window.hidePopoverMenus = function() {
-        onEachLazy(document.querySelectorAll(".search-container .popover"), elem => {
+        onEachLazy(document.querySelectorAll(".search-form .popover"), elem => {
             elem.style.display = "none";
         });
     };
diff --git a/src/librustdoc/html/templates/page.html b/src/librustdoc/html/templates/page.html
index ee8938ea603..c3238691687 100644
--- a/src/librustdoc/html/templates/page.html
+++ b/src/librustdoc/html/templates/page.html
@@ -115,24 +115,22 @@
                 </a> {#- -#}
                 {%- endif -%}
                 <form class="search-form"> {#- -#}
-                    <div class="search-container"> {#- -#}
-                        <span></span> {#- This empty span is a hacky fix for Safari - See #93184 -#}
-                        <input {# -#}
-                            class="search-input" {# -#}
-                            name="search" {# -#}
-                            autocomplete="off" {# -#}
-                            spellcheck="false" {# -#}
-                            placeholder="Click or press ‘S’ to search, ‘?’ for more options…" {# -#}
-                            type="search"> {#- -#}
-                        <div id="help-button" title="help" tabindex="-1"> {#- -#}
-                            <a href="{{page.root_path|safe}}help.html">?</a> {#- -#}
-                        </div> {#- -#}
-                        <div id="settings-menu" tabindex="-1"> {#- -#}
-                            <a href="{{page.root_path|safe}}settings.html" title="settings"> {#- -#}
-                                <img width="22" height="22" alt="Change settings" {# -#}
-                                 src="{{static_root_path|safe}}wheel{{page.resource_suffix}}.svg"> {#- -#}
-                            </a> {#- -#}
-                        </div> {#- -#}
+                    <span></span> {#- This empty span is a hacky fix for Safari - See #93184 -#}
+                    <input {# -#}
+                        class="search-input" {# -#}
+                        name="search" {# -#}
+                        autocomplete="off" {# -#}
+                        spellcheck="false" {# -#}
+                        placeholder="Click or press ‘S’ to search, ‘?’ for more options…" {# -#}
+                        type="search"> {#- -#}
+                    <div id="help-button" title="help" tabindex="-1"> {#- -#}
+                        <a href="{{page.root_path|safe}}help.html">?</a> {#- -#}
+                    </div> {#- -#}
+                    <div id="settings-menu" tabindex="-1"> {#- -#}
+                        <a href="{{page.root_path|safe}}settings.html" title="settings"> {#- -#}
+                            <img width="22" height="22" alt="Change settings" {# -#}
+                             src="{{static_root_path|safe}}wheel{{page.resource_suffix}}.svg"> {#- -#}
+                        </a> {#- -#}
                     </div> {#- -#}
                 </form> {#- -#}
             </nav> {#- -#}
diff --git a/src/librustdoc/passes/check_doc_test_visibility.rs b/src/librustdoc/passes/check_doc_test_visibility.rs
index 15982b40944..7740c6d5bbb 100644
--- a/src/librustdoc/passes/check_doc_test_visibility.rs
+++ b/src/librustdoc/passes/check_doc_test_visibility.rs
@@ -56,7 +56,7 @@ impl crate::doctest::Tester for Tests {
 }
 
 pub(crate) fn should_have_doc_example(cx: &DocContext<'_>, item: &clean::Item) -> bool {
-    if !cx.cache.access_levels.is_public(item.item_id.expect_def_id())
+    if !cx.cache.effective_visibilities.is_directly_public(item.item_id.expect_def_id())
         || matches!(
             *item.kind,
             clean::StructFieldItem(_)
@@ -130,7 +130,7 @@ pub(crate) fn look_for_tests<'tcx>(cx: &DocContext<'tcx>, dox: &str, item: &Item
             );
         }
     } else if tests.found_tests > 0
-        && !cx.cache.access_levels.is_exported(item.item_id.expect_def_id())
+        && !cx.cache.effective_visibilities.is_exported(item.item_id.expect_def_id())
     {
         cx.tcx.struct_span_lint_hir(
             crate::lint::PRIVATE_DOC_TESTS,
diff --git a/src/librustdoc/passes/collect_intra_doc_links.rs b/src/librustdoc/passes/collect_intra_doc_links.rs
index 3513c13d522..8aa0abd369c 100644
--- a/src/librustdoc/passes/collect_intra_doc_links.rs
+++ b/src/librustdoc/passes/collect_intra_doc_links.rs
@@ -1202,8 +1202,8 @@ impl LinkCollector<'_, '_> {
                 item.item_id.expect_def_id().as_local().map(|src_id| (src_id, dst_id))
             })
         {
-            if self.cx.tcx.privacy_access_levels(()).is_exported(src_id)
-                && !self.cx.tcx.privacy_access_levels(()).is_exported(dst_id)
+            if self.cx.tcx.effective_visibilities(()).is_exported(src_id)
+                && !self.cx.tcx.effective_visibilities(()).is_exported(dst_id)
             {
                 privacy_error(self.cx, diag_info, path_str);
             }
diff --git a/src/librustdoc/passes/html_tags.rs b/src/librustdoc/passes/html_tags.rs
index 67fc71665cc..a89ed7c7ed4 100644
--- a/src/librustdoc/passes/html_tags.rs
+++ b/src/librustdoc/passes/html_tags.rs
@@ -184,7 +184,60 @@ fn extract_html_tag(
                     }
                     drop_tag(tags, tag_name, r, f);
                 } else {
-                    tags.push((tag_name, r));
+                    let mut is_self_closing = false;
+                    let mut quote_pos = None;
+                    if c != '>' {
+                        let mut quote = None;
+                        let mut after_eq = false;
+                        for (i, c) in text[pos..].char_indices() {
+                            if !c.is_whitespace() {
+                                if let Some(q) = quote {
+                                    if c == q {
+                                        quote = None;
+                                        quote_pos = None;
+                                        after_eq = false;
+                                    }
+                                } else if c == '>' {
+                                    break;
+                                } else if c == '/' && !after_eq {
+                                    is_self_closing = true;
+                                } else {
+                                    if is_self_closing {
+                                        is_self_closing = false;
+                                    }
+                                    if (c == '"' || c == '\'') && after_eq {
+                                        quote = Some(c);
+                                        quote_pos = Some(pos + i);
+                                    } else if c == '=' {
+                                        after_eq = true;
+                                    }
+                                }
+                            } else if quote.is_none() {
+                                after_eq = false;
+                            }
+                        }
+                    }
+                    if let Some(quote_pos) = quote_pos {
+                        let qr = Range { start: quote_pos, end: quote_pos };
+                        f(
+                            &format!("unclosed quoted HTML attribute on tag `{}`", tag_name),
+                            &qr,
+                            false,
+                        );
+                    }
+                    if is_self_closing {
+                        // https://html.spec.whatwg.org/#parse-error-non-void-html-element-start-tag-with-trailing-solidus
+                        let valid = ALLOWED_UNCLOSED.contains(&&tag_name[..])
+                            || tags.iter().take(pos + 1).any(|(at, _)| {
+                                let at = at.to_lowercase();
+                                at == "svg" || at == "math"
+                            });
+                        if !valid {
+                            f(&format!("invalid self-closing HTML tag `{}`", tag_name), &r, false);
+                        }
+                    } else {
+                        tags.push((tag_name, r));
+                    }
                 }
             }
             break;
diff --git a/src/librustdoc/passes/strip_private.rs b/src/librustdoc/passes/strip_private.rs
index f3aa3c7ce24..450f69e15d1 100644
--- a/src/librustdoc/passes/strip_private.rs
+++ b/src/librustdoc/passes/strip_private.rs
@@ -23,7 +23,7 @@ pub(crate) fn strip_private(mut krate: clean::Crate, cx: &mut DocContext<'_>) ->
     {
         let mut stripper = Stripper {
             retained: &mut retained,
-            access_levels: &cx.cache.access_levels,
+            effective_visibilities: &cx.cache.effective_visibilities,
             update_retained: true,
             is_json_output,
         };
diff --git a/src/librustdoc/passes/stripper.rs b/src/librustdoc/passes/stripper.rs
index a9d768f0149..0089ce63d07 100644
--- a/src/librustdoc/passes/stripper.rs
+++ b/src/librustdoc/passes/stripper.rs
@@ -1,15 +1,17 @@
 //! A collection of utility functions for the `strip_*` passes.
 use rustc_hir::def_id::DefId;
-use rustc_middle::middle::privacy::AccessLevels;
+use rustc_middle::middle::privacy::EffectiveVisibilities;
+use rustc_span::symbol::sym;
+
 use std::mem;
 
-use crate::clean::{self, Item, ItemId, ItemIdSet};
+use crate::clean::{self, Item, ItemId, ItemIdSet, NestedAttributesExt};
 use crate::fold::{strip_item, DocFolder};
 use crate::formats::cache::Cache;
 
 pub(crate) struct Stripper<'a> {
     pub(crate) retained: &'a mut ItemIdSet,
-    pub(crate) access_levels: &'a AccessLevels<DefId>,
+    pub(crate) effective_visibilities: &'a EffectiveVisibilities<DefId>,
     pub(crate) update_retained: bool,
     pub(crate) is_json_output: bool,
 }
@@ -20,13 +22,13 @@ pub(crate) struct Stripper<'a> {
 #[inline]
 fn is_item_reachable(
     is_json_output: bool,
-    access_levels: &AccessLevels<DefId>,
+    effective_visibilities: &EffectiveVisibilities<DefId>,
     item_id: ItemId,
 ) -> bool {
     if is_json_output {
-        access_levels.is_reachable(item_id.expect_def_id())
+        effective_visibilities.is_reachable(item_id.expect_def_id())
     } else {
-        access_levels.is_exported(item_id.expect_def_id())
+        effective_visibilities.is_exported(item_id.expect_def_id())
     }
 }
 
@@ -64,7 +66,7 @@ impl<'a> DocFolder for Stripper<'a> {
             | clean::ForeignTypeItem => {
                 let item_id = i.item_id;
                 if item_id.is_local()
-                    && !is_item_reachable(self.is_json_output, self.access_levels, item_id)
+                    && !is_item_reachable(self.is_json_output, self.effective_visibilities, item_id)
                 {
                     debug!("Stripper: stripping {:?} {:?}", i.type_(), i.name);
                     return None;
@@ -151,6 +153,22 @@ pub(crate) struct ImplStripper<'a> {
     pub(crate) document_private: bool,
 }
 
+impl<'a> ImplStripper<'a> {
+    #[inline]
+    fn should_keep_impl(&self, item: &Item, for_def_id: DefId) -> bool {
+        if !for_def_id.is_local() || self.retained.contains(&for_def_id.into()) {
+            true
+        } else if self.is_json_output {
+            // If the "for" item is exported and the impl block isn't `#[doc(hidden)]`, then we
+            // need to keep it.
+            self.cache.effective_visibilities.is_exported(for_def_id)
+                && !item.attrs.lists(sym::doc).has_word(sym::hidden)
+        } else {
+            false
+        }
+    }
+}
+
 impl<'a> DocFolder for ImplStripper<'a> {
     fn fold_item(&mut self, i: Item) -> Option<Item> {
         if let clean::ImplItem(ref imp) = *i.kind {
@@ -168,7 +186,7 @@ impl<'a> DocFolder for ImplStripper<'a> {
                         item_id.is_local()
                             && !is_item_reachable(
                                 self.is_json_output,
-                                &self.cache.access_levels,
+                                &self.cache.effective_visibilities,
                                 item_id,
                             )
                     })
@@ -178,15 +196,17 @@ impl<'a> DocFolder for ImplStripper<'a> {
                     return None;
                 }
             }
+            // Because we don't inline in `maybe_inline_local` if the output format is JSON,
+            // we need to make a special check for JSON output: we want to keep it unless it has
+            // a `#[doc(hidden)]` attribute if the `for_` type is exported.
             if let Some(did) = imp.for_.def_id(self.cache) {
-                if did.is_local() && !imp.for_.is_assoc_ty() && !self.retained.contains(&did.into())
-                {
+                if !imp.for_.is_assoc_ty() && !self.should_keep_impl(&i, did) {
                     debug!("ImplStripper: impl item for stripped type; removing");
                     return None;
                 }
             }
             if let Some(did) = imp.trait_.as_ref().map(|t| t.def_id()) {
-                if did.is_local() && !self.retained.contains(&did.into()) {
+                if !self.should_keep_impl(&i, did) {
                     debug!("ImplStripper: impl item for stripped trait; removing");
                     return None;
                 }
@@ -194,7 +214,7 @@ impl<'a> DocFolder for ImplStripper<'a> {
             if let Some(generics) = imp.trait_.as_ref().and_then(|t| t.generics()) {
                 for typaram in generics {
                     if let Some(did) = typaram.def_id(self.cache) {
-                        if did.is_local() && !self.retained.contains(&did.into()) {
+                        if !self.should_keep_impl(&i, did) {
                             debug!(
                                 "ImplStripper: stripped item in trait's generics; removing impl"
                             );
diff --git a/src/librustdoc/visit_ast.rs b/src/librustdoc/visit_ast.rs
index b8522ea5d8f..06dffce555f 100644
--- a/src/librustdoc/visit_ast.rs
+++ b/src/librustdoc/visit_ast.rs
@@ -7,7 +7,7 @@ use rustc_hir::def::{DefKind, Res};
 use rustc_hir::def_id::DefId;
 use rustc_hir::Node;
 use rustc_hir::CRATE_HIR_ID;
-use rustc_middle::middle::privacy::AccessLevel;
+use rustc_middle::middle::privacy::Level;
 use rustc_middle::ty::{TyCtxt, Visibility};
 use rustc_span::def_id::{CRATE_DEF_ID, LOCAL_CRATE};
 use rustc_span::symbol::{kw, sym, Symbol};
@@ -230,10 +230,10 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> {
                     } else {
                         // All items need to be handled here in case someone wishes to link
                         // to them with intra-doc links
-                        self.cx.cache.access_levels.set_access_level(
+                        self.cx.cache.effective_visibilities.set_public_at_level(
                             did,
                             || Visibility::Restricted(CRATE_DEF_ID),
-                            AccessLevel::Public,
+                            Level::Direct,
                         );
                     }
                 }
@@ -246,7 +246,7 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> {
             None => return false,
         };
 
-        let is_private = !self.cx.cache.access_levels.is_public(res_did);
+        let is_private = !self.cx.cache.effective_visibilities.is_directly_public(res_did);
         let is_hidden = inherits_doc_hidden(self.cx.tcx, res_hir_id);
 
         // Only inline if requested or if the item would otherwise be stripped.
@@ -295,11 +295,11 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> {
         debug!("visiting item {:?}", item);
         let name = renamed.unwrap_or(item.ident.name);
 
-        let def_id = item.def_id.to_def_id();
+        let def_id = item.owner_id.to_def_id();
         let is_pub = self.cx.tcx.visibility(def_id).is_public();
 
         if is_pub {
-            self.store_path(item.def_id.to_def_id());
+            self.store_path(item.owner_id.to_def_id());
         }
 
         match item.kind {
@@ -360,7 +360,7 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> {
                 // 3. We're inlining, since a reexport where inlining has been requested
                 //    should be inlined even if it is also documented at the top level.
 
-                let def_id = item.def_id.to_def_id();
+                let def_id = item.owner_id.to_def_id();
                 let is_macro_2_0 = !macro_def.macro_rules;
                 let nonexported = !self.cx.tcx.has_attr(def_id, sym::macro_export);
 
@@ -405,7 +405,7 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> {
         om: &mut Module<'tcx>,
     ) {
         // If inlining we only want to include public functions.
-        if !self.inlining || self.cx.tcx.visibility(item.def_id).is_public() {
+        if !self.inlining || self.cx.tcx.visibility(item.owner_id).is_public() {
             om.foreigns.push((item, renamed));
         }
     }
diff --git a/src/librustdoc/visit_lib.rs b/src/librustdoc/visit_lib.rs
index 0511494668b..70214e2adba 100644
--- a/src/librustdoc/visit_lib.rs
+++ b/src/librustdoc/visit_lib.rs
@@ -1,7 +1,7 @@
 use rustc_data_structures::fx::FxHashSet;
 use rustc_hir::def::{DefKind, Res};
 use rustc_hir::def_id::{CrateNum, DefId, CRATE_DEF_ID};
-use rustc_middle::middle::privacy::{AccessLevel, AccessLevels};
+use rustc_middle::middle::privacy::{EffectiveVisibilities, Level};
 use rustc_middle::ty::{TyCtxt, Visibility};
 
 // FIXME: this may not be exhaustive, but is sufficient for rustdocs current uses
@@ -10,10 +10,10 @@ use rustc_middle::ty::{TyCtxt, Visibility};
 /// specific rustdoc annotations into account (i.e., `doc(hidden)`)
 pub(crate) struct LibEmbargoVisitor<'a, 'tcx> {
     tcx: TyCtxt<'tcx>,
-    // Accessibility levels for reachable nodes
-    access_levels: &'a mut AccessLevels<DefId>,
-    // Previous accessibility level, None means unreachable
-    prev_level: Option<AccessLevel>,
+    // Effective visibilities for reachable nodes
+    effective_visibilities: &'a mut EffectiveVisibilities<DefId>,
+    // Previous level, None means unreachable
+    prev_level: Option<Level>,
     // Keeps track of already visited modules, in case a module re-exports its parent
     visited_mods: FxHashSet<DefId>,
 }
@@ -22,26 +22,26 @@ impl<'a, 'tcx> LibEmbargoVisitor<'a, 'tcx> {
     pub(crate) fn new(cx: &'a mut crate::core::DocContext<'tcx>) -> LibEmbargoVisitor<'a, 'tcx> {
         LibEmbargoVisitor {
             tcx: cx.tcx,
-            access_levels: &mut cx.cache.access_levels,
-            prev_level: Some(AccessLevel::Public),
+            effective_visibilities: &mut cx.cache.effective_visibilities,
+            prev_level: Some(Level::Direct),
             visited_mods: FxHashSet::default(),
         }
     }
 
     pub(crate) fn visit_lib(&mut self, cnum: CrateNum) {
         let did = cnum.as_def_id();
-        self.update(did, Some(AccessLevel::Public));
+        self.update(did, Some(Level::Direct));
         self.visit_mod(did);
     }
 
     // Updates node level and returns the updated level
-    fn update(&mut self, did: DefId, level: Option<AccessLevel>) -> Option<AccessLevel> {
+    fn update(&mut self, did: DefId, level: Option<Level>) -> Option<Level> {
         let is_hidden = self.tcx.is_doc_hidden(did);
 
-        let old_level = self.access_levels.get_access_level(did);
-        // Accessibility levels can only grow
+        let old_level = self.effective_visibilities.public_at_level(did);
+        // Visibility levels can only grow
         if level > old_level && !is_hidden {
-            self.access_levels.set_access_level(
+            self.effective_visibilities.set_public_at_level(
                 did,
                 || Visibility::Restricted(CRATE_DEF_ID),
                 level.unwrap(),
diff --git a/src/rustdoc-json-types/lib.rs b/src/rustdoc-json-types/lib.rs
index 7379b04ad16..4bc91fc4030 100644
--- a/src/rustdoc-json-types/lib.rs
+++ b/src/rustdoc-json-types/lib.rs
@@ -51,6 +51,11 @@ pub struct ItemSummary {
     pub crate_id: u32,
     /// The list of path components for the fully qualified path of this item (e.g.
     /// `["std", "io", "lazy", "Lazy"]` for `std::io::lazy::Lazy`).
+    ///
+    /// Note that items can appear in multiple paths, and the one chosen is implementation
+    /// defined. Currenty, this is the full path to where the item was defined. Eg
+    /// [`String`] is currently `["alloc", "string", "String"]` and [`HashMap`] is
+    /// `["std", "collections", "hash", "map", "HashMap"]`, but this is subject to change.
     pub path: Vec<String>,
     /// Whether this item is a struct, trait, macro, etc.
     pub kind: ItemKind,
diff --git a/src/test/codegen/mir-inlined-line-numbers.rs b/src/test/codegen/mir-inlined-line-numbers.rs
new file mode 100644
index 00000000000..19d83f0eee7
--- /dev/null
+++ b/src/test/codegen/mir-inlined-line-numbers.rs
@@ -0,0 +1,25 @@
+// compile-flags: -O -g
+
+#![crate_type = "lib"]
+
+#[inline(always)]
+fn foo() {
+    bar();
+}
+
+#[inline(never)]
+#[no_mangle]
+fn bar() {
+    panic!();
+}
+
+#[no_mangle]
+pub fn example() {
+    foo();
+}
+
+// CHECK-LABEL: @example
+// CHECK:   tail call void @bar(), !dbg [[DBG_ID:![0-9]+]]
+// CHECK: [[DBG_ID]] = !DILocation(line: 7,
+// CHECK-SAME:                     inlinedAt: [[INLINE_ID:![0-9]+]])
+// CHECK: [[INLINE_ID]] = !DILocation(line: 18,
diff --git a/src/test/run-make-fulldeps/foreign-rust-exceptions/Makefile b/src/test/run-make-fulldeps/foreign-rust-exceptions/Makefile
new file mode 100644
index 00000000000..50fca7f24e6
--- /dev/null
+++ b/src/test/run-make-fulldeps/foreign-rust-exceptions/Makefile
@@ -0,0 +1,11 @@
+# ignore-i686-pc-windows-gnu
+
+# This test doesn't work on 32-bit MinGW as cdylib has its own copy of unwinder
+# so cross-DLL unwinding does not work.
+
+include ../tools.mk
+
+all:
+	$(RUSTC) bar.rs --crate-type=cdylib
+	$(RUSTC) foo.rs
+	$(call RUN,foo) 2>&1 | $(CGREP) "Rust cannot catch foreign exceptions"
diff --git a/src/test/run-make-fulldeps/foreign-rust-exceptions/bar.rs b/src/test/run-make-fulldeps/foreign-rust-exceptions/bar.rs
new file mode 100644
index 00000000000..5f9efe32360
--- /dev/null
+++ b/src/test/run-make-fulldeps/foreign-rust-exceptions/bar.rs
@@ -0,0 +1,7 @@
+#![crate_type = "cdylib"]
+#![feature(c_unwind)]
+
+#[no_mangle]
+extern "C-unwind" fn panic() {
+    panic!();
+}
diff --git a/src/test/run-make-fulldeps/foreign-rust-exceptions/foo.rs b/src/test/run-make-fulldeps/foreign-rust-exceptions/foo.rs
new file mode 100644
index 00000000000..266987c5b6d
--- /dev/null
+++ b/src/test/run-make-fulldeps/foreign-rust-exceptions/foo.rs
@@ -0,0 +1,13 @@
+#![feature(c_unwind)]
+
+#[cfg_attr(not(windows), link(name = "bar"))]
+#[cfg_attr(windows, link(name = "bar.dll"))]
+extern "C-unwind" {
+    fn panic();
+}
+
+fn main() {
+    let _ = std::panic::catch_unwind(|| {
+        unsafe { panic() };
+    });
+}
diff --git a/src/test/run-make-fulldeps/obtain-borrowck/driver.rs b/src/test/run-make-fulldeps/obtain-borrowck/driver.rs
index 8f78bda033e..a6c60df83a6 100644
--- a/src/test/run-make-fulldeps/obtain-borrowck/driver.rs
+++ b/src/test/run-make-fulldeps/obtain-borrowck/driver.rs
@@ -69,25 +69,25 @@ impl rustc_driver::Callbacks for CompilerCalls {
 
             let crate_items = tcx.hir_crate_items(());
             for id in crate_items.items() {
-                if matches!(tcx.def_kind(id.def_id), DefKind::Fn) {
-                    bodies.push(id.def_id);
+                if matches!(tcx.def_kind(id.owner_id), DefKind::Fn) {
+                    bodies.push(id.owner_id);
                 }
             }
 
             for id in crate_items.trait_items() {
-                if matches!(tcx.def_kind(id.def_id), DefKind::AssocFn) {
+                if matches!(tcx.def_kind(id.owner_id), DefKind::AssocFn) {
                     let trait_item = hir.trait_item(id);
                     if let rustc_hir::TraitItemKind::Fn(_, trait_fn) = &trait_item.kind {
                         if let rustc_hir::TraitFn::Provided(_) = trait_fn {
-                            bodies.push(trait_item.def_id);
+                            bodies.push(trait_item.owner_id);
                         }
                     }
                 }
             }
 
             for id in crate_items.impl_items() {
-                if matches!(tcx.def_kind(id.def_id), DefKind::AssocFn) {
-                    bodies.push(id.def_id);
+                if matches!(tcx.def_kind(id.owner_id), DefKind::AssocFn) {
+                    bodies.push(id.owner_id);
                 }
             }
 
diff --git a/src/test/rustdoc-gui/notable-trait.goml b/src/test/rustdoc-gui/notable-trait.goml
index 997fb5cf0ad..efe0cb15f08 100644
--- a/src/test/rustdoc-gui/notable-trait.goml
+++ b/src/test/rustdoc-gui/notable-trait.goml
@@ -24,7 +24,23 @@ assert-position: (
     "//*[@id='method.create_an_iterator_from_read']//*[@class='notable-traits']",
     {"x": 951},
 )
-
+// The tooltip should be beside the `i`
+click: "//*[@id='method.create_an_iterator_from_read']//*[@class='notable-traits']"
+compare-elements-position-near: (
+    "//*[@id='method.create_an_iterator_from_read']//*[@class='notable-traits']",
+    "//*[@id='method.create_an_iterator_from_read']//*[@class='notable-traits-tooltiptext force-tooltip']",
+    {"y": 2}
+)
+compare-elements-position-false: (
+    "//*[@id='method.create_an_iterator_from_read']//*[@class='notable-traits']",
+    "//*[@id='method.create_an_iterator_from_read']//*[@class='notable-traits-tooltiptext force-tooltip']",
+    ("x")
+)
+// The docblock should be flush with the border.
+assert-css: (
+    "//*[@id='method.create_an_iterator_from_read']//*[@class='notable-traits-tooltiptext force-tooltip']/*[@class='docblock']",
+    {"margin-left": "0px"}
+)
 
 // Now only the `i` should be on the next line.
 size: (1055, 600)
@@ -81,6 +97,27 @@ assert-position: (
     "//*[@id='method.create_an_iterator_from_read']//*[@class='notable-traits']",
     {"x": 289},
 )
+// The tooltip should be below `i`
+compare-elements-position-near-false: (
+    "//*[@id='method.create_an_iterator_from_read']//*[@class='notable-traits']",
+    "//*[@id='method.create_an_iterator_from_read']//*[@class='notable-traits-tooltiptext force-tooltip']",
+    {"y": 2}
+)
+compare-elements-position-false: (
+    "//*[@id='method.create_an_iterator_from_read']//*[@class='notable-traits']",
+    "//*[@id='method.create_an_iterator_from_read']//*[@class='notable-traits-tooltiptext force-tooltip']",
+    ("x")
+)
+compare-elements-position-near: (
+    "//*[@id='method.create_an_iterator_from_read']/parent::*",
+    "//*[@id='method.create_an_iterator_from_read']//*[@class='notable-traits-tooltiptext force-tooltip']",
+    {"x": 5}
+)
+// The docblock should be flush with the border.
+assert-css: (
+    "//*[@id='method.create_an_iterator_from_read']//*[@class='notable-traits-tooltiptext force-tooltip']/*[@class='docblock']",
+    {"margin-left": "0px"}
+)
 
 // Checking on very small mobile. The `i` should be on its own line.
 size: (365, 600)
diff --git a/src/test/rustdoc-gui/source-code-page.goml b/src/test/rustdoc-gui/source-code-page.goml
index 29d65fc7ebc..a2dac2aa681 100644
--- a/src/test/rustdoc-gui/source-code-page.goml
+++ b/src/test/rustdoc-gui/source-code-page.goml
@@ -1,5 +1,6 @@
 // Checks that the interactions with the source code pages are working as expected.
 goto: "file://" + |DOC_PATH| + "/src/test_docs/lib.rs.html"
+show-text: true
 // Check that we can click on the line number.
 click: ".src-line-numbers > span:nth-child(4)" // This is the span for line 4.
 // Ensure that the page URL was updated.
@@ -12,6 +13,48 @@ assert-attribute: (".src-line-numbers > span:nth-child(4)", {"class": "line-high
 assert-attribute: (".src-line-numbers > span:nth-child(5)", {"class": "line-highlighted"})
 assert-attribute: (".src-line-numbers > span:nth-child(6)", {"class": "line-highlighted"})
 assert-attribute-false: (".src-line-numbers > span:nth-child(7)", {"class": "line-highlighted"})
+
+define-function: (
+    "check-colors",
+    (theme, color, background_color, highlight_color, highlight_background_color),
+    [
+        ("local-storage", {"rustdoc-theme": |theme|, "rustdoc-use-system-theme": "false"}),
+        ("reload"),
+        ("assert-css", (
+            ".src-line-numbers > span:not(.line-highlighted)",
+            {"color": |color|, "background-color": |background_color|},
+            ALL,
+        )),
+        ("assert-css", (
+            ".src-line-numbers > span.line-highlighted",
+            {"color": |highlight_color|, "background-color": |highlight_background_color|},
+            ALL,
+        )),
+    ],
+)
+
+call-function: ("check-colors", {
+    "theme": "ayu",
+    "color": "rgb(92, 103, 115)",
+    "background_color": "rgba(0, 0, 0, 0)",
+    "highlight_color": "rgb(112, 128, 144)",
+    "highlight_background_color": "rgba(255, 236, 164, 0.06)",
+})
+call-function: ("check-colors", {
+    "theme": "dark",
+    "color": "rgb(59, 145, 226)",
+    "background_color": "rgba(0, 0, 0, 0)",
+    "highlight_color": "rgb(59, 145, 226)",
+    "highlight_background_color": "rgb(10, 4, 47)",
+})
+call-function: ("check-colors", {
+    "theme": "light",
+    "color": "rgb(198, 126, 45)",
+    "background_color": "rgba(0, 0, 0, 0)",
+    "highlight_color": "rgb(198, 126, 45)",
+    "highlight_background_color": "rgb(253, 255, 211)",
+})
+
 // This is to ensure that the content is correctly align with the line numbers.
 compare-elements-position: ("//*[@id='1']", ".rust > code > span", ("y"))
 
@@ -20,7 +63,6 @@ assert-css: (".src-line-numbers", {"text-align": "right"})
 
 // Now let's check that clicking on something else than the line number doesn't
 // do anything (and certainly not add a `#NaN` to the URL!).
-show-text: true
 goto: "file://" + |DOC_PATH| + "/src/test_docs/lib.rs.html"
 // We use this assert-position to know where we will click.
 assert-position: ("//*[@id='1']", {"x": 104, "y": 112})
diff --git a/src/test/rustdoc-json/reexport/reexport_method_from_private_module.rs b/src/test/rustdoc-json/reexport/reexport_method_from_private_module.rs
new file mode 100644
index 00000000000..239b1a23b43
--- /dev/null
+++ b/src/test/rustdoc-json/reexport/reexport_method_from_private_module.rs
@@ -0,0 +1,28 @@
+// Regression test for <https://github.com/rust-lang/rust/issues/102583>.
+
+// @set impl_S = "$.index[*][?(@.docs=='impl S')].id"
+// @has "$.index[*][?(@.name=='S')].inner.impls[*]" $impl_S
+// @set is_present = "$.index[*][?(@.name=='is_present')].id"
+// @is "$.index[*][?(@.docs=='impl S')].inner.items[*]" $is_present
+// @!has "$.index[*][?(@.name=='hidden_impl')]"
+// @!has "$.index[*][?(@.name=='hidden_fn')]"
+
+#![no_std]
+
+mod private_mod {
+    pub struct S;
+
+    /// impl S
+    impl S {
+        pub fn is_present() {}
+        #[doc(hidden)]
+        pub fn hidden_fn() {}
+    }
+
+    #[doc(hidden)]
+    impl S {
+        pub fn hidden_impl() {}
+    }
+}
+
+pub use private_mod::*;
diff --git a/src/test/rustdoc-ui/invalid-html-self-closing-tag.rs b/src/test/rustdoc-ui/invalid-html-self-closing-tag.rs
new file mode 100644
index 00000000000..d973a53cbc7
--- /dev/null
+++ b/src/test/rustdoc-ui/invalid-html-self-closing-tag.rs
@@ -0,0 +1,70 @@
+#![deny(rustdoc::invalid_html_tags)]
+
+/// <p/>
+//~^ ERROR invalid self-closing HTML tag `p`
+pub struct A;
+
+/// <p style/>
+//~^ ERROR invalid self-closing HTML tag `p`
+pub struct B;
+
+/// <p style=""/>
+//~^ ERROR invalid self-closing HTML tag `p`
+pub struct C;
+
+/// <p style="x"/>
+//~^ ERROR invalid self-closing HTML tag `p`
+pub struct D;
+
+/// <p style="x/></p>
+//~^ ERROR unclosed quoted HTML attribute
+pub struct E;
+
+/// <p style='x/></p>
+//~^ ERROR unclosed quoted HTML attribute
+pub struct F;
+
+/// <p style="x/"></p>
+pub struct G;
+
+/// <p style="x/"/>
+//~^ ERROR invalid self-closing HTML tag `p`
+pub struct H;
+
+/// <p / >
+//~^ ERROR invalid self-closing HTML tag `p`
+pub struct I;
+
+/// <br/>
+pub struct J;
+
+/// <a href=/></a>
+pub struct K;
+
+/// <a href=//></a>
+pub struct L;
+
+/// <a href="/"/>
+//~^ ERROR invalid self-closing HTML tag `a`
+pub struct M;
+
+/// <a href=x />
+//~^ ERROR invalid self-closing HTML tag `a`
+pub struct N;
+
+/// <a href= />
+//~^ ERROR invalid self-closing HTML tag `a`
+pub struct O;
+
+/// <a href=x/></a>
+pub struct P;
+
+/// <svg><rect width=1 height=1 /></svg>
+pub struct Q;
+
+/// <svg><rect width=1 height=/></svg>
+//~^ ERROR unclosed HTML tag `rect`
+pub struct R;
+
+/// <svg / q>
+pub struct S;
diff --git a/src/test/rustdoc-ui/invalid-html-self-closing-tag.stderr b/src/test/rustdoc-ui/invalid-html-self-closing-tag.stderr
new file mode 100644
index 00000000000..e45edfb43ff
--- /dev/null
+++ b/src/test/rustdoc-ui/invalid-html-self-closing-tag.stderr
@@ -0,0 +1,80 @@
+error: invalid self-closing HTML tag `p`
+  --> $DIR/invalid-html-self-closing-tag.rs:3:5
+   |
+LL | /// <p/>
+   |     ^^
+   |
+note: the lint level is defined here
+  --> $DIR/invalid-html-self-closing-tag.rs:1:9
+   |
+LL | #![deny(rustdoc::invalid_html_tags)]
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: invalid self-closing HTML tag `p`
+  --> $DIR/invalid-html-self-closing-tag.rs:7:5
+   |
+LL | /// <p style/>
+   |     ^^
+
+error: invalid self-closing HTML tag `p`
+  --> $DIR/invalid-html-self-closing-tag.rs:11:5
+   |
+LL | /// <p style=""/>
+   |     ^^
+
+error: invalid self-closing HTML tag `p`
+  --> $DIR/invalid-html-self-closing-tag.rs:15:5
+   |
+LL | /// <p style="x"/>
+   |     ^^
+
+error: unclosed quoted HTML attribute on tag `p`
+  --> $DIR/invalid-html-self-closing-tag.rs:19:14
+   |
+LL | /// <p style="x/></p>
+   |              ^
+
+error: unclosed quoted HTML attribute on tag `p`
+  --> $DIR/invalid-html-self-closing-tag.rs:23:14
+   |
+LL | /// <p style='x/></p>
+   |              ^
+
+error: invalid self-closing HTML tag `p`
+  --> $DIR/invalid-html-self-closing-tag.rs:30:5
+   |
+LL | /// <p style="x/"/>
+   |     ^^
+
+error: invalid self-closing HTML tag `p`
+  --> $DIR/invalid-html-self-closing-tag.rs:34:5
+   |
+LL | /// <p / >
+   |     ^^
+
+error: invalid self-closing HTML tag `a`
+  --> $DIR/invalid-html-self-closing-tag.rs:47:5
+   |
+LL | /// <a href="/"/>
+   |     ^^
+
+error: invalid self-closing HTML tag `a`
+  --> $DIR/invalid-html-self-closing-tag.rs:51:5
+   |
+LL | /// <a href=x />
+   |     ^^
+
+error: invalid self-closing HTML tag `a`
+  --> $DIR/invalid-html-self-closing-tag.rs:55:5
+   |
+LL | /// <a href= />
+   |     ^^
+
+error: unclosed HTML tag `rect`
+  --> $DIR/invalid-html-self-closing-tag.rs:65:10
+   |
+LL | /// <svg><rect width=1 height=/></svg>
+   |          ^^^^^
+
+error: aborting due to 12 previous errors
+
diff --git a/src/test/rustdoc/async-trait.rs b/src/test/rustdoc/async-trait.rs
new file mode 100644
index 00000000000..a473e467473
--- /dev/null
+++ b/src/test/rustdoc/async-trait.rs
@@ -0,0 +1,16 @@
+// aux-build:async-trait-dep.rs
+// edition:2021
+
+#![feature(async_fn_in_trait)]
+#![allow(incomplete_features)]
+
+extern crate async_trait_dep;
+
+pub struct Oink {}
+
+// @has 'async_trait/struct.Oink.html' '//h4[@class="code-header"]' "async fn woof()"
+impl async_trait_dep::Meow for Oink {
+    async fn woof() {
+        todo!()
+    }
+}
diff --git a/src/test/rustdoc/auxiliary/async-trait-dep.rs b/src/test/rustdoc/auxiliary/async-trait-dep.rs
new file mode 100644
index 00000000000..10a55dd0260
--- /dev/null
+++ b/src/test/rustdoc/auxiliary/async-trait-dep.rs
@@ -0,0 +1,9 @@
+// edition:2021
+
+#![feature(async_fn_in_trait)]
+#![allow(incomplete_features)]
+
+pub trait Meow {
+    /// Who's a good dog?
+    async fn woof();
+}
diff --git a/src/test/rustdoc/auxiliary/masked.rs b/src/test/rustdoc/auxiliary/masked.rs
index f289359e52a..3d722d5e0c2 100644
--- a/src/test/rustdoc/auxiliary/masked.rs
+++ b/src/test/rustdoc/auxiliary/masked.rs
@@ -8,3 +8,7 @@ pub trait MaskedTrait {
 impl MaskedTrait for String {
     fn masked_method() {}
 }
+
+pub trait MaskedBlanketTrait {}
+
+impl<T> MaskedBlanketTrait for T {}
diff --git a/src/test/rustdoc/auxiliary/reexport-doc-aux.rs b/src/test/rustdoc/auxiliary/reexport-doc-aux.rs
new file mode 100644
index 00000000000..3400717eba1
--- /dev/null
+++ b/src/test/rustdoc/auxiliary/reexport-doc-aux.rs
@@ -0,0 +1,5 @@
+pub struct Foo;
+
+impl Foo {
+    pub fn foo() {}
+}
diff --git a/src/test/rustdoc/doc-notable_trait_box_is_not_an_iterator.rs b/src/test/rustdoc/doc-notable_trait_box_is_not_an_iterator.rs
new file mode 100644
index 00000000000..3fb00c7db84
--- /dev/null
+++ b/src/test/rustdoc/doc-notable_trait_box_is_not_an_iterator.rs
@@ -0,0 +1,38 @@
+#![feature(doc_notable_trait)]
+#![feature(lang_items)]
+#![feature(no_core)]
+#![no_core]
+#[lang = "owned_box"]
+pub struct Box<T>;
+
+impl<T> Box<T> {
+    pub fn new(x: T) -> Box<T> {
+        Box
+    }
+}
+
+#[doc(notable_trait)]
+pub trait FakeIterator {}
+
+impl<I: FakeIterator> FakeIterator for Box<I> {}
+
+#[lang = "pin"]
+pub struct Pin<T>;
+
+impl<T> Pin<T> {
+    pub fn new(x: T) -> Pin<T> {
+        Pin
+    }
+}
+
+impl<I: FakeIterator> FakeIterator for Pin<I> {}
+
+// @!has doc_notable_trait_box_is_not_an_iterator/fn.foo.html '//*' 'Notable'
+pub fn foo<T>(x: T) -> Box<T> {
+    Box::new(x)
+}
+
+// @!has doc_notable_trait_box_is_not_an_iterator/fn.bar.html '//*' 'Notable'
+pub fn bar<T>(x: T) -> Pin<T> {
+    Pin::new(x)
+}
diff --git a/src/test/rustdoc/masked.rs b/src/test/rustdoc/masked.rs
index 80d5b99c0b0..875c026fd05 100644
--- a/src/test/rustdoc/masked.rs
+++ b/src/test/rustdoc/masked.rs
@@ -10,6 +10,7 @@ extern crate masked;
 // @!hasraw 'search-index.js' 'masked_method'
 
 // @!hasraw 'foo/struct.String.html' 'MaskedTrait'
+// @!hasraw 'foo/struct.String.html' 'MaskedBlanketTrait'
 // @!hasraw 'foo/struct.String.html' 'masked_method'
 pub use std::string::String;
 
diff --git a/src/test/rustdoc/reexport-doc.rs b/src/test/rustdoc/reexport-doc.rs
new file mode 100644
index 00000000000..df2c889b4d5
--- /dev/null
+++ b/src/test/rustdoc/reexport-doc.rs
@@ -0,0 +1,8 @@
+// aux-build:reexport-doc-aux.rs
+
+extern crate reexport_doc_aux as dep;
+
+// @has 'reexport_doc/struct.Foo.html'
+// @count - '//p' 'These are the docs for Foo.' 1
+/// These are the docs for Foo.
+pub use dep::Foo;
diff --git a/src/test/ui-fulldeps/session-diagnostic/diagnostic-derive.rs b/src/test/ui-fulldeps/session-diagnostic/diagnostic-derive.rs
index 46164d573b0..ca77e483d6f 100644
--- a/src/test/ui-fulldeps/session-diagnostic/diagnostic-derive.rs
+++ b/src/test/ui-fulldeps/session-diagnostic/diagnostic-derive.rs
@@ -758,3 +758,41 @@ struct WithDocComment {
     #[primary_span]
     span: Span,
 }
+
+#[derive(Diagnostic)]
+#[diag(compiletest_example)]
+struct SuggestionsGood {
+    #[suggestion(code("foo", "bar"))]
+    sub: Span,
+}
+
+#[derive(Diagnostic)]
+#[diag(compiletest_example)]
+struct SuggestionsSingleItem {
+    #[suggestion(code("foo"))]
+    sub: Span,
+}
+
+#[derive(Diagnostic)]
+#[diag(compiletest_example)]
+struct SuggestionsNoItem {
+    #[suggestion(code())]
+    //~^ ERROR expected at least one string literal for `code(...)`
+    sub: Span,
+}
+
+#[derive(Diagnostic)]
+#[diag(compiletest_example)]
+struct SuggestionsInvalidItem {
+    #[suggestion(code(foo))]
+    //~^ ERROR `code(...)` must contain only string literals
+    sub: Span,
+}
+
+#[derive(Diagnostic)]
+#[diag(compiletest_example)]
+struct SuggestionsInvalidLiteral {
+    #[suggestion(code = 3)]
+    //~^ ERROR `code = "..."`/`code(...)` must contain only string literals
+    sub: Span,
+}
diff --git a/src/test/ui-fulldeps/session-diagnostic/diagnostic-derive.stderr b/src/test/ui-fulldeps/session-diagnostic/diagnostic-derive.stderr
index 0a1c4bddb06..859c272b6ba 100644
--- a/src/test/ui-fulldeps/session-diagnostic/diagnostic-derive.stderr
+++ b/src/test/ui-fulldeps/session-diagnostic/diagnostic-derive.stderr
@@ -573,6 +573,24 @@ LL |     #[subdiagnostic(eager)]
    |
    = help: eager subdiagnostics are not supported on lints
 
+error: expected at least one string literal for `code(...)`
+  --> $DIR/diagnostic-derive.rs:779:18
+   |
+LL |     #[suggestion(code())]
+   |                  ^^^^^^
+
+error: `code(...)` must contain only string literals
+  --> $DIR/diagnostic-derive.rs:787:23
+   |
+LL |     #[suggestion(code(foo))]
+   |                       ^^^
+
+error: `code = "..."`/`code(...)` must contain only string literals
+  --> $DIR/diagnostic-derive.rs:795:18
+   |
+LL |     #[suggestion(code = 3)]
+   |                  ^^^^^^^^
+
 error: cannot find attribute `nonsense` in this scope
   --> $DIR/diagnostic-derive.rs:55:3
    |
@@ -647,7 +665,7 @@ LL |         arg: impl IntoDiagnosticArg,
    |                   ^^^^^^^^^^^^^^^^^ required by this bound in `DiagnosticBuilder::<'a, G>::set_arg`
    = note: this error originates in the derive macro `Diagnostic` (in Nightly builds, run with -Z macro-backtrace for more info)
 
-error: aborting due to 80 previous errors
+error: aborting due to 83 previous errors
 
 Some errors have detailed explanations: E0277, E0425.
 For more information about an error, try `rustc --explain E0277`.
diff --git a/src/test/ui-fulldeps/session-diagnostic/subdiagnostic-derive.rs b/src/test/ui-fulldeps/session-diagnostic/subdiagnostic-derive.rs
index 9088ca6ce46..efec85eb52c 100644
--- a/src/test/ui-fulldeps/session-diagnostic/subdiagnostic-derive.rs
+++ b/src/test/ui-fulldeps/session-diagnostic/subdiagnostic-derive.rs
@@ -661,3 +661,48 @@ enum BL {
         span: Span,
     }
 }
+
+#[derive(Subdiagnostic)]
+#[multipart_suggestion(parser_add_paren)]
+struct BM {
+    #[suggestion_part(code("foo"))]
+    //~^ ERROR expected exactly one string literal for `code = ...`
+    span: Span,
+    r#type: String,
+}
+
+#[derive(Subdiagnostic)]
+#[multipart_suggestion(parser_add_paren)]
+struct BN {
+    #[suggestion_part(code("foo", "bar"))]
+    //~^ ERROR expected exactly one string literal for `code = ...`
+    span: Span,
+    r#type: String,
+}
+
+#[derive(Subdiagnostic)]
+#[multipart_suggestion(parser_add_paren)]
+struct BO {
+    #[suggestion_part(code(3))]
+    //~^ ERROR expected exactly one string literal for `code = ...`
+    span: Span,
+    r#type: String,
+}
+
+#[derive(Subdiagnostic)]
+#[multipart_suggestion(parser_add_paren)]
+struct BP {
+    #[suggestion_part(code())]
+    //~^ ERROR expected exactly one string literal for `code = ...`
+    span: Span,
+    r#type: String,
+}
+
+#[derive(Subdiagnostic)]
+#[multipart_suggestion(parser_add_paren)]
+struct BQ {
+    #[suggestion_part(code = 3)]
+    //~^ ERROR `code = "..."`/`code(...)` must contain only string literals
+    span: Span,
+    r#type: String,
+}
diff --git a/src/test/ui-fulldeps/session-diagnostic/subdiagnostic-derive.stderr b/src/test/ui-fulldeps/session-diagnostic/subdiagnostic-derive.stderr
index b21f9cc94a9..a85a8711eac 100644
--- a/src/test/ui-fulldeps/session-diagnostic/subdiagnostic-derive.stderr
+++ b/src/test/ui-fulldeps/session-diagnostic/subdiagnostic-derive.stderr
@@ -415,6 +415,36 @@ error: `#[applicability]` has no effect if all `#[suggestion]`/`#[multipart_sugg
 LL |     #[applicability]
    |     ^^^^^^^^^^^^^^^^
 
+error: expected exactly one string literal for `code = ...`
+  --> $DIR/subdiagnostic-derive.rs:668:23
+   |
+LL |     #[suggestion_part(code("foo"))]
+   |                       ^^^^^^^^^^^
+
+error: expected exactly one string literal for `code = ...`
+  --> $DIR/subdiagnostic-derive.rs:677:23
+   |
+LL |     #[suggestion_part(code("foo", "bar"))]
+   |                       ^^^^^^^^^^^^^^^^^^
+
+error: expected exactly one string literal for `code = ...`
+  --> $DIR/subdiagnostic-derive.rs:686:23
+   |
+LL |     #[suggestion_part(code(3))]
+   |                       ^^^^^^^
+
+error: expected exactly one string literal for `code = ...`
+  --> $DIR/subdiagnostic-derive.rs:695:23
+   |
+LL |     #[suggestion_part(code())]
+   |                       ^^^^^^
+
+error: `code = "..."`/`code(...)` must contain only string literals
+  --> $DIR/subdiagnostic-derive.rs:704:23
+   |
+LL |     #[suggestion_part(code = 3)]
+   |                       ^^^^^^^^
+
 error: cannot find attribute `foo` in this scope
   --> $DIR/subdiagnostic-derive.rs:63:3
    |
@@ -475,6 +505,6 @@ error[E0425]: cannot find value `slug` in module `rustc_errors::fluent`
 LL | #[label(slug)]
    |         ^^^^ not found in `rustc_errors::fluent`
 
-error: aborting due to 67 previous errors
+error: aborting due to 72 previous errors
 
 For more information about this error, try `rustc --explain E0425`.
diff --git a/src/test/ui/associated-types/cache/project-fn-ret-invariant.oneuse.stderr b/src/test/ui/associated-types/cache/project-fn-ret-invariant.oneuse.stderr
index cc156016212..77841780f62 100644
--- a/src/test/ui/associated-types/cache/project-fn-ret-invariant.oneuse.stderr
+++ b/src/test/ui/associated-types/cache/project-fn-ret-invariant.oneuse.stderr
@@ -15,19 +15,19 @@ LL |     let a = bar(f, x);
    = help: see <https://doc.rust-lang.org/nomicon/subtyping.html> for more information about variance
 
 error: lifetime may not live long enough
-  --> $DIR/project-fn-ret-invariant.rs:40:13
+  --> $DIR/project-fn-ret-invariant.rs:42:13
    |
 LL | fn baz<'a, 'b>(x: Type<'a>, y: Type<'b>) -> (Type<'a>, Type<'b>) {
    |        --  -- lifetime `'b` defined here
    |        |
    |        lifetime `'a` defined here
-LL |     let f = foo; // <-- No consistent type can be inferred for `f` here.
-LL |     let a = bar(f, x);
+...
+LL |     let b = bar(f, y);
    |             ^^^^^^^^^ argument requires that `'b` must outlive `'a`
    |
    = help: consider adding the following bound: `'b: 'a`
-   = note: requirement occurs because of a function pointer to `foo`
-   = note: the function `foo` is invariant over the parameter `'a`
+   = note: requirement occurs because of the type `Type<'_>`, which makes the generic argument `'_` invariant
+   = note: the struct `Type<'a>` is invariant over the parameter `'a`
    = help: see <https://doc.rust-lang.org/nomicon/subtyping.html> for more information about variance
 
 help: `'a` and `'b` must be the same: replace one with the other
diff --git a/src/test/ui/associated-types/cache/project-fn-ret-invariant.rs b/src/test/ui/associated-types/cache/project-fn-ret-invariant.rs
index 1075fd6e092..e043379133a 100644
--- a/src/test/ui/associated-types/cache/project-fn-ret-invariant.rs
+++ b/src/test/ui/associated-types/cache/project-fn-ret-invariant.rs
@@ -39,8 +39,8 @@ fn baz<'a, 'b>(x: Type<'a>, y: Type<'b>) -> (Type<'a>, Type<'b>) {
     let f = foo; // <-- No consistent type can be inferred for `f` here.
     let a = bar(f, x);
     //[oneuse]~^ ERROR lifetime may not live long enough
-    //[oneuse]~| ERROR lifetime may not live long enough
     let b = bar(f, y);
+    //[oneuse]~^ ERROR lifetime may not live long enough
     (a, b)
 }
 
diff --git a/src/test/ui/async-await/async-fn-nonsend.stderr b/src/test/ui/async-await/async-fn-nonsend.stderr
index 40ad46b4862..a7b872fe444 100644
--- a/src/test/ui/async-await/async-fn-nonsend.stderr
+++ b/src/test/ui/async-await/async-fn-nonsend.stderr
@@ -27,7 +27,7 @@ error: future cannot be sent between threads safely
 LL |     assert_send(non_sync_with_method_call());
    |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^ future returned by `non_sync_with_method_call` is not `Send`
    |
-   = help: the trait `Send` is not implemented for `dyn std::fmt::Write`
+   = help: within `impl Future<Output = ()>`, the trait `Send` is not implemented for `dyn std::fmt::Write`
 note: future is not `Send` as this value is used across an await
   --> $DIR/async-fn-nonsend.rs:46:14
    |
diff --git a/src/test/ui/async-await/in-trait/async-associated-types.rs b/src/test/ui/async-await/in-trait/async-associated-types.rs
new file mode 100644
index 00000000000..a6f928f3b1b
--- /dev/null
+++ b/src/test/ui/async-await/in-trait/async-associated-types.rs
@@ -0,0 +1,24 @@
+// check-fail
+// known-bug: #102682
+// edition: 2021
+
+#![feature(async_fn_in_trait)]
+#![allow(incomplete_features)]
+
+use std::fmt::Debug;
+
+trait MyTrait<'a, 'b, T> where Self: 'a, T: Debug + Sized + 'b {
+    type MyAssoc;
+
+    async fn foo(&'a self, key: &'b T) -> Self::MyAssoc;
+}
+
+impl<'a, 'b, T: Debug + Sized + 'b, U: 'a> MyTrait<'a, 'b, T> for U {
+    type MyAssoc = (&'a U, &'b T);
+
+    async fn foo(&'a self, key: &'b T) -> (&'a U, &'b T) {
+        (self, key)
+    }
+}
+
+fn main() {}
diff --git a/src/test/ui/async-await/in-trait/async-associated-types.stderr b/src/test/ui/async-await/in-trait/async-associated-types.stderr
new file mode 100644
index 00000000000..0985150eee0
--- /dev/null
+++ b/src/test/ui/async-await/in-trait/async-associated-types.stderr
@@ -0,0 +1,57 @@
+error[E0495]: cannot infer an appropriate lifetime for lifetime parameter `'a` due to conflicting requirements
+  --> $DIR/async-associated-types.rs:19:43
+   |
+LL |     async fn foo(&'a self, key: &'b T) -> (&'a U, &'b T) {
+   |                                           ^^^^^^^^^^^^^^
+   |
+note: first, the lifetime cannot outlive the lifetime `'a` as defined here...
+  --> $DIR/async-associated-types.rs:16:6
+   |
+LL | impl<'a, 'b, T: Debug + Sized + 'b, U: 'a> MyTrait<'a, 'b, T> for U {
+   |      ^^
+note: ...so that the types are compatible
+  --> $DIR/async-associated-types.rs:19:43
+   |
+LL |     async fn foo(&'a self, key: &'b T) -> (&'a U, &'b T) {
+   |                                           ^^^^^^^^^^^^^^
+   = note: expected `(&'a U, &'b T)`
+              found `(&U, &T)`
+   = note: but, the lifetime must be valid for the static lifetime...
+note: ...so that the types are compatible
+  --> $DIR/async-associated-types.rs:19:43
+   |
+LL |     async fn foo(&'a self, key: &'b T) -> (&'a U, &'b T) {
+   |                                           ^^^^^^^^^^^^^^
+   = note: expected `MyTrait<'static, 'static, T>`
+              found `MyTrait<'_, '_, T>`
+
+error[E0495]: cannot infer an appropriate lifetime for lifetime parameter `'b` due to conflicting requirements
+  --> $DIR/async-associated-types.rs:19:43
+   |
+LL |     async fn foo(&'a self, key: &'b T) -> (&'a U, &'b T) {
+   |                                           ^^^^^^^^^^^^^^
+   |
+note: first, the lifetime cannot outlive the lifetime `'b` as defined here...
+  --> $DIR/async-associated-types.rs:16:10
+   |
+LL | impl<'a, 'b, T: Debug + Sized + 'b, U: 'a> MyTrait<'a, 'b, T> for U {
+   |          ^^
+note: ...so that the types are compatible
+  --> $DIR/async-associated-types.rs:19:43
+   |
+LL |     async fn foo(&'a self, key: &'b T) -> (&'a U, &'b T) {
+   |                                           ^^^^^^^^^^^^^^
+   = note: expected `(&'a U, &'b T)`
+              found `(&U, &T)`
+   = note: but, the lifetime must be valid for the static lifetime...
+note: ...so that the types are compatible
+  --> $DIR/async-associated-types.rs:19:43
+   |
+LL |     async fn foo(&'a self, key: &'b T) -> (&'a U, &'b T) {
+   |                                           ^^^^^^^^^^^^^^
+   = note: expected `MyTrait<'static, 'static, T>`
+              found `MyTrait<'_, '_, T>`
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0495`.
diff --git a/src/test/ui/async-await/in-trait/async-associated-types2.rs b/src/test/ui/async-await/in-trait/async-associated-types2.rs
new file mode 100644
index 00000000000..e546a0579c6
--- /dev/null
+++ b/src/test/ui/async-await/in-trait/async-associated-types2.rs
@@ -0,0 +1,30 @@
+// check-pass
+// edition: 2021
+
+#![feature(async_fn_in_trait)]
+#![feature(type_alias_impl_trait)]
+#![allow(incomplete_features)]
+
+use std::future::Future;
+
+trait MyTrait {
+    type Fut<'a>: Future<Output = i32>
+    where
+        Self: 'a;
+
+    fn foo<'a>(&'a self) -> Self::Fut<'a>;
+}
+
+impl MyTrait for i32 {
+    type Fut<'a> = impl Future<Output = i32> + 'a
+    where
+        Self: 'a;
+
+    fn foo<'a>(&'a self) -> Self::Fut<'a> {
+        async {
+            *self
+        }
+    }
+}
+
+fn main() {}
diff --git a/src/test/ui/async-await/in-trait/async-example-desugared-boxed-in-trait.rs b/src/test/ui/async-await/in-trait/async-example-desugared-boxed-in-trait.rs
new file mode 100644
index 00000000000..38ba297189c
--- /dev/null
+++ b/src/test/ui/async-await/in-trait/async-example-desugared-boxed-in-trait.rs
@@ -0,0 +1,21 @@
+// edition: 2021
+
+#![feature(async_fn_in_trait)]
+#![feature(return_position_impl_trait_in_trait)]
+#![allow(incomplete_features)]
+
+use std::future::Future;
+use std::pin::Pin;
+
+trait MyTrait {
+    fn foo(&self) -> Pin<Box<dyn Future<Output = i32> + '_>>;
+}
+
+impl MyTrait for i32 {
+    async fn foo(&self) -> i32 {
+        //~^ ERROR method `foo` has an incompatible type for trait
+        *self
+    }
+}
+
+fn main() {}
diff --git a/src/test/ui/async-await/in-trait/async-example-desugared-boxed-in-trait.stderr b/src/test/ui/async-await/in-trait/async-example-desugared-boxed-in-trait.stderr
new file mode 100644
index 00000000000..22d2928f2f5
--- /dev/null
+++ b/src/test/ui/async-await/in-trait/async-example-desugared-boxed-in-trait.stderr
@@ -0,0 +1,17 @@
+error[E0053]: method `foo` has an incompatible type for trait
+  --> $DIR/async-example-desugared-boxed-in-trait.rs:15:28
+   |
+LL |     async fn foo(&self) -> i32 {
+   |                            ^^^ expected struct `Pin`, found opaque type
+   |
+note: type in trait
+  --> $DIR/async-example-desugared-boxed-in-trait.rs:11:22
+   |
+LL |     fn foo(&self) -> Pin<Box<dyn Future<Output = i32> + '_>>;
+   |                      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   = note: expected fn pointer `fn(&i32) -> Pin<Box<dyn Future<Output = i32>>>`
+              found fn pointer `fn(&i32) -> impl Future<Output = i32>`
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0053`.
diff --git a/src/test/ui/async-await/in-trait/async-example-desugared-boxed.rs b/src/test/ui/async-await/in-trait/async-example-desugared-boxed.rs
new file mode 100644
index 00000000000..61d7e2520ea
--- /dev/null
+++ b/src/test/ui/async-await/in-trait/async-example-desugared-boxed.rs
@@ -0,0 +1,24 @@
+// check-pass
+// edition: 2021
+
+#![feature(async_fn_in_trait)]
+#![feature(return_position_impl_trait_in_trait)]
+#![allow(incomplete_features)]
+
+use std::future::Future;
+use std::pin::Pin;
+
+trait MyTrait {
+    async fn foo(&self) -> i32;
+}
+
+impl MyTrait for i32 {
+    // This will break once a PR that implements #102745 is merged
+    fn foo(&self) -> Pin<Box<dyn Future<Output = i32> + '_>> {
+        Box::pin(async {
+            *self
+        })
+    }
+}
+
+fn main() {}
diff --git a/src/test/ui/async-await/in-trait/async-example-desugared-in-trait.rs b/src/test/ui/async-await/in-trait/async-example-desugared-in-trait.rs
new file mode 100644
index 00000000000..feeda719e03
--- /dev/null
+++ b/src/test/ui/async-await/in-trait/async-example-desugared-in-trait.rs
@@ -0,0 +1,21 @@
+// check-pass
+// edition: 2021
+
+#![feature(async_fn_in_trait)]
+#![feature(return_position_impl_trait_in_trait)]
+#![allow(incomplete_features)]
+
+use std::future::Future;
+
+trait MyTrait {
+    fn foo(&self) -> impl Future<Output = i32> + '_;
+}
+
+impl MyTrait for i32 {
+    // This will break once a PR that implements #102745 is merged
+    async fn foo(&self) -> i32 {
+        *self
+    }
+}
+
+fn main() {}
diff --git a/src/test/ui/async-await/in-trait/async-example-desugared.rs b/src/test/ui/async-await/in-trait/async-example-desugared.rs
new file mode 100644
index 00000000000..1313c9edd86
--- /dev/null
+++ b/src/test/ui/async-await/in-trait/async-example-desugared.rs
@@ -0,0 +1,23 @@
+// check-pass
+// edition: 2021
+
+#![feature(async_fn_in_trait)]
+#![feature(return_position_impl_trait_in_trait)]
+#![allow(incomplete_features)]
+
+use std::future::Future;
+
+trait MyTrait {
+    async fn foo(&self) -> i32;
+}
+
+impl MyTrait for i32 {
+    // This will break once a PR that implements #102745 is merged
+    fn foo(&self) -> impl Future<Output = i32> + '_ {
+        async {
+            *self
+        }
+    }
+}
+
+fn main() {}
diff --git a/src/test/ui/async-await/in-trait/async-example.rs b/src/test/ui/async-await/in-trait/async-example.rs
new file mode 100644
index 00000000000..abf94ef7450
--- /dev/null
+++ b/src/test/ui/async-await/in-trait/async-example.rs
@@ -0,0 +1,32 @@
+// check-pass
+// edition: 2021
+
+#![feature(async_fn_in_trait)]
+#![allow(incomplete_features)]
+
+trait MyTrait {
+    async fn foo(&self) -> i32;
+    async fn bar(&self) -> i32;
+}
+
+impl MyTrait for i32 {
+    async fn foo(&self) -> i32 {
+        *self
+    }
+
+    async fn bar(&self) -> i32 {
+        self.foo().await
+    }
+}
+
+fn main() {
+    let x = 5;
+    // Calling from non-async context
+    let _ = x.foo();
+    let _ = x.bar();
+    // Calling from async block in non-async context
+    async {
+        let _: i32 = x.foo().await;
+        let _: i32 = x.bar().await;
+    };
+}
diff --git a/src/test/ui/async-await/in-trait/async-generics-and-bounds.rs b/src/test/ui/async-await/in-trait/async-generics-and-bounds.rs
new file mode 100644
index 00000000000..a73d55adfec
--- /dev/null
+++ b/src/test/ui/async-await/in-trait/async-generics-and-bounds.rs
@@ -0,0 +1,21 @@
+// check-fail
+// known-bug: #102682
+// edition: 2021
+
+#![feature(async_fn_in_trait)]
+#![allow(incomplete_features)]
+
+use std::fmt::Debug;
+use std::hash::Hash;
+
+trait MyTrait<T, U> {
+    async fn foo(&self) -> &(T, U) where T: Debug + Sized, U: Hash;
+}
+
+impl<T, U> MyTrait<T, U> for (T, U) {
+    async fn foo(&self) -> &(T, U) {
+        self
+    }
+}
+
+fn main() {}
diff --git a/src/test/ui/async-await/in-trait/async-generics-and-bounds.stderr b/src/test/ui/async-await/in-trait/async-generics-and-bounds.stderr
new file mode 100644
index 00000000000..5c8d64fc6cb
--- /dev/null
+++ b/src/test/ui/async-await/in-trait/async-generics-and-bounds.stderr
@@ -0,0 +1,37 @@
+error[E0311]: the parameter type `U` may not live long enough
+  --> $DIR/async-generics-and-bounds.rs:12:28
+   |
+LL |     async fn foo(&self) -> &(T, U) where T: Debug + Sized, U: Hash;
+   |                            ^^^^^^^
+   |
+note: the parameter type `U` must be valid for the anonymous lifetime as defined here...
+  --> $DIR/async-generics-and-bounds.rs:12:18
+   |
+LL |     async fn foo(&self) -> &(T, U) where T: Debug + Sized, U: Hash;
+   |                  ^
+note: ...so that the reference type `&(T, U)` does not outlive the data it points at
+  --> $DIR/async-generics-and-bounds.rs:12:28
+   |
+LL |     async fn foo(&self) -> &(T, U) where T: Debug + Sized, U: Hash;
+   |                            ^^^^^^^
+
+error[E0311]: the parameter type `T` may not live long enough
+  --> $DIR/async-generics-and-bounds.rs:12:28
+   |
+LL |     async fn foo(&self) -> &(T, U) where T: Debug + Sized, U: Hash;
+   |                            ^^^^^^^
+   |
+note: the parameter type `T` must be valid for the anonymous lifetime as defined here...
+  --> $DIR/async-generics-and-bounds.rs:12:18
+   |
+LL |     async fn foo(&self) -> &(T, U) where T: Debug + Sized, U: Hash;
+   |                  ^
+note: ...so that the reference type `&(T, U)` does not outlive the data it points at
+  --> $DIR/async-generics-and-bounds.rs:12:28
+   |
+LL |     async fn foo(&self) -> &(T, U) where T: Debug + Sized, U: Hash;
+   |                            ^^^^^^^
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0311`.
diff --git a/src/test/ui/async-await/in-trait/async-generics.rs b/src/test/ui/async-await/in-trait/async-generics.rs
new file mode 100644
index 00000000000..67000e5770e
--- /dev/null
+++ b/src/test/ui/async-await/in-trait/async-generics.rs
@@ -0,0 +1,18 @@
+// check-fail
+// known-bug: #102682
+// edition: 2021
+
+#![feature(async_fn_in_trait)]
+#![allow(incomplete_features)]
+
+trait MyTrait<T, U> {
+    async fn foo(&self) -> &(T, U);
+}
+
+impl<T, U> MyTrait<T, U> for (T, U) {
+    async fn foo(&self) -> &(T, U) {
+        self
+    }
+}
+
+fn main() {}
diff --git a/src/test/ui/async-await/in-trait/async-generics.stderr b/src/test/ui/async-await/in-trait/async-generics.stderr
new file mode 100644
index 00000000000..6ae73d9e3a6
--- /dev/null
+++ b/src/test/ui/async-await/in-trait/async-generics.stderr
@@ -0,0 +1,37 @@
+error[E0311]: the parameter type `U` may not live long enough
+  --> $DIR/async-generics.rs:9:28
+   |
+LL |     async fn foo(&self) -> &(T, U);
+   |                            ^^^^^^^
+   |
+note: the parameter type `U` must be valid for the anonymous lifetime as defined here...
+  --> $DIR/async-generics.rs:9:18
+   |
+LL |     async fn foo(&self) -> &(T, U);
+   |                  ^
+note: ...so that the reference type `&(T, U)` does not outlive the data it points at
+  --> $DIR/async-generics.rs:9:28
+   |
+LL |     async fn foo(&self) -> &(T, U);
+   |                            ^^^^^^^
+
+error[E0311]: the parameter type `T` may not live long enough
+  --> $DIR/async-generics.rs:9:28
+   |
+LL |     async fn foo(&self) -> &(T, U);
+   |                            ^^^^^^^
+   |
+note: the parameter type `T` must be valid for the anonymous lifetime as defined here...
+  --> $DIR/async-generics.rs:9:18
+   |
+LL |     async fn foo(&self) -> &(T, U);
+   |                  ^
+note: ...so that the reference type `&(T, U)` does not outlive the data it points at
+  --> $DIR/async-generics.rs:9:28
+   |
+LL |     async fn foo(&self) -> &(T, U);
+   |                            ^^^^^^^
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0311`.
diff --git a/src/test/ui/async-await/in-trait/async-lifetimes-and-bounds.rs b/src/test/ui/async-await/in-trait/async-lifetimes-and-bounds.rs
new file mode 100644
index 00000000000..3f7448cecd1
--- /dev/null
+++ b/src/test/ui/async-await/in-trait/async-lifetimes-and-bounds.rs
@@ -0,0 +1,20 @@
+// check-fail
+// known-bug: #102682
+// edition: 2021
+
+#![feature(async_fn_in_trait)]
+#![allow(incomplete_features)]
+
+use std::fmt::Debug;
+
+trait MyTrait<'a, 'b, T> {
+    async fn foo(&'a self, key: &'b T) -> (&'a Self, &'b T) where T: Debug + Sized;
+}
+
+impl<'a, 'b, T, U> MyTrait<'a, 'b, T> for U {
+    async fn foo(&'a self, key: &'b T) -> (&'a U, &'b T) {
+        (self, key)
+    }
+}
+
+fn main() {}
diff --git a/src/test/ui/async-await/in-trait/async-lifetimes-and-bounds.stderr b/src/test/ui/async-await/in-trait/async-lifetimes-and-bounds.stderr
new file mode 100644
index 00000000000..0f024202743
--- /dev/null
+++ b/src/test/ui/async-await/in-trait/async-lifetimes-and-bounds.stderr
@@ -0,0 +1,23 @@
+error[E0309]: the parameter type `Self` may not live long enough
+  --> $DIR/async-lifetimes-and-bounds.rs:11:43
+   |
+LL |     async fn foo(&'a self, key: &'b T) -> (&'a Self, &'b T) where T: Debug + Sized;
+   |                                           ^^^^^^^^^^^^^^^^^
+   |
+   = help: consider adding an explicit lifetime bound `Self: 'a`...
+   = note: ...so that the reference type `&'a Self` does not outlive the data it points at
+
+error[E0309]: the parameter type `T` may not live long enough
+  --> $DIR/async-lifetimes-and-bounds.rs:11:43
+   |
+LL |     async fn foo(&'a self, key: &'b T) -> (&'a Self, &'b T) where T: Debug + Sized;
+   |                                           ^^^^^^^^^^^^^^^^^ ...so that the reference type `&'b T` does not outlive the data it points at
+   |
+help: consider adding an explicit lifetime bound...
+   |
+LL | trait MyTrait<'a, 'b, T: 'b> {
+   |                        ++++
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0309`.
diff --git a/src/test/ui/async-await/in-trait/async-lifetimes.rs b/src/test/ui/async-await/in-trait/async-lifetimes.rs
new file mode 100644
index 00000000000..acbac471cf7
--- /dev/null
+++ b/src/test/ui/async-await/in-trait/async-lifetimes.rs
@@ -0,0 +1,18 @@
+// check-fail
+// known-bug: #102682
+// edition: 2021
+
+#![feature(async_fn_in_trait)]
+#![allow(incomplete_features)]
+
+trait MyTrait<'a, 'b, T> {
+    async fn foo(&'a self, key: &'b T) -> (&'a Self, &'b T);
+}
+
+impl<'a, 'b, T, U> MyTrait<'a, 'b, T> for U {
+    async fn foo(&'a self, key: &'b T) -> (&'a U, &'b T) {
+        (self, key)
+    }
+}
+
+fn main() {}
diff --git a/src/test/ui/async-await/in-trait/async-lifetimes.stderr b/src/test/ui/async-await/in-trait/async-lifetimes.stderr
new file mode 100644
index 00000000000..9a7d294bb17
--- /dev/null
+++ b/src/test/ui/async-await/in-trait/async-lifetimes.stderr
@@ -0,0 +1,23 @@
+error[E0309]: the parameter type `Self` may not live long enough
+  --> $DIR/async-lifetimes.rs:9:43
+   |
+LL |     async fn foo(&'a self, key: &'b T) -> (&'a Self, &'b T);
+   |                                           ^^^^^^^^^^^^^^^^^
+   |
+   = help: consider adding an explicit lifetime bound `Self: 'a`...
+   = note: ...so that the reference type `&'a Self` does not outlive the data it points at
+
+error[E0309]: the parameter type `T` may not live long enough
+  --> $DIR/async-lifetimes.rs:9:43
+   |
+LL |     async fn foo(&'a self, key: &'b T) -> (&'a Self, &'b T);
+   |                                           ^^^^^^^^^^^^^^^^^ ...so that the reference type `&'b T` does not outlive the data it points at
+   |
+help: consider adding an explicit lifetime bound...
+   |
+LL | trait MyTrait<'a, 'b, T: 'b> {
+   |                        ++++
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0309`.
diff --git a/src/test/ui/async-await/in-trait/async-recursive-generic.rs b/src/test/ui/async-await/in-trait/async-recursive-generic.rs
new file mode 100644
index 00000000000..6839abd381c
--- /dev/null
+++ b/src/test/ui/async-await/in-trait/async-recursive-generic.rs
@@ -0,0 +1,21 @@
+// edition: 2021
+
+#![feature(async_fn_in_trait)]
+#![allow(incomplete_features)]
+
+trait MyTrait<T> {
+    async fn foo_recursive(&self, n: usize) -> T;
+}
+
+impl<T> MyTrait<T> for T where T: Copy {
+    async fn foo_recursive(&self, n: usize) -> T {
+        //~^ ERROR recursion in an `async fn` requires boxing
+        if n > 0 {
+            self.foo_recursive(n - 1).await
+        } else {
+            *self
+        }
+    }
+}
+
+fn main() {}
diff --git a/src/test/ui/async-await/in-trait/async-recursive-generic.stderr b/src/test/ui/async-await/in-trait/async-recursive-generic.stderr
new file mode 100644
index 00000000000..cab173bdd5b
--- /dev/null
+++ b/src/test/ui/async-await/in-trait/async-recursive-generic.stderr
@@ -0,0 +1,12 @@
+error[E0733]: recursion in an `async fn` requires boxing
+  --> $DIR/async-recursive-generic.rs:11:48
+   |
+LL |     async fn foo_recursive(&self, n: usize) -> T {
+   |                                                ^ recursive `async fn`
+   |
+   = note: a recursive `async fn` must be rewritten to return a boxed `dyn Future`
+   = note: consider using the `async_recursion` crate: https://crates.io/crates/async_recursion
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0733`.
diff --git a/src/test/ui/async-await/in-trait/async-recursive.rs b/src/test/ui/async-await/in-trait/async-recursive.rs
new file mode 100644
index 00000000000..61119f8095b
--- /dev/null
+++ b/src/test/ui/async-await/in-trait/async-recursive.rs
@@ -0,0 +1,21 @@
+// edition: 2021
+
+#![feature(async_fn_in_trait)]
+#![allow(incomplete_features)]
+
+trait MyTrait {
+    async fn foo_recursive(&self, n: usize) -> i32;
+}
+
+impl MyTrait for i32 {
+    async fn foo_recursive(&self, n: usize) -> i32 {
+        //~^ ERROR recursion in an `async fn` requires boxing
+        if n > 0 {
+            self.foo_recursive(n - 1).await
+        } else {
+            *self
+        }
+    }
+}
+
+fn main() {}
diff --git a/src/test/ui/async-await/in-trait/async-recursive.stderr b/src/test/ui/async-await/in-trait/async-recursive.stderr
new file mode 100644
index 00000000000..9feff37b3fe
--- /dev/null
+++ b/src/test/ui/async-await/in-trait/async-recursive.stderr
@@ -0,0 +1,12 @@
+error[E0733]: recursion in an `async fn` requires boxing
+  --> $DIR/async-recursive.rs:11:48
+   |
+LL |     async fn foo_recursive(&self, n: usize) -> i32 {
+   |                                                ^^^ recursive `async fn`
+   |
+   = note: a recursive `async fn` must be rewritten to return a boxed `dyn Future`
+   = note: consider using the `async_recursion` crate: https://crates.io/crates/async_recursion
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0733`.
diff --git a/src/test/ui/async-await/in-trait/fn-not-async-err.rs b/src/test/ui/async-await/in-trait/fn-not-async-err.rs
new file mode 100644
index 00000000000..f94d32145a2
--- /dev/null
+++ b/src/test/ui/async-await/in-trait/fn-not-async-err.rs
@@ -0,0 +1,17 @@
+// edition: 2021
+
+#![feature(async_fn_in_trait)]
+#![allow(incomplete_features)]
+
+trait MyTrait {
+    async fn foo(&self) -> i32;
+}
+
+impl MyTrait for i32 {
+    fn foo(&self) -> i32 {
+        //~^ ERROR: `i32` is not a future [E0277]
+        *self
+    }
+}
+
+fn main() {}
diff --git a/src/test/ui/async-await/in-trait/fn-not-async-err.stderr b/src/test/ui/async-await/in-trait/fn-not-async-err.stderr
new file mode 100644
index 00000000000..03321dc5b5a
--- /dev/null
+++ b/src/test/ui/async-await/in-trait/fn-not-async-err.stderr
@@ -0,0 +1,17 @@
+error[E0277]: `i32` is not a future
+  --> $DIR/fn-not-async-err.rs:11:22
+   |
+LL |     fn foo(&self) -> i32 {
+   |                      ^^^ `i32` is not a future
+   |
+   = help: the trait `Future` is not implemented for `i32`
+   = note: i32 must be a future or must implement `IntoFuture` to be awaited
+note: required by a bound in `MyTrait::foo::{opaque#0}`
+  --> $DIR/fn-not-async-err.rs:7:28
+   |
+LL |     async fn foo(&self) -> i32;
+   |                            ^^^ required by this bound in `MyTrait::foo::{opaque#0}`
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0277`.
diff --git a/src/test/ui/async-await/in-trait/fn-not-async-err2.rs b/src/test/ui/async-await/in-trait/fn-not-async-err2.rs
new file mode 100644
index 00000000000..594baa91ad8
--- /dev/null
+++ b/src/test/ui/async-await/in-trait/fn-not-async-err2.rs
@@ -0,0 +1,21 @@
+// edition: 2021
+
+#![feature(async_fn_in_trait)]
+#![allow(incomplete_features)]
+
+use std::future::Future;
+
+trait MyTrait {
+    async fn foo(&self) -> i32;
+}
+
+impl MyTrait for i32 {
+    fn foo(&self) -> impl Future<Output = i32> {
+        //~^ ERROR `impl Trait` only allowed in function and inherent method return types, not in `impl` method return [E0562]
+        async {
+            *self
+        }
+    }
+}
+
+fn main() {}
diff --git a/src/test/ui/async-await/in-trait/fn-not-async-err2.stderr b/src/test/ui/async-await/in-trait/fn-not-async-err2.stderr
new file mode 100644
index 00000000000..f591f184772
--- /dev/null
+++ b/src/test/ui/async-await/in-trait/fn-not-async-err2.stderr
@@ -0,0 +1,12 @@
+error[E0562]: `impl Trait` only allowed in function and inherent method return types, not in `impl` method return
+  --> $DIR/fn-not-async-err2.rs:13:22
+   |
+LL |     fn foo(&self) -> impl Future<Output = i32> {
+   |                      ^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: see issue #91611 <https://github.com/rust-lang/rust/issues/91611> for more information
+   = help: add `#![feature(return_position_impl_trait_in_trait)]` to the crate attributes to enable
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0562`.
diff --git a/src/test/ui/async-await/issue-98634.rs b/src/test/ui/async-await/issue-98634.rs
new file mode 100644
index 00000000000..b0d38687f01
--- /dev/null
+++ b/src/test/ui/async-await/issue-98634.rs
@@ -0,0 +1,50 @@
+// edition: 2021
+
+use std::{
+    future::Future,
+    pin::Pin,
+    task::{Context, Poll, Waker},
+};
+
+pub struct StructAsync<F: Fn() -> Pin<Box<dyn Future<Output = ()>>>> {
+    pub callback: F,
+}
+
+impl<F> Future for StructAsync<F>
+where
+    F: Fn() -> Pin<Box<dyn Future<Output = ()>>>,
+{
+    type Output = ();
+
+    fn poll(self: Pin<&mut Self>, _cx: &mut Context<'_>) -> Poll<Self::Output> {
+        Poll::Pending
+    }
+}
+
+async fn callback() {}
+
+struct Runtime;
+
+fn waker() -> &'static Waker {
+    todo!()
+}
+
+impl Runtime {
+    #[track_caller]
+    pub fn block_on<F: Future>(&self, mut future: F) -> F::Output {
+        loop {
+            unsafe {
+                Pin::new_unchecked(&mut future).poll(&mut Context::from_waker(waker()));
+            }
+        }
+    }
+}
+
+fn main() {
+    Runtime.block_on(async {
+        StructAsync { callback }.await;
+        //~^ ERROR expected `fn() -> impl Future<Output = ()> {callback}` to be a fn item that returns `Pin<Box<(dyn Future<Output = ()> + 'static)>>`, but it returns `impl Future<Output = ()>`
+        //~| ERROR expected `fn() -> impl Future<Output = ()> {callback}` to be a fn item that returns `Pin<Box<(dyn Future<Output = ()> + 'static)>>`, but it returns `impl Future<Output = ()>`
+        //~| ERROR expected `fn() -> impl Future<Output = ()> {callback}` to be a fn item that returns `Pin<Box<(dyn Future<Output = ()> + 'static)>>`, but it returns `impl Future<Output = ()>`
+    });
+}
diff --git a/src/test/ui/async-await/issue-98634.stderr b/src/test/ui/async-await/issue-98634.stderr
new file mode 100644
index 00000000000..5160e48d88a
--- /dev/null
+++ b/src/test/ui/async-await/issue-98634.stderr
@@ -0,0 +1,60 @@
+error[E0271]: expected `fn() -> impl Future<Output = ()> {callback}` to be a fn item that returns `Pin<Box<(dyn Future<Output = ()> + 'static)>>`, but it returns `impl Future<Output = ()>`
+  --> $DIR/issue-98634.rs:45:23
+   |
+LL |         StructAsync { callback }.await;
+   |                       ^^^^^^^^ expected struct `Pin`, found opaque type
+   |
+note: while checking the return type of the `async fn`
+  --> $DIR/issue-98634.rs:24:21
+   |
+LL | async fn callback() {}
+   |                     ^ checked the `Output` of this `async fn`, found opaque type
+   = note:   expected struct `Pin<Box<(dyn Future<Output = ()> + 'static)>>`
+           found opaque type `impl Future<Output = ()>`
+note: required by a bound in `StructAsync`
+  --> $DIR/issue-98634.rs:9:35
+   |
+LL | pub struct StructAsync<F: Fn() -> Pin<Box<dyn Future<Output = ()>>>> {
+   |                                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `StructAsync`
+
+error[E0271]: expected `fn() -> impl Future<Output = ()> {callback}` to be a fn item that returns `Pin<Box<(dyn Future<Output = ()> + 'static)>>`, but it returns `impl Future<Output = ()>`
+  --> $DIR/issue-98634.rs:45:9
+   |
+LL |         StructAsync { callback }.await;
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^ expected struct `Pin`, found opaque type
+   |
+note: while checking the return type of the `async fn`
+  --> $DIR/issue-98634.rs:24:21
+   |
+LL | async fn callback() {}
+   |                     ^ checked the `Output` of this `async fn`, found opaque type
+   = note:   expected struct `Pin<Box<(dyn Future<Output = ()> + 'static)>>`
+           found opaque type `impl Future<Output = ()>`
+note: required by a bound in `StructAsync`
+  --> $DIR/issue-98634.rs:9:35
+   |
+LL | pub struct StructAsync<F: Fn() -> Pin<Box<dyn Future<Output = ()>>>> {
+   |                                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `StructAsync`
+
+error[E0271]: expected `fn() -> impl Future<Output = ()> {callback}` to be a fn item that returns `Pin<Box<(dyn Future<Output = ()> + 'static)>>`, but it returns `impl Future<Output = ()>`
+  --> $DIR/issue-98634.rs:45:33
+   |
+LL |         StructAsync { callback }.await;
+   |                                 ^^^^^^ expected struct `Pin`, found opaque type
+   |
+note: while checking the return type of the `async fn`
+  --> $DIR/issue-98634.rs:24:21
+   |
+LL | async fn callback() {}
+   |                     ^ checked the `Output` of this `async fn`, found opaque type
+   = note:   expected struct `Pin<Box<(dyn Future<Output = ()> + 'static)>>`
+           found opaque type `impl Future<Output = ()>`
+note: required by a bound in `StructAsync`
+  --> $DIR/issue-98634.rs:9:35
+   |
+LL | pub struct StructAsync<F: Fn() -> Pin<Box<dyn Future<Output = ()>>>> {
+   |                                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `StructAsync`
+
+error: aborting due to 3 previous errors
+
+For more information about this error, try `rustc --explain E0271`.
diff --git a/src/test/ui/async-await/issues/issue-72312.stderr b/src/test/ui/async-await/issues/issue-72312.stderr
index 5e5a980adb9..aa947b69003 100644
--- a/src/test/ui/async-await/issues/issue-72312.stderr
+++ b/src/test/ui/async-await/issues/issue-72312.stderr
@@ -1,5 +1,5 @@
 error[E0521]: borrowed data escapes outside of associated function
-  --> $DIR/issue-72312.rs:12:24
+  --> $DIR/issue-72312.rs:12:9
    |
 LL |       pub async fn start(&self) {
    |                          -----
@@ -7,17 +7,16 @@ LL |       pub async fn start(&self) {
    |                          `self` is a reference that is only valid in the associated function body
    |                          let's call the lifetime of this reference `'1`
 ...
-LL |           require_static(async move {
-   |  ________________________^
+LL | /         require_static(async move {
 LL | |
 LL | |
 LL | |
 LL | |             &self;
 LL | |         });
-   | |         ^
-   | |         |
-   | |_________`self` escapes the associated function body here
-   |           argument requires that `'1` must outlive `'static`
+   | |          ^
+   | |          |
+   | |__________`self` escapes the associated function body here
+   |            argument requires that `'1` must outlive `'static`
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/async-await/multiple-lifetimes/ret-impl-trait-one.stderr b/src/test/ui/async-await/multiple-lifetimes/ret-impl-trait-one.stderr
index 3128b4df4e2..ae4d0d5853c 100644
--- a/src/test/ui/async-await/multiple-lifetimes/ret-impl-trait-one.stderr
+++ b/src/test/ui/async-await/multiple-lifetimes/ret-impl-trait-one.stderr
@@ -25,7 +25,7 @@ LL | |     (a, b)
 LL | | }
    | |_^
    |
-help: to declare that the `impl Trait` captures `'b`, you can add an explicit `'b` lifetime bound
+help: to declare that `impl Trait<'a>` captures `'b`, you can add an explicit `'b` lifetime bound
    |
 LL | async fn async_ret_impl_trait1<'a, 'b>(a: &'a u8, b: &'b u8) -> impl Trait<'a> + 'b {
    |                                                                                ++++
diff --git a/src/test/ui/borrowck/issue-103624.rs b/src/test/ui/borrowck/issue-103624.rs
new file mode 100644
index 00000000000..f1fa95f9246
--- /dev/null
+++ b/src/test/ui/borrowck/issue-103624.rs
@@ -0,0 +1,31 @@
+// edition:2021
+
+struct StructA {
+    b: StructB,
+}
+
+async fn spawn_blocking<T>(f: impl (Fn() -> T) + Send + Sync + 'static) -> T {
+    todo!()
+}
+
+impl StructA {
+    async fn foo(&self) {
+        let bar = self.b.bar().await;
+        spawn_blocking(move || {
+            //~^ ERROR borrowed data escapes outside of associated function
+            self.b;
+            //~^ ERROR cannot move out of `self.b`, as `self` is a captured variable in an `Fn` closure
+        })
+        .await;
+    }
+}
+
+struct StructB {}
+
+impl StructB {
+    async fn bar(&self) -> Option<u8> {
+        None
+    }
+}
+
+fn main() {}
diff --git a/src/test/ui/borrowck/issue-103624.stderr b/src/test/ui/borrowck/issue-103624.stderr
new file mode 100644
index 00000000000..e6a35dd8801
--- /dev/null
+++ b/src/test/ui/borrowck/issue-103624.stderr
@@ -0,0 +1,35 @@
+error[E0507]: cannot move out of `self.b`, as `self` is a captured variable in an `Fn` closure
+  --> $DIR/issue-103624.rs:16:13
+   |
+LL |     async fn foo(&self) {
+   |                  ----- captured outer variable
+LL |         let bar = self.b.bar().await;
+LL |         spawn_blocking(move || {
+   |                        ------- captured by this `Fn` closure
+LL |
+LL |             self.b;
+   |             ^^^^^^ move occurs because `self.b` has type `StructB`, which does not implement the `Copy` trait
+
+error[E0521]: borrowed data escapes outside of associated function
+  --> $DIR/issue-103624.rs:14:9
+   |
+LL |       async fn foo(&self) {
+   |                    -----
+   |                    |
+   |                    `self` is a reference that is only valid in the associated function body
+   |                    let's call the lifetime of this reference `'1`
+LL |           let bar = self.b.bar().await;
+LL | /         spawn_blocking(move || {
+LL | |
+LL | |             self.b;
+LL | |
+LL | |         })
+   | |          ^
+   | |          |
+   | |__________`self` escapes the associated function body here
+   |            argument requires that `'1` must outlive `'static`
+
+error: aborting due to 2 previous errors
+
+Some errors have detailed explanations: E0507, E0521.
+For more information about an error, try `rustc --explain E0507`.
diff --git a/src/test/ui/cast/issue-88621.rs b/src/test/ui/cast/issue-88621.rs
index 9242b80e229..1679793ee68 100644
--- a/src/test/ui/cast/issue-88621.rs
+++ b/src/test/ui/cast/issue-88621.rs
@@ -1,5 +1,3 @@
-#![feature(arbitrary_enum_discriminant)]
-
 #[repr(u8)]
 enum Kind2 {
     Foo() = 1,
diff --git a/src/test/ui/cast/issue-88621.stderr b/src/test/ui/cast/issue-88621.stderr
index e96d8665152..886145c1baf 100644
--- a/src/test/ui/cast/issue-88621.stderr
+++ b/src/test/ui/cast/issue-88621.stderr
@@ -1,5 +1,5 @@
 error[E0605]: non-primitive cast: `Kind2` as `u8`
-  --> $DIR/issue-88621.rs:11:13
+  --> $DIR/issue-88621.rs:9:13
    |
 LL |     let _ = Kind2::Foo() as u8;
    |             ^^^^^^^^^^^^^^^^^^ an `as` expression can only be used to convert between primitive types or to coerce to a specific trait object
diff --git a/src/test/ui/cfg/cfg-method-receiver-ok.rs b/src/test/ui/cfg/cfg-method-receiver-ok.rs
new file mode 100644
index 00000000000..61ad3b8c17a
--- /dev/null
+++ b/src/test/ui/cfg/cfg-method-receiver-ok.rs
@@ -0,0 +1,14 @@
+// check-pass
+
+macro_rules! foo {
+    () => {
+        #[allow(unreachable_patterns)]
+        {
+            123i32
+        }
+    };
+}
+
+fn main() {
+    let _ = foo!().abs();
+}
diff --git a/src/test/ui/cfg/cfg-method-receiver.rs b/src/test/ui/cfg/cfg-method-receiver.rs
index 78a072f503f..71134ff17b5 100644
--- a/src/test/ui/cfg/cfg-method-receiver.rs
+++ b/src/test/ui/cfg/cfg-method-receiver.rs
@@ -7,6 +7,5 @@ macro_rules! cbor_map {
 
 fn main() {
     cbor_map! { #[cfg(test)] 4};
-    //~^ ERROR attributes on expressions are experimental
-    //~| ERROR removing an expression is not supported in this position
+    //~^ ERROR removing an expression is not supported in this position
 }
diff --git a/src/test/ui/cfg/cfg-method-receiver.stderr b/src/test/ui/cfg/cfg-method-receiver.stderr
index 517fc8168e7..5767a7c1b4b 100644
--- a/src/test/ui/cfg/cfg-method-receiver.stderr
+++ b/src/test/ui/cfg/cfg-method-receiver.stderr
@@ -1,12 +1,3 @@
-error[E0658]: attributes on expressions are experimental
-  --> $DIR/cfg-method-receiver.rs:9:17
-   |
-LL |     cbor_map! { #[cfg(test)] 4};
-   |                 ^^^^^^^^^^^^
-   |
-   = note: see issue #15701 <https://github.com/rust-lang/rust/issues/15701> for more information
-   = help: add `#![feature(stmt_expr_attributes)]` to the crate attributes to enable
-
 error: removing an expression is not supported in this position
   --> $DIR/cfg-method-receiver.rs:9:17
    |
@@ -28,7 +19,6 @@ help: you must specify a concrete type for this numeric value, like `i32`
 LL |     cbor_map! { #[cfg(test)] 4_i32};
    |                              ~~~~~
 
-error: aborting due to 3 previous errors
+error: aborting due to 2 previous errors
 
-Some errors have detailed explanations: E0658, E0689.
-For more information about an error, try `rustc --explain E0658`.
+For more information about this error, try `rustc --explain E0689`.
diff --git a/src/test/ui/coercion/coerce-block-tail-26978.rs b/src/test/ui/coercion/coerce-block-tail-26978.rs
new file mode 100644
index 00000000000..01c8ab5a839
--- /dev/null
+++ b/src/test/ui/coercion/coerce-block-tail-26978.rs
@@ -0,0 +1,11 @@
+// check-fail
+fn f(_: &i32) {}
+
+fn main() {
+    let x = Box::new(1i32);
+
+    f(&x);
+    f(&(x));
+    f(&{x});
+    //~^ ERROR mismatched types
+}
diff --git a/src/test/ui/coercion/coerce-block-tail-26978.stderr b/src/test/ui/coercion/coerce-block-tail-26978.stderr
new file mode 100644
index 00000000000..384debd487c
--- /dev/null
+++ b/src/test/ui/coercion/coerce-block-tail-26978.stderr
@@ -0,0 +1,16 @@
+error[E0308]: mismatched types
+  --> $DIR/coerce-block-tail-26978.rs:9:9
+   |
+LL |     f(&{x});
+   |         ^ expected `i32`, found struct `Box`
+   |
+   = note: expected type `i32`
+            found struct `Box<i32>`
+help: consider unboxing the value
+   |
+LL |     f(&{*x});
+   |         +
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0308`.
diff --git a/src/test/ui/coercion/coerce-block-tail-57749.rs b/src/test/ui/coercion/coerce-block-tail-57749.rs
new file mode 100644
index 00000000000..79b5b33233b
--- /dev/null
+++ b/src/test/ui/coercion/coerce-block-tail-57749.rs
@@ -0,0 +1,35 @@
+// check-fail
+use std::ops::Deref;
+
+fn main() {
+    fn save(who: &str) {
+        println!("I'll save you, {}!", who);
+    }
+
+    struct Madoka;
+
+    impl Deref for Madoka {
+        type Target = str;
+        fn deref(&self) -> &Self::Target {
+            "Madoka"
+        }
+    }
+
+    save(&{ Madoka });
+
+    fn reset(how: &u32) {
+        println!("Reset {} times", how);
+    }
+
+    struct Homura;
+
+    impl Deref for Homura {
+        type Target = u32;
+        fn deref(&self) -> &Self::Target {
+            &42
+        }
+    }
+
+    reset(&{ Homura });
+    //~^ ERROR mismatched types
+}
diff --git a/src/test/ui/coercion/coerce-block-tail-57749.stderr b/src/test/ui/coercion/coerce-block-tail-57749.stderr
new file mode 100644
index 00000000000..d5660c81dbd
--- /dev/null
+++ b/src/test/ui/coercion/coerce-block-tail-57749.stderr
@@ -0,0 +1,14 @@
+error[E0308]: mismatched types
+  --> $DIR/coerce-block-tail-57749.rs:33:14
+   |
+LL |     reset(&{ Homura });
+   |              ^^^^^^ expected `u32`, found struct `Homura`
+   |
+help: consider dereferencing the type
+   |
+LL |     reset(&{ *Homura });
+   |              +
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0308`.
diff --git a/src/test/ui/coercion/coerce-block-tail-83783.rs b/src/test/ui/coercion/coerce-block-tail-83783.rs
new file mode 100644
index 00000000000..18c8ae3bbba
--- /dev/null
+++ b/src/test/ui/coercion/coerce-block-tail-83783.rs
@@ -0,0 +1,13 @@
+// check-fail
+// edition:2018
+fn _consume_reference<T: ?Sized>(_: &T) {}
+
+async fn _foo() {
+    _consume_reference::<i32>(&Box::new(7_i32));
+    _consume_reference::<i32>(&async { Box::new(7_i32) }.await);
+    //~^ ERROR mismatched types
+    _consume_reference::<[i32]>(&vec![7_i32]);
+    _consume_reference::<[i32]>(&async { vec![7_i32] }.await);
+}
+
+fn main() { }
diff --git a/src/test/ui/coercion/coerce-block-tail-83783.stderr b/src/test/ui/coercion/coerce-block-tail-83783.stderr
new file mode 100644
index 00000000000..5f53606ce22
--- /dev/null
+++ b/src/test/ui/coercion/coerce-block-tail-83783.stderr
@@ -0,0 +1,12 @@
+error[E0308]: mismatched types
+  --> $DIR/coerce-block-tail-83783.rs:7:32
+   |
+LL |     _consume_reference::<i32>(&async { Box::new(7_i32) }.await);
+   |                                ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `i32`, found struct `Box`
+   |
+   = note: expected type `i32`
+            found struct `Box<i32>`
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0308`.
diff --git a/src/test/ui/coercion/coerce-block-tail-83850.rs b/src/test/ui/coercion/coerce-block-tail-83850.rs
new file mode 100644
index 00000000000..77fdf999833
--- /dev/null
+++ b/src/test/ui/coercion/coerce-block-tail-83850.rs
@@ -0,0 +1,7 @@
+// check-fail
+fn f(_: &[i32]) {}
+
+fn main() {
+    f(&Box::new([1, 2]));
+    //~^ ERROR mismatched types
+}
diff --git a/src/test/ui/coercion/coerce-block-tail-83850.stderr b/src/test/ui/coercion/coerce-block-tail-83850.stderr
new file mode 100644
index 00000000000..bbf60754370
--- /dev/null
+++ b/src/test/ui/coercion/coerce-block-tail-83850.stderr
@@ -0,0 +1,19 @@
+error[E0308]: mismatched types
+  --> $DIR/coerce-block-tail-83850.rs:5:7
+   |
+LL |     f(&Box::new([1, 2]));
+   |     - ^^^^^^^^^^^^^^^^^ expected slice `[i32]`, found struct `Box`
+   |     |
+   |     arguments to this function are incorrect
+   |
+   = note: expected reference `&[i32]`
+              found reference `&Box<[{integer}; 2]>`
+note: function defined here
+  --> $DIR/coerce-block-tail-83850.rs:2:4
+   |
+LL | fn f(_: &[i32]) {}
+   |    ^ ---------
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0308`.
diff --git a/src/test/ui/coercion/coerce-block-tail.rs b/src/test/ui/coercion/coerce-block-tail.rs
new file mode 100644
index 00000000000..dcbcd376286
--- /dev/null
+++ b/src/test/ui/coercion/coerce-block-tail.rs
@@ -0,0 +1,6 @@
+// check-fail
+fn main() {
+    let _: &str = & { String::from("hahah")};
+    let _: &i32 = & { Box::new(1i32) };
+    //~^ ERROR mismatched types
+}
diff --git a/src/test/ui/coercion/coerce-block-tail.stderr b/src/test/ui/coercion/coerce-block-tail.stderr
new file mode 100644
index 00000000000..318cf75867b
--- /dev/null
+++ b/src/test/ui/coercion/coerce-block-tail.stderr
@@ -0,0 +1,16 @@
+error[E0308]: mismatched types
+  --> $DIR/coerce-block-tail.rs:4:23
+   |
+LL |     let _: &i32 = & { Box::new(1i32) };
+   |                       ^^^^^^^^^^^^^^ expected `i32`, found struct `Box`
+   |
+   = note: expected type `i32`
+            found struct `Box<i32>`
+help: consider unboxing the value
+   |
+LL |     let _: &i32 = & { *Box::new(1i32) };
+   |                       +
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0308`.
diff --git a/src/test/ui/coercion/issue-36007.rs b/src/test/ui/coercion/issue-36007.rs
new file mode 100644
index 00000000000..78812df870d
--- /dev/null
+++ b/src/test/ui/coercion/issue-36007.rs
@@ -0,0 +1,20 @@
+// check-pass
+#![feature(coerce_unsized, unsize)]
+
+use std::marker::Unsize;
+use std::ops::CoerceUnsized;
+
+struct Foo<T: ?Sized>(Box<T>);
+
+impl<T> CoerceUnsized<Foo<dyn Baz>> for Foo<T> where T: Unsize<dyn Baz> {}
+
+struct Bar;
+
+trait Baz {}
+
+impl Baz for Bar {}
+
+fn main() {
+    let foo = Foo(Box::new(Bar));
+    let foobar: Foo<Bar> = foo;
+}
diff --git a/src/test/ui/coherence/coherence-default-trait-impl.stderr b/src/test/ui/coherence/coherence-default-trait-impl.stderr
index b08ccb087d9..63201878272 100644
--- a/src/test/ui/coherence/coherence-default-trait-impl.stderr
+++ b/src/test/ui/coherence/coherence-default-trait-impl.stderr
@@ -3,12 +3,24 @@ error[E0199]: implementing the trait `MySafeTrait` is not unsafe
    |
 LL | unsafe impl MySafeTrait for Foo {}
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+help: remove `unsafe` from this trait implementation
+   |
+LL - unsafe impl MySafeTrait for Foo {}
+LL + impl MySafeTrait for Foo {}
+   |
 
 error[E0200]: the trait `MyUnsafeTrait` requires an `unsafe impl` declaration
   --> $DIR/coherence-default-trait-impl.rs:13:1
    |
 LL | impl MyUnsafeTrait for Foo {}
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: the trait `MyUnsafeTrait` enforces invariants that the compiler can't check. Review the trait documentation and make sure this implementation upholds those invariants before adding the `unsafe` keyword
+help: add `unsafe` to this trait implementation
+   |
+LL | unsafe impl MyUnsafeTrait for Foo {}
+   | ++++++
 
 error: aborting due to 2 previous errors
 
diff --git a/src/test/ui/consts/unnormalized-param-env.rs b/src/test/ui/consts/unnormalized-param-env.rs
new file mode 100644
index 00000000000..a7bbe4db992
--- /dev/null
+++ b/src/test/ui/consts/unnormalized-param-env.rs
@@ -0,0 +1,31 @@
+// check-pass
+
+pub trait CSpace<const N: usize> {
+    type Traj;
+}
+
+pub struct Const<const R: usize>;
+
+pub trait Obstacle<CS, const N: usize> {
+    fn trajectory_free<FT, S1>(&self, t: &FT)
+    where
+        CS::Traj: Sized,
+        CS: CSpace<N>;
+}
+
+// -----
+
+const N: usize = 4;
+
+struct ObstacleSpace2df32;
+
+impl<CS> Obstacle<CS, N> for ObstacleSpace2df32 {
+    fn trajectory_free<TF, S1>(&self, t: &TF)
+    where
+        CS::Traj: Sized,
+        CS: CSpace<N>,
+    {
+    }
+}
+
+fn main() {}
diff --git a/src/test/ui/dropck/dropck-eyepatch-implies-unsafe-impl.stderr b/src/test/ui/dropck/dropck-eyepatch-implies-unsafe-impl.stderr
index 49e55be1b49..82169ee01be 100644
--- a/src/test/ui/dropck/dropck-eyepatch-implies-unsafe-impl.stderr
+++ b/src/test/ui/dropck/dropck-eyepatch-implies-unsafe-impl.stderr
@@ -8,6 +8,12 @@ LL | |     // (unsafe to access self.1  due to #[may_dangle] on A)
 LL | |     fn drop(&mut self) { println!("drop {} {:?}", self.0, self.2); }
 LL | | }
    | |_^
+   |
+   = note: the trait `Drop` enforces invariants that the compiler can't check. Review the trait documentation and make sure this implementation upholds those invariants before adding the `unsafe` keyword
+help: add `unsafe` to this trait implementation
+   |
+LL | unsafe impl<#[may_dangle] A, B: fmt::Debug> Drop for Pt<A, B> {
+   | ++++++
 
 error[E0569]: requires an `unsafe impl` declaration due to `#[may_dangle]` attribute
   --> $DIR/dropck-eyepatch-implies-unsafe-impl.rs:27:1
@@ -19,6 +25,12 @@ LL | |     // (unsafe to access self.1 due to #[may_dangle] on 'a)
 LL | |     fn drop(&mut self) { println!("drop {} {:?}", self.0, self.2); }
 LL | | }
    | |_^
+   |
+   = note: the trait `Drop` enforces invariants that the compiler can't check. Review the trait documentation and make sure this implementation upholds those invariants before adding the `unsafe` keyword
+help: add `unsafe` to this trait implementation
+   |
+LL | unsafe impl<#[may_dangle] 'a, 'b, B: fmt::Debug> Drop for Pr<'a, 'b, B> {
+   | ++++++
 
 error: aborting due to 2 previous errors
 
diff --git a/src/test/ui/dyn-star/no-explicit-dyn-star-cast.rs b/src/test/ui/dyn-star/no-explicit-dyn-star-cast.rs
new file mode 100644
index 00000000000..67240c8e8da
--- /dev/null
+++ b/src/test/ui/dyn-star/no-explicit-dyn-star-cast.rs
@@ -0,0 +1,13 @@
+use std::fmt::Debug;
+
+fn make_dyn_star() {
+    let i = 42usize;
+    let dyn_i: dyn* Debug = i as dyn* Debug;
+    //~^ ERROR casting `usize` as `dyn* Debug` is invalid
+    //~| ERROR dyn* trait objects are unstable
+    //~| ERROR dyn* trait objects are unstable
+}
+
+fn main() {
+    make_dyn_star();
+}
diff --git a/src/test/ui/dyn-star/no-explicit-dyn-star-cast.stderr b/src/test/ui/dyn-star/no-explicit-dyn-star-cast.stderr
new file mode 100644
index 00000000000..687d7db0464
--- /dev/null
+++ b/src/test/ui/dyn-star/no-explicit-dyn-star-cast.stderr
@@ -0,0 +1,28 @@
+error[E0658]: dyn* trait objects are unstable
+  --> $DIR/no-explicit-dyn-star-cast.rs:5:16
+   |
+LL |     let dyn_i: dyn* Debug = i as dyn* Debug;
+   |                ^^^^^^^^^^
+   |
+   = note: see issue #91611 <https://github.com/rust-lang/rust/issues/91611> for more information
+   = help: add `#![feature(dyn_star)]` to the crate attributes to enable
+
+error[E0658]: dyn* trait objects are unstable
+  --> $DIR/no-explicit-dyn-star-cast.rs:5:34
+   |
+LL |     let dyn_i: dyn* Debug = i as dyn* Debug;
+   |                                  ^^^^^^^^^^
+   |
+   = note: see issue #91611 <https://github.com/rust-lang/rust/issues/91611> for more information
+   = help: add `#![feature(dyn_star)]` to the crate attributes to enable
+
+error[E0606]: casting `usize` as `dyn* Debug` is invalid
+  --> $DIR/no-explicit-dyn-star-cast.rs:5:29
+   |
+LL |     let dyn_i: dyn* Debug = i as dyn* Debug;
+   |                             ^^^^^^^^^^^^^^^
+
+error: aborting due to 3 previous errors
+
+Some errors have detailed explanations: E0606, E0658.
+For more information about an error, try `rustc --explain E0606`.
diff --git a/src/test/ui/dyn-star/no-explicit-dyn-star.rs b/src/test/ui/dyn-star/no-explicit-dyn-star.rs
new file mode 100644
index 00000000000..4f726b7c6a6
--- /dev/null
+++ b/src/test/ui/dyn-star/no-explicit-dyn-star.rs
@@ -0,0 +1,8 @@
+// aux-build:dyn-star-foreign.rs
+
+extern crate dyn_star_foreign;
+
+fn main() {
+    dyn_star_foreign::require_dyn_star_display(1usize as _);
+    //~^ ERROR casting `usize` as `dyn* std::fmt::Display` is invalid
+}
diff --git a/src/test/ui/dyn-star/no-explicit-dyn-star.stderr b/src/test/ui/dyn-star/no-explicit-dyn-star.stderr
new file mode 100644
index 00000000000..49706fae19e
--- /dev/null
+++ b/src/test/ui/dyn-star/no-explicit-dyn-star.stderr
@@ -0,0 +1,9 @@
+error[E0606]: casting `usize` as `dyn* std::fmt::Display` is invalid
+  --> $DIR/no-explicit-dyn-star.rs:6:48
+   |
+LL |     dyn_star_foreign::require_dyn_star_display(1usize as _);
+   |                                                ^^^^^^^^^^^
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0606`.
diff --git a/src/test/ui/enum-discriminant/arbitrary_enum_discriminant-no-repr.rs b/src/test/ui/enum-discriminant/arbitrary_enum_discriminant-no-repr.rs
index 4da7b5ab24b..a6e5f70fdef 100644
--- a/src/test/ui/enum-discriminant/arbitrary_enum_discriminant-no-repr.rs
+++ b/src/test/ui/enum-discriminant/arbitrary_enum_discriminant-no-repr.rs
@@ -1,5 +1,4 @@
 #![crate_type="lib"]
-#![feature(arbitrary_enum_discriminant)]
 
 enum Enum {
 //~^ ERROR `#[repr(inttype)]` must be specified
diff --git a/src/test/ui/enum-discriminant/arbitrary_enum_discriminant-no-repr.stderr b/src/test/ui/enum-discriminant/arbitrary_enum_discriminant-no-repr.stderr
index 803bb06fcc2..8cee7469629 100644
--- a/src/test/ui/enum-discriminant/arbitrary_enum_discriminant-no-repr.stderr
+++ b/src/test/ui/enum-discriminant/arbitrary_enum_discriminant-no-repr.stderr
@@ -1,5 +1,5 @@
 error[E0732]: `#[repr(inttype)]` must be specified
-  --> $DIR/arbitrary_enum_discriminant-no-repr.rs:4:1
+  --> $DIR/arbitrary_enum_discriminant-no-repr.rs:3:1
    |
 LL | enum Enum {
    | ^^^^^^^^^
diff --git a/src/test/ui/enum-discriminant/arbitrary_enum_discriminant.rs b/src/test/ui/enum-discriminant/arbitrary_enum_discriminant.rs
index ccc423e4a19..83e74a6e685 100644
--- a/src/test/ui/enum-discriminant/arbitrary_enum_discriminant.rs
+++ b/src/test/ui/enum-discriminant/arbitrary_enum_discriminant.rs
@@ -1,5 +1,5 @@
 // run-pass
-#![feature(arbitrary_enum_discriminant, test)]
+#![feature(test)]
 
 extern crate test;
 
diff --git a/src/test/ui/enum-discriminant/discriminant_value.rs b/src/test/ui/enum-discriminant/discriminant_value.rs
index 65ab411dbcb..f3dfac298ad 100644
--- a/src/test/ui/enum-discriminant/discriminant_value.rs
+++ b/src/test/ui/enum-discriminant/discriminant_value.rs
@@ -1,6 +1,6 @@
 // run-pass
 #![allow(stable_features)]
-#![feature(arbitrary_enum_discriminant, core, core_intrinsics)]
+#![feature(core, core_intrinsics)]
 
 extern crate core;
 use core::intrinsics::discriminant_value;
diff --git a/src/test/ui/enum-discriminant/feature-gate-arbitrary_enum_discriminant.rs b/src/test/ui/enum-discriminant/feature-gate-arbitrary_enum_discriminant.rs
deleted file mode 100644
index 3e90af4d36a..00000000000
--- a/src/test/ui/enum-discriminant/feature-gate-arbitrary_enum_discriminant.rs
+++ /dev/null
@@ -1,10 +0,0 @@
-#![crate_type="lib"]
-
-enum Enum {
-  Unit = 1,
-  //~^ ERROR custom discriminant values are not allowed in enums with tuple or struct variants
-  Tuple() = 2,
-  //~^ ERROR discriminants on non-unit variants are experimental
-  Struct{} = 3,
-  //~^ ERROR discriminants on non-unit variants are experimental
-}
diff --git a/src/test/ui/enum-discriminant/feature-gate-arbitrary_enum_discriminant.stderr b/src/test/ui/enum-discriminant/feature-gate-arbitrary_enum_discriminant.stderr
deleted file mode 100644
index b5f61e6e991..00000000000
--- a/src/test/ui/enum-discriminant/feature-gate-arbitrary_enum_discriminant.stderr
+++ /dev/null
@@ -1,36 +0,0 @@
-error[E0658]: discriminants on non-unit variants are experimental
-  --> $DIR/feature-gate-arbitrary_enum_discriminant.rs:6:13
-   |
-LL |   Tuple() = 2,
-   |             ^
-   |
-   = note: see issue #60553 <https://github.com/rust-lang/rust/issues/60553> for more information
-   = help: add `#![feature(arbitrary_enum_discriminant)]` to the crate attributes to enable
-
-error[E0658]: discriminants on non-unit variants are experimental
-  --> $DIR/feature-gate-arbitrary_enum_discriminant.rs:8:14
-   |
-LL |   Struct{} = 3,
-   |              ^
-   |
-   = note: see issue #60553 <https://github.com/rust-lang/rust/issues/60553> for more information
-   = help: add `#![feature(arbitrary_enum_discriminant)]` to the crate attributes to enable
-
-error[E0658]: custom discriminant values are not allowed in enums with tuple or struct variants
-  --> $DIR/feature-gate-arbitrary_enum_discriminant.rs:4:10
-   |
-LL |   Unit = 1,
-   |          ^ disallowed custom discriminant
-LL |
-LL |   Tuple() = 2,
-   |   ----------- tuple variant defined here
-LL |
-LL |   Struct{} = 3,
-   |   ------------ struct variant defined here
-   |
-   = note: see issue #60553 <https://github.com/rust-lang/rust/issues/60553> for more information
-   = help: add `#![feature(arbitrary_enum_discriminant)]` to the crate attributes to enable
-
-error: aborting due to 3 previous errors
-
-For more information about this error, try `rustc --explain E0658`.
diff --git a/src/test/ui/enum-discriminant/issue-70453-generics-in-discr-ice-2.rs b/src/test/ui/enum-discriminant/issue-70453-generics-in-discr-ice-2.rs
index f927dd18903..ad9fcc25b41 100644
--- a/src/test/ui/enum-discriminant/issue-70453-generics-in-discr-ice-2.rs
+++ b/src/test/ui/enum-discriminant/issue-70453-generics-in-discr-ice-2.rs
@@ -1,4 +1,4 @@
-#![feature(arbitrary_enum_discriminant, core_intrinsics)]
+#![feature(core_intrinsics)]
 
 extern crate core;
 use core::intrinsics::discriminant_value;
diff --git a/src/test/ui/enum-discriminant/issue-70453-polymorphic-ctfe.rs b/src/test/ui/enum-discriminant/issue-70453-polymorphic-ctfe.rs
index e62582fb516..42a062239d3 100644
--- a/src/test/ui/enum-discriminant/issue-70453-polymorphic-ctfe.rs
+++ b/src/test/ui/enum-discriminant/issue-70453-polymorphic-ctfe.rs
@@ -1,4 +1,4 @@
-#![feature(arbitrary_enum_discriminant, core_intrinsics)]
+#![feature(core_intrinsics)]
 
 extern crate core;
 use core::intrinsics::discriminant_value;
diff --git a/src/test/ui/enum-discriminant/issue-70509-partial_eq.rs b/src/test/ui/enum-discriminant/issue-70509-partial_eq.rs
index ae389e11466..3adac7b7262 100644
--- a/src/test/ui/enum-discriminant/issue-70509-partial_eq.rs
+++ b/src/test/ui/enum-discriminant/issue-70509-partial_eq.rs
@@ -1,5 +1,5 @@
 // run-pass
-#![feature(repr128, arbitrary_enum_discriminant)]
+#![feature(repr128)]
 //~^ WARN the feature `repr128` is incomplete
 
 #[derive(PartialEq, Debug)]
diff --git a/src/test/ui/enum-discriminant/issue-70509-partial_eq.stderr b/src/test/ui/enum-discriminant/issue-70509-partial_eq.stderr
index ac93badf215..2eef930c394 100644
--- a/src/test/ui/enum-discriminant/issue-70509-partial_eq.stderr
+++ b/src/test/ui/enum-discriminant/issue-70509-partial_eq.stderr
@@ -1,7 +1,7 @@
 warning: the feature `repr128` is incomplete and may not be safe to use and/or cause compiler crashes
   --> $DIR/issue-70509-partial_eq.rs:2:12
    |
-LL | #![feature(repr128, arbitrary_enum_discriminant)]
+LL | #![feature(repr128)]
    |            ^^^^^^^
    |
    = note: see issue #56071 <https://github.com/rust-lang/rust/issues/56071> for more information
diff --git a/src/test/ui/error-codes/E0199.stderr b/src/test/ui/error-codes/E0199.stderr
index 3632d26cd32..99d808c0d4b 100644
--- a/src/test/ui/error-codes/E0199.stderr
+++ b/src/test/ui/error-codes/E0199.stderr
@@ -3,6 +3,12 @@ error[E0199]: implementing the trait `Bar` is not unsafe
    |
 LL | unsafe impl Bar for Foo { }
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+help: remove `unsafe` from this trait implementation
+   |
+LL - unsafe impl Bar for Foo { }
+LL + impl Bar for Foo { }
+   |
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/error-codes/E0200.stderr b/src/test/ui/error-codes/E0200.stderr
index 677271aad44..1fd86aecee1 100644
--- a/src/test/ui/error-codes/E0200.stderr
+++ b/src/test/ui/error-codes/E0200.stderr
@@ -3,6 +3,12 @@ error[E0200]: the trait `Bar` requires an `unsafe impl` declaration
    |
 LL | impl Bar for Foo { }
    | ^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: the trait `Bar` enforces invariants that the compiler can't check. Review the trait documentation and make sure this implementation upholds those invariants before adding the `unsafe` keyword
+help: add `unsafe` to this trait implementation
+   |
+LL | unsafe impl Bar for Foo { }
+   | ++++++
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/generic-associated-types/issue-87258_a.stderr b/src/test/ui/generic-associated-types/issue-87258_a.stderr
index fa0748a280b..eae9bd9b16f 100644
--- a/src/test/ui/generic-associated-types/issue-87258_a.stderr
+++ b/src/test/ui/generic-associated-types/issue-87258_a.stderr
@@ -4,7 +4,7 @@ error: unconstrained opaque type
 LL |     type FooFuture<'a> = impl Trait1;
    |                          ^^^^^^^^^^^
    |
-   = note: `FooFuture` must be used in combination with a concrete type within the same module
+   = note: `FooFuture` must be used in combination with a concrete type within the same impl
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/impl-trait/hidden-lifetimes.stderr b/src/test/ui/impl-trait/hidden-lifetimes.stderr
index de06ded7acd..3cc47e1e89d 100644
--- a/src/test/ui/impl-trait/hidden-lifetimes.stderr
+++ b/src/test/ui/impl-trait/hidden-lifetimes.stderr
@@ -6,7 +6,7 @@ LL | fn hide_ref<'a, 'b, T: 'static>(x: &'a mut &'b T) -> impl Swap + 'a {
 LL |     x
    |     ^
    |
-help: to declare that the `impl Trait` captures `'b`, you can add an explicit `'b` lifetime bound
+help: to declare that `impl Swap + 'a` captures `'b`, you can add an explicit `'b` lifetime bound
    |
 LL | fn hide_ref<'a, 'b, T: 'static>(x: &'a mut &'b T) -> impl Swap + 'a + 'b {
    |                                                                     ++++
@@ -19,7 +19,7 @@ LL | fn hide_rc_refcell<'a, 'b: 'a, T: 'static>(x: Rc<RefCell<&'b T>>) -> impl S
 LL |     x
    |     ^
    |
-help: to declare that the `impl Trait` captures `'b`, you can add an explicit `'b` lifetime bound
+help: to declare that `impl Swap + 'a` captures `'b`, you can add an explicit `'b` lifetime bound
    |
 LL | fn hide_rc_refcell<'a, 'b: 'a, T: 'static>(x: Rc<RefCell<&'b T>>) -> impl Swap + 'a + 'b {
    |                                                                                     ++++
diff --git a/src/test/ui/impl-trait/in-trait/early.rs b/src/test/ui/impl-trait/in-trait/early.rs
new file mode 100644
index 00000000000..9c1c2b50339
--- /dev/null
+++ b/src/test/ui/impl-trait/in-trait/early.rs
@@ -0,0 +1,23 @@
+// check-pass
+// edition:2021
+
+#![feature(async_fn_in_trait, return_position_impl_trait_in_trait)]
+#![allow(incomplete_features)]
+
+pub trait Foo {
+    async fn bar<'a: 'a>(&'a mut self);
+}
+
+impl Foo for () {
+    async fn bar<'a: 'a>(&'a mut self) {}
+}
+
+pub trait Foo2 {
+    fn bar<'a: 'a>(&'a mut self) -> impl Sized + 'a;
+}
+
+impl Foo2 for () {
+    fn bar<'a: 'a>(&'a mut self) -> impl Sized + 'a {}
+}
+
+fn main() {}
diff --git a/src/test/ui/impl-trait/issue-103599.rs b/src/test/ui/impl-trait/issue-103599.rs
new file mode 100644
index 00000000000..043ae67f2e1
--- /dev/null
+++ b/src/test/ui/impl-trait/issue-103599.rs
@@ -0,0 +1,10 @@
+// check-pass
+
+trait T {}
+
+fn wrap(x: impl T) -> impl T {
+    //~^ WARN function cannot return without recursing
+    wrap(wrap(x))
+}
+
+fn main() {}
diff --git a/src/test/ui/impl-trait/issue-103599.stderr b/src/test/ui/impl-trait/issue-103599.stderr
new file mode 100644
index 00000000000..82038c1dceb
--- /dev/null
+++ b/src/test/ui/impl-trait/issue-103599.stderr
@@ -0,0 +1,14 @@
+warning: function cannot return without recursing
+  --> $DIR/issue-103599.rs:5:1
+   |
+LL | fn wrap(x: impl T) -> impl T {
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ cannot return without recursing
+LL |
+LL |     wrap(wrap(x))
+   |          ------- recursive call site
+   |
+   = help: a `loop` may express intention better if this is on purpose
+   = note: `#[warn(unconditional_recursion)]` on by default
+
+warning: 1 warning emitted
+
diff --git a/src/test/ui/impl-trait/multiple-lifetimes/ordinary-bounds-unrelated.stderr b/src/test/ui/impl-trait/multiple-lifetimes/ordinary-bounds-unrelated.stderr
index cb1dc0b7d50..ec49a61795a 100644
--- a/src/test/ui/impl-trait/multiple-lifetimes/ordinary-bounds-unrelated.stderr
+++ b/src/test/ui/impl-trait/multiple-lifetimes/ordinary-bounds-unrelated.stderr
@@ -7,7 +7,7 @@ LL | fn upper_bounds<'a, 'b, 'c, 'd, 'e>(a: Ordinary<'a>, b: Ordinary<'b>) -> im
 LL |     if condition() { a } else { b }
    |                                 ^
    |
-help: to declare that the `impl Trait` captures `'b`, you can add an explicit `'b` lifetime bound
+help: to declare that `impl Trait<'d, 'e>` captures `'b`, you can add an explicit `'b` lifetime bound
    |
 LL | fn upper_bounds<'a, 'b, 'c, 'd, 'e>(a: Ordinary<'a>, b: Ordinary<'b>) -> impl Trait<'d, 'e> + 'b
    |                                                                                             ++++
diff --git a/src/test/ui/impl-trait/multiple-lifetimes/ordinary-bounds-unsuited.stderr b/src/test/ui/impl-trait/multiple-lifetimes/ordinary-bounds-unsuited.stderr
index 4388e6601a6..c36f9bc6957 100644
--- a/src/test/ui/impl-trait/multiple-lifetimes/ordinary-bounds-unsuited.stderr
+++ b/src/test/ui/impl-trait/multiple-lifetimes/ordinary-bounds-unsuited.stderr
@@ -7,7 +7,7 @@ LL | fn upper_bounds<'a, 'b>(a: Ordinary<'a>, b: Ordinary<'b>) -> impl Trait<'a,
 LL |     if condition() { a } else { b }
    |                                 ^
    |
-help: to declare that the `impl Trait` captures `'b`, you can add an explicit `'b` lifetime bound
+help: to declare that `impl Trait<'a, 'b>` captures `'b`, you can add an explicit `'b` lifetime bound
    |
 LL | fn upper_bounds<'a, 'b>(a: Ordinary<'a>, b: Ordinary<'b>) -> impl Trait<'a, 'b> + 'b
    |                                                                                 ++++
diff --git a/src/test/ui/impl-trait/must_outlive_least_region_or_bound.stderr b/src/test/ui/impl-trait/must_outlive_least_region_or_bound.stderr
index 16767abd722..9c81791fbcb 100644
--- a/src/test/ui/impl-trait/must_outlive_least_region_or_bound.stderr
+++ b/src/test/ui/impl-trait/must_outlive_least_region_or_bound.stderr
@@ -6,7 +6,7 @@ LL | fn elided(x: &i32) -> impl Copy { x }
    |              |
    |              hidden type `&i32` captures the anonymous lifetime defined here
    |
-help: to declare that the `impl Trait` captures `'_`, you can add an explicit `'_` lifetime bound
+help: to declare that `impl Copy` captures `'_`, you can add an explicit `'_` lifetime bound
    |
 LL | fn elided(x: &i32) -> impl Copy + '_ { x }
    |                                 ++++
@@ -19,7 +19,7 @@ LL | fn explicit<'a>(x: &'a i32) -> impl Copy { x }
    |             |
    |             hidden type `&'a i32` captures the lifetime `'a` as defined here
    |
-help: to declare that the `impl Trait` captures `'a`, you can add an explicit `'a` lifetime bound
+help: to declare that `impl Copy` captures `'a`, you can add an explicit `'a` lifetime bound
    |
 LL | fn explicit<'a>(x: &'a i32) -> impl Copy + 'a { x }
    |                                          ++++
@@ -32,7 +32,7 @@ LL | fn elided2(x: &i32) -> impl Copy + 'static { x }
    |               |
    |               let's call the lifetime of this reference `'1`
    |
-help: consider changing the `impl Trait`'s explicit `'static` bound to the lifetime of argument `x`
+help: consider changing `impl Copy + 'static`'s explicit `'static` bound to the lifetime of argument `x`
    |
 LL | fn elided2(x: &i32) -> impl Copy + '_ { x }
    |                                    ~~
@@ -47,7 +47,7 @@ error: lifetime may not live long enough
 LL | fn explicit2<'a>(x: &'a i32) -> impl Copy + 'static { x }
    |              -- lifetime `'a` defined here            ^ returning this value requires that `'a` must outlive `'static`
    |
-help: consider changing the `impl Trait`'s explicit `'static` bound to the lifetime of argument `x`
+help: consider changing `impl Copy + 'static`'s explicit `'static` bound to the lifetime of argument `x`
    |
 LL | fn explicit2<'a>(x: &'a i32) -> impl Copy + 'a { x }
    |                                             ~~
@@ -76,7 +76,7 @@ help: to declare that the trait object captures data from argument `x`, you can
    |
 LL | fn elided5(x: &i32) -> (Box<dyn Debug + '_>, impl Debug) { (Box::new(x), x) }
    |                                       ++++
-help: to declare that the `impl Trait` captures data from argument `x`, you can add an explicit `'_` lifetime bound
+help: to declare that `impl Debug` captures data from argument `x`, you can add an explicit `'_` lifetime bound
    |
 LL | fn elided5(x: &i32) -> (Box<dyn Debug>, impl Debug + '_) { (Box::new(x), x) }
    |                                                    ++++
@@ -87,7 +87,7 @@ error: lifetime may not live long enough
 LL | fn with_bound<'a>(x: &'a i32) -> impl LifetimeTrait<'a> + 'static { x }
    |               -- lifetime `'a` defined here                         ^ returning this value requires that `'a` must outlive `'static`
    |
-help: consider changing the `impl Trait`'s explicit `'static` bound to the lifetime of argument `x`
+help: consider changing `impl LifetimeTrait<'a> + 'static`'s explicit `'static` bound to the lifetime of argument `x`
    |
 LL | fn with_bound<'a>(x: &'a i32) -> impl LifetimeTrait<'a> + 'a { x }
    |                                                           ~~
@@ -104,7 +104,7 @@ LL | fn move_lifetime_into_fn<'a, 'b>(x: &'a u32, y: &'b u32) -> impl Fn(&'a u32
 LL |     move |_| println!("{}", y)
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
-help: to declare that the `impl Trait` captures `'b`, you can add an explicit `'b` lifetime bound
+help: to declare that `impl Fn(&'a u32)` captures `'b`, you can add an explicit `'b` lifetime bound
    |
 LL | fn move_lifetime_into_fn<'a, 'b>(x: &'a u32, y: &'b u32) -> impl Fn(&'a u32) + 'b {
    |                                                                              ++++
diff --git a/src/test/ui/impl-trait/region-escape-via-bound.stderr b/src/test/ui/impl-trait/region-escape-via-bound.stderr
index fdb2fe022b4..44a790cb1a4 100644
--- a/src/test/ui/impl-trait/region-escape-via-bound.stderr
+++ b/src/test/ui/impl-trait/region-escape-via-bound.stderr
@@ -7,7 +7,7 @@ LL | fn foo<'x, 'y>(x: Cell<&'x u32>) -> impl Trait<'y>
 LL |     x
    |     ^
    |
-help: to declare that the `impl Trait` captures `'x`, you can add an explicit `'x` lifetime bound
+help: to declare that `impl Trait<'y>` captures `'x`, you can add an explicit `'x` lifetime bound
    |
 LL | fn foo<'x, 'y>(x: Cell<&'x u32>) -> impl Trait<'y> + 'x
    |                                                    ++++
diff --git a/src/test/ui/impl-trait/static-return-lifetime-infered.stderr b/src/test/ui/impl-trait/static-return-lifetime-infered.stderr
index b8681523155..b365bd88454 100644
--- a/src/test/ui/impl-trait/static-return-lifetime-infered.stderr
+++ b/src/test/ui/impl-trait/static-return-lifetime-infered.stderr
@@ -6,7 +6,7 @@ LL |     fn iter_values_anon(&self) -> impl Iterator<Item=u32> {
 LL |         self.x.iter().map(|a| a.0)
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
-help: to declare that the `impl Trait` captures `'_`, you can add an explicit `'_` lifetime bound
+help: to declare that `impl Iterator<Item = u32>` captures `'_`, you can add an explicit `'_` lifetime bound
    |
 LL |     fn iter_values_anon(&self) -> impl Iterator<Item=u32> + '_ {
    |                                                           ++++
@@ -19,7 +19,7 @@ LL |     fn iter_values_anon(&self) -> impl Iterator<Item=u32> {
 LL |         self.x.iter().map(|a| a.0)
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
-help: to declare that the `impl Trait` captures `'_`, you can add an explicit `'_` lifetime bound
+help: to declare that `impl Iterator<Item = u32>` captures `'_`, you can add an explicit `'_` lifetime bound
    |
 LL |     fn iter_values_anon(&self) -> impl Iterator<Item=u32> + '_ {
    |                                                           ++++
@@ -32,7 +32,7 @@ LL |     fn iter_values<'a>(&'a self) -> impl Iterator<Item=u32> {
 LL |         self.x.iter().map(|a| a.0)
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
-help: to declare that the `impl Trait` captures `'a`, you can add an explicit `'a` lifetime bound
+help: to declare that `impl Iterator<Item = u32>` captures `'a`, you can add an explicit `'a` lifetime bound
    |
 LL |     fn iter_values<'a>(&'a self) -> impl Iterator<Item=u32> + 'a {
    |                                                             ++++
@@ -45,7 +45,7 @@ LL |     fn iter_values<'a>(&'a self) -> impl Iterator<Item=u32> {
 LL |         self.x.iter().map(|a| a.0)
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
-help: to declare that the `impl Trait` captures `'a`, you can add an explicit `'a` lifetime bound
+help: to declare that `impl Iterator<Item = u32>` captures `'a`, you can add an explicit `'a` lifetime bound
    |
 LL |     fn iter_values<'a>(&'a self) -> impl Iterator<Item=u32> + 'a {
    |                                                             ++++
diff --git a/src/test/ui/intrinsics/panic-uninitialized-zeroed.rs b/src/test/ui/intrinsics/panic-uninitialized-zeroed.rs
index ae44ffd29bd..ec3860a322f 100644
--- a/src/test/ui/intrinsics/panic-uninitialized-zeroed.rs
+++ b/src/test/ui/intrinsics/panic-uninitialized-zeroed.rs
@@ -7,7 +7,7 @@
 
 // This test checks panic emitted from `mem::{uninitialized,zeroed}`.
 
-#![feature(never_type, arbitrary_enum_discriminant)]
+#![feature(never_type)]
 #![allow(deprecated, invalid_value)]
 
 use std::{
diff --git a/src/test/ui/lifetimes/lifetime-elision-return-type-requires-explicit-lifetime.rs b/src/test/ui/lifetimes/lifetime-elision-return-type-requires-explicit-lifetime.rs
index 7a2eba518fe..d0a8fe795ef 100644
--- a/src/test/ui/lifetimes/lifetime-elision-return-type-requires-explicit-lifetime.rs
+++ b/src/test/ui/lifetimes/lifetime-elision-return-type-requires-explicit-lifetime.rs
@@ -42,4 +42,10 @@ fn k<'a, T: WithLifetime<'a>>(_x: T::Output) -> &isize {
     panic!()
 }
 
+fn l<'a>(_: &'a str, _: &'a str) -> &str { "" }
+//~^ ERROR missing lifetime specifier
+
+// This is ok because both `'a` are for the same parameter.
+fn m<'a>(_: &'a Foo<'a>) -> &str { "" }
+
 fn main() {}
diff --git a/src/test/ui/lifetimes/lifetime-elision-return-type-requires-explicit-lifetime.stderr b/src/test/ui/lifetimes/lifetime-elision-return-type-requires-explicit-lifetime.stderr
index d0775487955..5eee953ef18 100644
--- a/src/test/ui/lifetimes/lifetime-elision-return-type-requires-explicit-lifetime.stderr
+++ b/src/test/ui/lifetimes/lifetime-elision-return-type-requires-explicit-lifetime.stderr
@@ -70,6 +70,18 @@ help: consider using the `'a` lifetime
 LL | fn k<'a, T: WithLifetime<'a>>(_x: T::Output) -> &'a isize {
    |                                                  ++
 
-error: aborting due to 6 previous errors
+error[E0106]: missing lifetime specifier
+  --> $DIR/lifetime-elision-return-type-requires-explicit-lifetime.rs:45:37
+   |
+LL | fn l<'a>(_: &'a str, _: &'a str) -> &str { "" }
+   |             -------     -------     ^ expected named lifetime parameter
+   |
+   = help: this function's return type contains a borrowed value with an elided lifetime, but the lifetime cannot be derived from the arguments
+help: consider using the `'a` lifetime
+   |
+LL | fn l<'a>(_: &'a str, _: &'a str) -> &'a str { "" }
+   |                                      ++
+
+error: aborting due to 7 previous errors
 
 For more information about this error, try `rustc --explain E0106`.
diff --git a/src/test/ui/lint/inline-trait-and-foreign-items.stderr b/src/test/ui/lint/inline-trait-and-foreign-items.stderr
index 27399746bed..2f1fb4c46c0 100644
--- a/src/test/ui/lint/inline-trait-and-foreign-items.stderr
+++ b/src/test/ui/lint/inline-trait-and-foreign-items.stderr
@@ -67,7 +67,7 @@ error: unconstrained opaque type
 LL |     type U = impl Trait;
    |              ^^^^^^^^^^
    |
-   = note: `U` must be used in combination with a concrete type within the same module
+   = note: `U` must be used in combination with a concrete type within the same impl
 
 error: aborting due to 6 previous errors; 2 warnings emitted
 
diff --git a/src/test/ui/lint/no-coverage.stderr b/src/test/ui/lint/no-coverage.stderr
index 8452ccc7a03..404efbeac1e 100644
--- a/src/test/ui/lint/no-coverage.stderr
+++ b/src/test/ui/lint/no-coverage.stderr
@@ -94,7 +94,7 @@ error: unconstrained opaque type
 LL |     type U = impl Trait;
    |              ^^^^^^^^^^
    |
-   = note: `U` must be used in combination with a concrete type within the same module
+   = note: `U` must be used in combination with a concrete type within the same impl
 
 error: aborting due to 7 previous errors; 6 warnings emitted
 
diff --git a/src/test/ui/macros/macro_rules-unmatchable-literals.rs b/src/test/ui/macros/macro_rules-unmatchable-literals.rs
new file mode 100644
index 00000000000..bde0fe1a015
--- /dev/null
+++ b/src/test/ui/macros/macro_rules-unmatchable-literals.rs
@@ -0,0 +1,14 @@
+// Pinning tests for things that don't work to make sure we notice if that changes
+
+#![crate_type = "lib"]
+
+macro_rules! octal_with_bad_digit {
+    ( 0o1238 ) => {}; //~ ERROR invalid digit
+}
+
+macro_rules! binary_with_bad_digit {
+    ( 0b012 ) => {}; //~ ERROR invalid digit
+}
+
+// This can't happen for Hex and Decimal as things like `123A` and `0xFFG`
+// get treated as unknown *suffixes*, rather than digits.
diff --git a/src/test/ui/macros/macro_rules-unmatchable-literals.stderr b/src/test/ui/macros/macro_rules-unmatchable-literals.stderr
new file mode 100644
index 00000000000..956a669791d
--- /dev/null
+++ b/src/test/ui/macros/macro_rules-unmatchable-literals.stderr
@@ -0,0 +1,14 @@
+error: invalid digit for a base 8 literal
+  --> $DIR/macro_rules-unmatchable-literals.rs:6:12
+   |
+LL |     ( 0o1238 ) => {};
+   |            ^
+
+error: invalid digit for a base 2 literal
+  --> $DIR/macro_rules-unmatchable-literals.rs:10:11
+   |
+LL |     ( 0b012 ) => {};
+   |           ^
+
+error: aborting due to 2 previous errors
+
diff --git a/src/test/ui/macros/macros-nonfatal-errors.rs b/src/test/ui/macros/macros-nonfatal-errors.rs
index 140cc5b0fd8..ab14c35893d 100644
--- a/src/test/ui/macros/macros-nonfatal-errors.rs
+++ b/src/test/ui/macros/macros-nonfatal-errors.rs
@@ -4,7 +4,7 @@
 // immediately, so that we get more errors listed at a time.
 
 #![feature(trace_macros, concat_idents)]
-#![feature(stmt_expr_attributes, arbitrary_enum_discriminant)]
+#![feature(stmt_expr_attributes)]
 
 use std::arch::asm;
 
diff --git a/src/test/ui/marker_trait_attr/overlap-marker-trait-with-static-lifetime.rs b/src/test/ui/marker_trait_attr/overlap-marker-trait-with-static-lifetime.rs
new file mode 100644
index 00000000000..62aa22d41ed
--- /dev/null
+++ b/src/test/ui/marker_trait_attr/overlap-marker-trait-with-static-lifetime.rs
@@ -0,0 +1,10 @@
+// check-pass
+#![feature(marker_trait_attr)]
+
+#[marker]
+trait Marker {}
+
+impl Marker for &'static () {}
+impl Marker for &'static () {}
+
+fn main() {}
diff --git a/src/test/ui/marker_trait_attr/overlap-marker-trait-with-underscore-lifetime.rs b/src/test/ui/marker_trait_attr/overlap-marker-trait-with-underscore-lifetime.rs
new file mode 100644
index 00000000000..eabce1aeff1
--- /dev/null
+++ b/src/test/ui/marker_trait_attr/overlap-marker-trait-with-underscore-lifetime.rs
@@ -0,0 +1,9 @@
+#![feature(marker_trait_attr)]
+
+#[marker]
+trait Marker {}
+
+impl Marker for &'_ () {} //~ ERROR type annotations needed
+impl Marker for &'_ () {} //~ ERROR type annotations needed
+
+fn main() {}
diff --git a/src/test/ui/marker_trait_attr/overlap-marker-trait-with-underscore-lifetime.stderr b/src/test/ui/marker_trait_attr/overlap-marker-trait-with-underscore-lifetime.stderr
new file mode 100644
index 00000000000..235c89e200a
--- /dev/null
+++ b/src/test/ui/marker_trait_attr/overlap-marker-trait-with-underscore-lifetime.stderr
@@ -0,0 +1,31 @@
+error[E0283]: type annotations needed: cannot satisfy `&(): Marker`
+  --> $DIR/overlap-marker-trait-with-underscore-lifetime.rs:6:6
+   |
+LL | impl Marker for &'_ () {}
+   |      ^^^^^^
+   |
+note: multiple `impl`s satisfying `&(): Marker` found
+  --> $DIR/overlap-marker-trait-with-underscore-lifetime.rs:6:1
+   |
+LL | impl Marker for &'_ () {}
+   | ^^^^^^^^^^^^^^^^^^^^^^
+LL | impl Marker for &'_ () {}
+   | ^^^^^^^^^^^^^^^^^^^^^^
+
+error[E0283]: type annotations needed: cannot satisfy `&(): Marker`
+  --> $DIR/overlap-marker-trait-with-underscore-lifetime.rs:7:6
+   |
+LL | impl Marker for &'_ () {}
+   |      ^^^^^^
+   |
+note: multiple `impl`s satisfying `&(): Marker` found
+  --> $DIR/overlap-marker-trait-with-underscore-lifetime.rs:6:1
+   |
+LL | impl Marker for &'_ () {}
+   | ^^^^^^^^^^^^^^^^^^^^^^
+LL | impl Marker for &'_ () {}
+   | ^^^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0283`.
diff --git a/src/test/ui/marker_trait_attr/overlap-marker-trait.rs b/src/test/ui/marker_trait_attr/overlap-marker-trait.rs
index 8794d42f411..67e55179775 100644
--- a/src/test/ui/marker_trait_attr/overlap-marker-trait.rs
+++ b/src/test/ui/marker_trait_attr/overlap-marker-trait.rs
@@ -7,7 +7,8 @@
 
 use std::fmt::{Debug, Display};
 
-#[marker] trait Marker {}
+#[marker]
+trait Marker {}
 
 impl<T: Debug> Marker for T {}
 impl<T: Display> Marker for T {}
diff --git a/src/test/ui/marker_trait_attr/overlap-marker-trait.stderr b/src/test/ui/marker_trait_attr/overlap-marker-trait.stderr
index 1f341059794..133bc0484ee 100644
--- a/src/test/ui/marker_trait_attr/overlap-marker-trait.stderr
+++ b/src/test/ui/marker_trait_attr/overlap-marker-trait.stderr
@@ -1,11 +1,11 @@
 error[E0277]: the trait bound `NotDebugOrDisplay: Marker` is not satisfied
-  --> $DIR/overlap-marker-trait.rs:27:17
+  --> $DIR/overlap-marker-trait.rs:28:17
    |
 LL |     is_marker::<NotDebugOrDisplay>();
    |                 ^^^^^^^^^^^^^^^^^ the trait `Marker` is not implemented for `NotDebugOrDisplay`
    |
 note: required by a bound in `is_marker`
-  --> $DIR/overlap-marker-trait.rs:15:17
+  --> $DIR/overlap-marker-trait.rs:16:17
    |
 LL | fn is_marker<T: Marker>() { }
    |                 ^^^^^^ required by this bound in `is_marker`
diff --git a/src/test/ui/marker_trait_attr/overlap-permitted-for-annotated-marker-traits.rs b/src/test/ui/marker_trait_attr/overlap-permitted-for-annotated-marker-traits.rs
index 38331390237..f7654458feb 100644
--- a/src/test/ui/marker_trait_attr/overlap-permitted-for-annotated-marker-traits.rs
+++ b/src/test/ui/marker_trait_attr/overlap-permitted-for-annotated-marker-traits.rs
@@ -7,7 +7,8 @@
 
 use std::fmt::{Debug, Display};
 
-#[marker] trait MyMarker {}
+#[marker]
+trait MyMarker {}
 
 impl<T: Debug> MyMarker for T {}
 impl<T: Display> MyMarker for T {}
diff --git a/src/test/ui/nll/closure-requirements/propagate-approximated-shorter-to-static-comparing-against-free.stderr b/src/test/ui/nll/closure-requirements/propagate-approximated-shorter-to-static-comparing-against-free.stderr
index da4bc499c7e..01293379700 100644
--- a/src/test/ui/nll/closure-requirements/propagate-approximated-shorter-to-static-comparing-against-free.stderr
+++ b/src/test/ui/nll/closure-requirements/propagate-approximated-shorter-to-static-comparing-against-free.stderr
@@ -53,14 +53,15 @@ LL | fn case2() {
 error[E0597]: `a` does not live long enough
   --> $DIR/propagate-approximated-shorter-to-static-comparing-against-free.rs:30:26
    |
-LL |     let cell = Cell::new(&a);
-   |                ----------^^-
-   |                |         |
-   |                |         borrowed value does not live long enough
-   |                argument requires that `a` is borrowed for `'static`
+LL |       let cell = Cell::new(&a);
+   |                            ^^ borrowed value does not live long enough
 ...
-LL | }
-   | - `a` dropped here while still borrowed
+LL | /     foo(cell, |cell_a, cell_x| {
+LL | |         cell_x.set(cell_a.get()); // forces 'a: 'x, implies 'a = 'static -> borrow error
+LL | |     })
+   | |______- argument requires that `a` is borrowed for `'static`
+LL |   }
+   |   - `a` dropped here while still borrowed
 
 error: aborting due to 2 previous errors
 
diff --git a/src/test/ui/nll/ty-outlives/impl-trait-captures.stderr b/src/test/ui/nll/ty-outlives/impl-trait-captures.stderr
index 6a8a1ad1caa..737cb35841c 100644
--- a/src/test/ui/nll/ty-outlives/impl-trait-captures.stderr
+++ b/src/test/ui/nll/ty-outlives/impl-trait-captures.stderr
@@ -6,7 +6,7 @@ LL | fn foo<'a, T>(x: &T) -> impl Foo<'a> {
 LL |     x
    |     ^
    |
-help: to declare that the `impl Trait` captures `ReFree(DefId(0:8 ~ impl_trait_captures[1afc]::foo), BrNamed(DefId(0:12 ~ impl_trait_captures[1afc]::foo::'_), '_))`, you can add an explicit `ReFree(DefId(0:8 ~ impl_trait_captures[1afc]::foo), BrNamed(DefId(0:12 ~ impl_trait_captures[1afc]::foo::'_), '_))` lifetime bound
+help: to declare that `Opaque(DefId(0:13 ~ impl_trait_captures[1afc]::foo::{opaque#0}), [ReEarlyBound(0, 'a), T, ReEarlyBound(2, 'a)])` captures `ReFree(DefId(0:8 ~ impl_trait_captures[1afc]::foo), BrNamed(DefId(0:12 ~ impl_trait_captures[1afc]::foo::'_), '_))`, you can add an explicit `ReFree(DefId(0:8 ~ impl_trait_captures[1afc]::foo), BrNamed(DefId(0:12 ~ impl_trait_captures[1afc]::foo::'_), '_))` lifetime bound
    |
 LL | fn foo<'a, T>(x: &T) -> impl Foo<'a> + ReFree(DefId(0:8 ~ impl_trait_captures[1afc]::foo), BrNamed(DefId(0:12 ~ impl_trait_captures[1afc]::foo::'_), '_)) {
    |                                      ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
diff --git a/src/test/ui/nll/user-annotations/adt-nullary-enums.stderr b/src/test/ui/nll/user-annotations/adt-nullary-enums.stderr
index bb703412228..3326fa521fc 100644
--- a/src/test/ui/nll/user-annotations/adt-nullary-enums.stderr
+++ b/src/test/ui/nll/user-annotations/adt-nullary-enums.stderr
@@ -1,14 +1,14 @@
 error[E0597]: `c` does not live long enough
   --> $DIR/adt-nullary-enums.rs:33:41
    |
-LL |         SomeEnum::SomeVariant(Cell::new(&c)),
-   |                               ----------^^-
-   |                               |         |
-   |                               |         borrowed value does not live long enough
-   |                               argument requires that `c` is borrowed for `'static`
-...
-LL | }
-   | - `c` dropped here while still borrowed
+LL | /     combine(
+LL | |         SomeEnum::SomeVariant(Cell::new(&c)),
+   | |                                         ^^ borrowed value does not live long enough
+LL | |         SomeEnum::SomeOtherVariant::<Cell<&'static u32>>,
+LL | |     );
+   | |_____- argument requires that `c` is borrowed for `'static`
+LL |   }
+   |   - `c` dropped here while still borrowed
 
 error[E0597]: `c` does not live long enough
   --> $DIR/adt-nullary-enums.rs:41:41
diff --git a/src/test/ui/parser/issue-103425.rs b/src/test/ui/parser/issue-103425.rs
new file mode 100644
index 00000000000..c2f8123ca4e
--- /dev/null
+++ b/src/test/ui/parser/issue-103425.rs
@@ -0,0 +1,15 @@
+fn f() -> f32 {
+    3
+    //~^ ERROR expected `;`
+    5.0
+}
+
+fn k() -> f32 {
+    2_u32
+    //~^ ERROR expected `;`
+    3_i8
+    //~^ ERROR expected `;`
+    5.0
+}
+
+fn main() {}
diff --git a/src/test/ui/parser/issue-103425.stderr b/src/test/ui/parser/issue-103425.stderr
new file mode 100644
index 00000000000..0efe3e3ca71
--- /dev/null
+++ b/src/test/ui/parser/issue-103425.stderr
@@ -0,0 +1,29 @@
+error: expected `;`, found `5.0`
+  --> $DIR/issue-103425.rs:2:6
+   |
+LL |     3
+   |      ^ help: add `;` here
+LL |
+LL |     5.0
+   |     --- unexpected token
+
+error: expected `;`, found `3_i8`
+  --> $DIR/issue-103425.rs:8:10
+   |
+LL |     2_u32
+   |          ^ help: add `;` here
+LL |
+LL |     3_i8
+   |     ---- unexpected token
+
+error: expected `;`, found `5.0`
+  --> $DIR/issue-103425.rs:10:9
+   |
+LL |     3_i8
+   |         ^ help: add `;` here
+LL |
+LL |     5.0
+   |     --- unexpected token
+
+error: aborting due to 3 previous errors
+
diff --git a/src/test/ui/parser/issues/issue-17383.rs b/src/test/ui/parser/issues/issue-17383.rs
deleted file mode 100644
index 7bf0e64f2c0..00000000000
--- a/src/test/ui/parser/issues/issue-17383.rs
+++ /dev/null
@@ -1,7 +0,0 @@
-enum X {
-    A = 3,
-    //~^ ERROR custom discriminant values are not allowed in enums with tuple or struct variants
-    B(usize)
-}
-
-fn main() {}
diff --git a/src/test/ui/parser/issues/issue-17383.stderr b/src/test/ui/parser/issues/issue-17383.stderr
deleted file mode 100644
index 265d6e14866..00000000000
--- a/src/test/ui/parser/issues/issue-17383.stderr
+++ /dev/null
@@ -1,15 +0,0 @@
-error[E0658]: custom discriminant values are not allowed in enums with tuple or struct variants
-  --> $DIR/issue-17383.rs:2:9
-   |
-LL |     A = 3,
-   |         ^ disallowed custom discriminant
-LL |
-LL |     B(usize)
-   |     -------- tuple variant defined here
-   |
-   = note: see issue #60553 <https://github.com/rust-lang/rust/issues/60553> for more information
-   = help: add `#![feature(arbitrary_enum_discriminant)]` 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/src/test/ui/parser/tag-variant-disr-non-nullary.rs b/src/test/ui/parser/tag-variant-disr-non-nullary.rs
deleted file mode 100644
index a9cfdd549c7..00000000000
--- a/src/test/ui/parser/tag-variant-disr-non-nullary.rs
+++ /dev/null
@@ -1,12 +0,0 @@
-enum Color {
-    Red = 0xff0000,
-    //~^ ERROR custom discriminant values are not allowed in enums with tuple or struct variants
-    Green = 0x00ff00,
-    Blue = 0x0000ff,
-    Black = 0x000000,
-    White = 0xffffff,
-    Other(usize),
-    Other2(usize, usize),
-}
-
-fn main() {}
diff --git a/src/test/ui/parser/tag-variant-disr-non-nullary.stderr b/src/test/ui/parser/tag-variant-disr-non-nullary.stderr
deleted file mode 100644
index 79f044a0675..00000000000
--- a/src/test/ui/parser/tag-variant-disr-non-nullary.stderr
+++ /dev/null
@@ -1,25 +0,0 @@
-error[E0658]: custom discriminant values are not allowed in enums with tuple or struct variants
-  --> $DIR/tag-variant-disr-non-nullary.rs:2:11
-   |
-LL |     Red = 0xff0000,
-   |           ^^^^^^^^ disallowed custom discriminant
-LL |
-LL |     Green = 0x00ff00,
-   |             ^^^^^^^^ disallowed custom discriminant
-LL |     Blue = 0x0000ff,
-   |            ^^^^^^^^ disallowed custom discriminant
-LL |     Black = 0x000000,
-   |             ^^^^^^^^ disallowed custom discriminant
-LL |     White = 0xffffff,
-   |             ^^^^^^^^ disallowed custom discriminant
-LL |     Other(usize),
-   |     ------------ tuple variant defined here
-LL |     Other2(usize, usize),
-   |     -------------------- tuple variant defined here
-   |
-   = note: see issue #60553 <https://github.com/rust-lang/rust/issues/60553> for more information
-   = help: add `#![feature(arbitrary_enum_discriminant)]` 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/src/test/ui/privacy/access_levels.rs b/src/test/ui/privacy/access_levels.rs
deleted file mode 100644
index 42c9975bedb..00000000000
--- a/src/test/ui/privacy/access_levels.rs
+++ /dev/null
@@ -1,75 +0,0 @@
-#![feature(rustc_attrs)]
-
-#[rustc_effective_visibility]
-mod outer { //~ ERROR Public: pub(crate), Exported: pub(crate), Reachable: pub(crate), ReachableFromImplTrait: pub(crate)
-    #[rustc_effective_visibility]
-    pub mod inner1 { //~ ERROR Public: pub(crate), Exported: pub, Reachable: pub, ReachableFromImplTrait: pub
-
-        #[rustc_effective_visibility]
-        extern "C" {} //~ ERROR Public: pub(crate), Exported: pub, Reachable: pub, ReachableFromImplTrait: pub
-
-        #[rustc_effective_visibility]
-        pub trait PubTrait { //~ ERROR Public: pub(crate), Exported: pub, Reachable: pub, ReachableFromImplTrait: pub
-            #[rustc_effective_visibility]
-            const A: i32; //~ ERROR Public: pub(crate), Exported: pub, Reachable: pub, ReachableFromImplTrait: pub
-            #[rustc_effective_visibility]
-            type B; //~ ERROR Public: pub(crate), Exported: pub, Reachable: pub, ReachableFromImplTrait: pub
-        }
-
-        #[rustc_effective_visibility]
-        struct PrivStruct; //~ ERROR Public: pub(self), Exported: pub(self), Reachable: pub(self), ReachableFromImplTrait: pub(self)
-
-        #[rustc_effective_visibility]
-        pub union PubUnion { //~ ERROR Public: pub(crate), Exported: pub, Reachable: pub, ReachableFromImplTrait: pub
-            #[rustc_effective_visibility]
-            a: u8, //~ ERROR Public: pub(self), Exported: pub(self), Reachable: pub(self), ReachableFromImplTrait: pub(self)
-            #[rustc_effective_visibility]
-            pub b: u8, //~ ERROR Public: pub(crate), Exported: pub, Reachable: pub, ReachableFromImplTrait: pub
-        }
-
-        #[rustc_effective_visibility]
-        pub enum Enum { //~ ERROR Public: pub(crate), Exported: pub, Reachable: pub, ReachableFromImplTrait: pub
-            #[rustc_effective_visibility]
-            A( //~ ERROR Public: pub(crate), Exported: pub, Reachable: pub, ReachableFromImplTrait: pub
-                #[rustc_effective_visibility]
-                PubUnion,  //~ ERROR Public: pub(crate), Exported: pub, Reachable: pub, ReachableFromImplTrait: pub
-            ),
-        }
-    }
-
-    #[rustc_effective_visibility]
-    macro_rules! none_macro { //~ Public: pub(crate), Exported: pub(crate), Reachable: pub(crate), ReachableFromImplTrait: pub(crate)
-        () => {};
-    }
-
-    #[macro_export]
-    #[rustc_effective_visibility]
-    macro_rules! public_macro { //~ Public: pub, Exported: pub, Reachable: pub, ReachableFromImplTrait: pub
-        () => {};
-    }
-
-    #[rustc_effective_visibility]
-    pub struct ReachableStruct { //~ ERROR Public: pub(crate), Exported: pub(crate), Reachable: pub, ReachableFromImplTrait: pub
-        #[rustc_effective_visibility]
-        pub a: u8, //~ ERROR Public: pub(crate), Exported: pub(crate), Reachable: pub, ReachableFromImplTrait: pub
-    }
-}
-
-#[rustc_effective_visibility]
-pub use outer::inner1; //~ ERROR Public: pub, Exported: pub, Reachable: pub, ReachableFromImplTrait: pub
-
-pub fn foo() -> outer::ReachableStruct { outer::ReachableStruct {a: 0} }
-
-mod half_public_import {
-    #[rustc_effective_visibility]
-    pub type HalfPublicImport = u8; //~ ERROR Public: pub(crate), Exported: pub, Reachable: pub, ReachableFromImplTrait: pub
-    #[rustc_effective_visibility]
-    #[allow(non_upper_case_globals)]
-    pub(crate) const HalfPublicImport: u8 = 0; //~ ERROR Public: pub(crate), Exported: pub(crate), Reachable: pub(crate), ReachableFromImplTrait: pub(crate)
-}
-
-#[rustc_effective_visibility]
-pub use half_public_import::HalfPublicImport; //~ ERROR Public: pub, Exported: pub, Reachable: pub, ReachableFromImplTrait: pub
-                                              //~^ ERROR Public: pub, Exported: pub, Reachable: pub, ReachableFromImplTrait: pub
-
-fn main() {}
diff --git a/src/test/ui/privacy/access_levels.stderr b/src/test/ui/privacy/access_levels.stderr
deleted file mode 100644
index 111e02bc329..00000000000
--- a/src/test/ui/privacy/access_levels.stderr
+++ /dev/null
@@ -1,134 +0,0 @@
-error: Public: pub(crate), Exported: pub(crate), Reachable: pub(crate), ReachableFromImplTrait: pub(crate)
-  --> $DIR/access_levels.rs:4:1
-   |
-LL | mod outer {
-   | ^^^^^^^^^
-
-error: Public: pub(crate), Exported: pub, Reachable: pub, ReachableFromImplTrait: pub
-  --> $DIR/access_levels.rs:6:5
-   |
-LL |     pub mod inner1 {
-   |     ^^^^^^^^^^^^^^
-
-error: Public: pub(crate), Exported: pub, Reachable: pub, ReachableFromImplTrait: pub
-  --> $DIR/access_levels.rs:9:9
-   |
-LL |         extern "C" {}
-   |         ^^^^^^^^^^^^^
-
-error: Public: pub(crate), Exported: pub, Reachable: pub, ReachableFromImplTrait: pub
-  --> $DIR/access_levels.rs:12:9
-   |
-LL |         pub trait PubTrait {
-   |         ^^^^^^^^^^^^^^^^^^
-
-error: Public: pub(self), Exported: pub(self), Reachable: pub(self), ReachableFromImplTrait: pub(self)
-  --> $DIR/access_levels.rs:20:9
-   |
-LL |         struct PrivStruct;
-   |         ^^^^^^^^^^^^^^^^^
-
-error: Public: pub(crate), Exported: pub, Reachable: pub, ReachableFromImplTrait: pub
-  --> $DIR/access_levels.rs:23:9
-   |
-LL |         pub union PubUnion {
-   |         ^^^^^^^^^^^^^^^^^^
-
-error: Public: pub(self), Exported: pub(self), Reachable: pub(self), ReachableFromImplTrait: pub(self)
-  --> $DIR/access_levels.rs:25:13
-   |
-LL |             a: u8,
-   |             ^^^^^
-
-error: Public: pub(crate), Exported: pub, Reachable: pub, ReachableFromImplTrait: pub
-  --> $DIR/access_levels.rs:27:13
-   |
-LL |             pub b: u8,
-   |             ^^^^^^^^^
-
-error: Public: pub(crate), Exported: pub, Reachable: pub, ReachableFromImplTrait: pub
-  --> $DIR/access_levels.rs:31:9
-   |
-LL |         pub enum Enum {
-   |         ^^^^^^^^^^^^^
-
-error: Public: pub(crate), Exported: pub, Reachable: pub, ReachableFromImplTrait: pub
-  --> $DIR/access_levels.rs:33:13
-   |
-LL |             A(
-   |             ^
-
-error: Public: pub(crate), Exported: pub, Reachable: pub, ReachableFromImplTrait: pub
-  --> $DIR/access_levels.rs:35:17
-   |
-LL |                 PubUnion,
-   |                 ^^^^^^^^
-
-error: Public: pub(crate), Exported: pub(crate), Reachable: pub(crate), ReachableFromImplTrait: pub(crate)
-  --> $DIR/access_levels.rs:41:5
-   |
-LL |     macro_rules! none_macro {
-   |     ^^^^^^^^^^^^^^^^^^^^^^^
-
-error: Public: pub, Exported: pub, Reachable: pub, ReachableFromImplTrait: pub
-  --> $DIR/access_levels.rs:47:5
-   |
-LL |     macro_rules! public_macro {
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
-
-error: Public: pub(crate), Exported: pub(crate), Reachable: pub, ReachableFromImplTrait: pub
-  --> $DIR/access_levels.rs:52:5
-   |
-LL |     pub struct ReachableStruct {
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-error: Public: pub(crate), Exported: pub(crate), Reachable: pub, ReachableFromImplTrait: pub
-  --> $DIR/access_levels.rs:54:9
-   |
-LL |         pub a: u8,
-   |         ^^^^^^^^^
-
-error: Public: pub, Exported: pub, Reachable: pub, ReachableFromImplTrait: pub
-  --> $DIR/access_levels.rs:59:9
-   |
-LL | pub use outer::inner1;
-   |         ^^^^^^^^^^^^^
-
-error: Public: pub(crate), Exported: pub, Reachable: pub, ReachableFromImplTrait: pub
-  --> $DIR/access_levels.rs:65:5
-   |
-LL |     pub type HalfPublicImport = u8;
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
-
-error: Public: pub(crate), Exported: pub(crate), Reachable: pub(crate), ReachableFromImplTrait: pub(crate)
-  --> $DIR/access_levels.rs:68:5
-   |
-LL |     pub(crate) const HalfPublicImport: u8 = 0;
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-error: Public: pub, Exported: pub, Reachable: pub, ReachableFromImplTrait: pub
-  --> $DIR/access_levels.rs:72:9
-   |
-LL | pub use half_public_import::HalfPublicImport;
-   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-error: Public: pub, Exported: pub, Reachable: pub, ReachableFromImplTrait: pub
-  --> $DIR/access_levels.rs:72:9
-   |
-LL | pub use half_public_import::HalfPublicImport;
-   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-error: Public: pub(crate), Exported: pub, Reachable: pub, ReachableFromImplTrait: pub
-  --> $DIR/access_levels.rs:14:13
-   |
-LL |             const A: i32;
-   |             ^^^^^^^^^^^^
-
-error: Public: pub(crate), Exported: pub, Reachable: pub, ReachableFromImplTrait: pub
-  --> $DIR/access_levels.rs:16:13
-   |
-LL |             type B;
-   |             ^^^^^^
-
-error: aborting due to 22 previous errors
-
diff --git a/src/test/ui/privacy/effective_visibilities.rs b/src/test/ui/privacy/effective_visibilities.rs
new file mode 100644
index 00000000000..1d806a1d1d1
--- /dev/null
+++ b/src/test/ui/privacy/effective_visibilities.rs
@@ -0,0 +1,75 @@
+#![feature(rustc_attrs)]
+
+#[rustc_effective_visibility]
+mod outer { //~ ERROR Direct: pub(crate), Reexported: pub(crate), Reachable: pub(crate), ReachableThroughImplTrait: pub(crate)
+    #[rustc_effective_visibility]
+    pub mod inner1 { //~ ERROR Direct: pub(crate), Reexported: pub, Reachable: pub, ReachableThroughImplTrait: pub
+
+        #[rustc_effective_visibility]
+        extern "C" {} //~ ERROR Direct: pub(crate), Reexported: pub, Reachable: pub, ReachableThroughImplTrait: pub
+
+        #[rustc_effective_visibility]
+        pub trait PubTrait { //~ ERROR Direct: pub(crate), Reexported: pub, Reachable: pub, ReachableThroughImplTrait: pub
+            #[rustc_effective_visibility]
+            const A: i32; //~ ERROR Direct: pub(crate), Reexported: pub, Reachable: pub, ReachableThroughImplTrait: pub
+            #[rustc_effective_visibility]
+            type B; //~ ERROR Direct: pub(crate), Reexported: pub, Reachable: pub, ReachableThroughImplTrait: pub
+        }
+
+        #[rustc_effective_visibility]
+        struct PrivStruct; //~ ERROR not in the table
+
+        #[rustc_effective_visibility]
+        pub union PubUnion { //~ ERROR Direct: pub(crate), Reexported: pub, Reachable: pub, ReachableThroughImplTrait: pub
+            #[rustc_effective_visibility]
+            a: u8, //~ ERROR not in the table
+            #[rustc_effective_visibility]
+            pub b: u8, //~ ERROR Direct: pub(crate), Reexported: pub, Reachable: pub, ReachableThroughImplTrait: pub
+        }
+
+        #[rustc_effective_visibility]
+        pub enum Enum { //~ ERROR Direct: pub(crate), Reexported: pub, Reachable: pub, ReachableThroughImplTrait: pub
+            #[rustc_effective_visibility]
+            A( //~ ERROR Direct: pub(crate), Reexported: pub, Reachable: pub, ReachableThroughImplTrait: pub
+                #[rustc_effective_visibility]
+                PubUnion,  //~ ERROR Direct: pub(crate), Reexported: pub, Reachable: pub, ReachableThroughImplTrait: pub
+            ),
+        }
+    }
+
+    #[rustc_effective_visibility]
+    macro_rules! none_macro { //~ Direct: pub(crate), Reexported: pub(crate), Reachable: pub(crate), ReachableThroughImplTrait: pub(crate)
+        () => {};
+    }
+
+    #[macro_export]
+    #[rustc_effective_visibility]
+    macro_rules! public_macro { //~ Direct: pub, Reexported: pub, Reachable: pub, ReachableThroughImplTrait: pub
+        () => {};
+    }
+
+    #[rustc_effective_visibility]
+    pub struct ReachableStruct { //~ ERROR Direct: pub(crate), Reexported: pub(crate), Reachable: pub, ReachableThroughImplTrait: pub
+        #[rustc_effective_visibility]
+        pub a: u8, //~ ERROR Direct: pub(crate), Reexported: pub(crate), Reachable: pub, ReachableThroughImplTrait: pub
+    }
+}
+
+#[rustc_effective_visibility]
+pub use outer::inner1; //~ ERROR Direct: pub, Reexported: pub, Reachable: pub, ReachableThroughImplTrait: pub
+
+pub fn foo() -> outer::ReachableStruct { outer::ReachableStruct {a: 0} }
+
+mod half_public_import {
+    #[rustc_effective_visibility]
+    pub type HalfPublicImport = u8; //~ ERROR Direct: pub(crate), Reexported: pub, Reachable: pub, ReachableThroughImplTrait: pub
+    #[rustc_effective_visibility]
+    #[allow(non_upper_case_globals)]
+    pub(crate) const HalfPublicImport: u8 = 0; //~ ERROR Direct: pub(crate), Reexported: pub(crate), Reachable: pub(crate), ReachableThroughImplTrait: pub(crate)
+}
+
+#[rustc_effective_visibility]
+pub use half_public_import::HalfPublicImport; //~ ERROR Direct: pub, Reexported: pub, Reachable: pub, ReachableThroughImplTrait: pub
+                                              //~^ ERROR Direct: pub, Reexported: pub, Reachable: pub, ReachableThroughImplTrait: pub
+
+fn main() {}
diff --git a/src/test/ui/privacy/effective_visibilities.stderr b/src/test/ui/privacy/effective_visibilities.stderr
new file mode 100644
index 00000000000..1c6201600b6
--- /dev/null
+++ b/src/test/ui/privacy/effective_visibilities.stderr
@@ -0,0 +1,134 @@
+error: Direct: pub(crate), Reexported: pub(crate), Reachable: pub(crate), ReachableThroughImplTrait: pub(crate)
+  --> $DIR/effective_visibilities.rs:4:1
+   |
+LL | mod outer {
+   | ^^^^^^^^^
+
+error: Direct: pub(crate), Reexported: pub, Reachable: pub, ReachableThroughImplTrait: pub
+  --> $DIR/effective_visibilities.rs:6:5
+   |
+LL |     pub mod inner1 {
+   |     ^^^^^^^^^^^^^^
+
+error: Direct: pub(crate), Reexported: pub, Reachable: pub, ReachableThroughImplTrait: pub
+  --> $DIR/effective_visibilities.rs:9:9
+   |
+LL |         extern "C" {}
+   |         ^^^^^^^^^^^^^
+
+error: Direct: pub(crate), Reexported: pub, Reachable: pub, ReachableThroughImplTrait: pub
+  --> $DIR/effective_visibilities.rs:12:9
+   |
+LL |         pub trait PubTrait {
+   |         ^^^^^^^^^^^^^^^^^^
+
+error: not in the table
+  --> $DIR/effective_visibilities.rs:20:9
+   |
+LL |         struct PrivStruct;
+   |         ^^^^^^^^^^^^^^^^^
+
+error: Direct: pub(crate), Reexported: pub, Reachable: pub, ReachableThroughImplTrait: pub
+  --> $DIR/effective_visibilities.rs:23:9
+   |
+LL |         pub union PubUnion {
+   |         ^^^^^^^^^^^^^^^^^^
+
+error: not in the table
+  --> $DIR/effective_visibilities.rs:25:13
+   |
+LL |             a: u8,
+   |             ^^^^^
+
+error: Direct: pub(crate), Reexported: pub, Reachable: pub, ReachableThroughImplTrait: pub
+  --> $DIR/effective_visibilities.rs:27:13
+   |
+LL |             pub b: u8,
+   |             ^^^^^^^^^
+
+error: Direct: pub(crate), Reexported: pub, Reachable: pub, ReachableThroughImplTrait: pub
+  --> $DIR/effective_visibilities.rs:31:9
+   |
+LL |         pub enum Enum {
+   |         ^^^^^^^^^^^^^
+
+error: Direct: pub(crate), Reexported: pub, Reachable: pub, ReachableThroughImplTrait: pub
+  --> $DIR/effective_visibilities.rs:33:13
+   |
+LL |             A(
+   |             ^
+
+error: Direct: pub(crate), Reexported: pub, Reachable: pub, ReachableThroughImplTrait: pub
+  --> $DIR/effective_visibilities.rs:35:17
+   |
+LL |                 PubUnion,
+   |                 ^^^^^^^^
+
+error: Direct: pub(crate), Reexported: pub(crate), Reachable: pub(crate), ReachableThroughImplTrait: pub(crate)
+  --> $DIR/effective_visibilities.rs:41:5
+   |
+LL |     macro_rules! none_macro {
+   |     ^^^^^^^^^^^^^^^^^^^^^^^
+
+error: Direct: pub, Reexported: pub, Reachable: pub, ReachableThroughImplTrait: pub
+  --> $DIR/effective_visibilities.rs:47:5
+   |
+LL |     macro_rules! public_macro {
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: Direct: pub(crate), Reexported: pub(crate), Reachable: pub, ReachableThroughImplTrait: pub
+  --> $DIR/effective_visibilities.rs:52:5
+   |
+LL |     pub struct ReachableStruct {
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: Direct: pub(crate), Reexported: pub(crate), Reachable: pub, ReachableThroughImplTrait: pub
+  --> $DIR/effective_visibilities.rs:54:9
+   |
+LL |         pub a: u8,
+   |         ^^^^^^^^^
+
+error: Direct: pub, Reexported: pub, Reachable: pub, ReachableThroughImplTrait: pub
+  --> $DIR/effective_visibilities.rs:59:9
+   |
+LL | pub use outer::inner1;
+   |         ^^^^^^^^^^^^^
+
+error: Direct: pub(crate), Reexported: pub, Reachable: pub, ReachableThroughImplTrait: pub
+  --> $DIR/effective_visibilities.rs:65:5
+   |
+LL |     pub type HalfPublicImport = u8;
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: Direct: pub(crate), Reexported: pub(crate), Reachable: pub(crate), ReachableThroughImplTrait: pub(crate)
+  --> $DIR/effective_visibilities.rs:68:5
+   |
+LL |     pub(crate) const HalfPublicImport: u8 = 0;
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: Direct: pub, Reexported: pub, Reachable: pub, ReachableThroughImplTrait: pub
+  --> $DIR/effective_visibilities.rs:72:9
+   |
+LL | pub use half_public_import::HalfPublicImport;
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: Direct: pub, Reexported: pub, Reachable: pub, ReachableThroughImplTrait: pub
+  --> $DIR/effective_visibilities.rs:72:9
+   |
+LL | pub use half_public_import::HalfPublicImport;
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: Direct: pub(crate), Reexported: pub, Reachable: pub, ReachableThroughImplTrait: pub
+  --> $DIR/effective_visibilities.rs:14:13
+   |
+LL |             const A: i32;
+   |             ^^^^^^^^^^^^
+
+error: Direct: pub(crate), Reexported: pub, Reachable: pub, ReachableThroughImplTrait: pub
+  --> $DIR/effective_visibilities.rs:16:13
+   |
+LL |             type B;
+   |             ^^^^^^
+
+error: aborting due to 22 previous errors
+
diff --git a/src/test/ui/resolve/issue-23305.rs b/src/test/ui/resolve/issue-23305.rs
index 95635e12a63..6d7fe7c50a2 100644
--- a/src/test/ui/resolve/issue-23305.rs
+++ b/src/test/ui/resolve/issue-23305.rs
@@ -3,6 +3,6 @@ pub trait ToNbt<T> {
 }
 
 impl dyn ToNbt<Self> {}
-//~^ ERROR cycle detected
+//~^ ERROR `Self` is not valid in the self type of an impl block
 
 fn main() {}
diff --git a/src/test/ui/resolve/issue-23305.stderr b/src/test/ui/resolve/issue-23305.stderr
index 20aeb7b995a..aad1b583a32 100644
--- a/src/test/ui/resolve/issue-23305.stderr
+++ b/src/test/ui/resolve/issue-23305.stderr
@@ -1,22 +1,10 @@
-error[E0391]: cycle detected when computing type of `<impl at $DIR/issue-23305.rs:5:1: 5:21>`
+error: `Self` is not valid in the self type of an impl block
   --> $DIR/issue-23305.rs:5:16
    |
 LL | impl dyn ToNbt<Self> {}
    |                ^^^^
    |
-   = note: ...which immediately requires computing type of `<impl at $DIR/issue-23305.rs:5:1: 5:21>` again
-note: cycle used when collecting item types in top-level module
-  --> $DIR/issue-23305.rs:1:1
-   |
-LL | / pub trait ToNbt<T> {
-LL | |     fn new(val: T) -> Self;
-LL | | }
-LL | |
-...  |
-LL | |
-LL | | fn main() {}
-   | |____________^
+   = note: replace `Self` with a different type
 
 error: aborting due to previous error
 
-For more information about this error, try `rustc --explain E0391`.
diff --git a/src/test/ui/resolve/resolve-self-in-impl.rs b/src/test/ui/resolve/resolve-self-in-impl.rs
index 024fdc51ea3..d0872d1b76f 100644
--- a/src/test/ui/resolve/resolve-self-in-impl.rs
+++ b/src/test/ui/resolve/resolve-self-in-impl.rs
@@ -11,10 +11,11 @@ impl Tr for S where Self: Copy {} // OK
 impl Tr for S where S<Self>: Copy {} // OK
 impl Tr for S where Self::A: Copy {} // OK
 
-impl Tr for Self {} //~ ERROR cycle detected
-impl Tr for S<Self> {} //~ ERROR cycle detected
-impl Self {} //~ ERROR cycle detected
-impl S<Self> {} //~ ERROR cycle detected
+impl Tr for Self {} //~ ERROR `Self` is not valid in the self type of an impl block
+impl Tr for S<Self> {} //~ ERROR `Self` is not valid in the self type of an impl block
+impl Self {} //~ ERROR `Self` is not valid in the self type of an impl block
+impl S<Self> {} //~ ERROR `Self` is not valid in the self type of an impl block
+impl (Self, Self) {} //~ ERROR `Self` is not valid in the self type of an impl block
 impl Tr<Self::A> for S {} //~ ERROR cycle detected
 
 fn main() {}
diff --git a/src/test/ui/resolve/resolve-self-in-impl.stderr b/src/test/ui/resolve/resolve-self-in-impl.stderr
index aa99c1a3335..9f9ed68898f 100644
--- a/src/test/ui/resolve/resolve-self-in-impl.stderr
+++ b/src/test/ui/resolve/resolve-self-in-impl.stderr
@@ -1,86 +1,50 @@
-error[E0391]: cycle detected when computing type of `<impl at $DIR/resolve-self-in-impl.rs:14:1: 14:17>`
+error: `Self` is not valid in the self type of an impl block
   --> $DIR/resolve-self-in-impl.rs:14:13
    |
 LL | impl Tr for Self {}
    |             ^^^^
    |
-   = note: ...which immediately requires computing type of `<impl at $DIR/resolve-self-in-impl.rs:14:1: 14:17>` again
-note: cycle used when collecting item types in top-level module
-  --> $DIR/resolve-self-in-impl.rs:1:1
-   |
-LL | / #![feature(associated_type_defaults)]
-LL | |
-LL | | struct S<T = u8>(T);
-LL | | trait Tr<T = u8> {
-...  |
-LL | |
-LL | | fn main() {}
-   | |____________^
+   = note: replace `Self` with a different type
 
-error[E0391]: cycle detected when computing type of `<impl at $DIR/resolve-self-in-impl.rs:15:1: 15:20>`
+error: `Self` is not valid in the self type of an impl block
   --> $DIR/resolve-self-in-impl.rs:15:15
    |
 LL | impl Tr for S<Self> {}
    |               ^^^^
    |
-   = note: ...which immediately requires computing type of `<impl at $DIR/resolve-self-in-impl.rs:15:1: 15:20>` again
-note: cycle used when collecting item types in top-level module
-  --> $DIR/resolve-self-in-impl.rs:1:1
-   |
-LL | / #![feature(associated_type_defaults)]
-LL | |
-LL | | struct S<T = u8>(T);
-LL | | trait Tr<T = u8> {
-...  |
-LL | |
-LL | | fn main() {}
-   | |____________^
+   = note: replace `Self` with a different type
 
-error[E0391]: cycle detected when computing type of `<impl at $DIR/resolve-self-in-impl.rs:16:1: 16:10>`
+error: `Self` is not valid in the self type of an impl block
   --> $DIR/resolve-self-in-impl.rs:16:6
    |
 LL | impl Self {}
    |      ^^^^
    |
-   = note: ...which immediately requires computing type of `<impl at $DIR/resolve-self-in-impl.rs:16:1: 16:10>` again
-note: cycle used when collecting item types in top-level module
-  --> $DIR/resolve-self-in-impl.rs:1:1
-   |
-LL | / #![feature(associated_type_defaults)]
-LL | |
-LL | | struct S<T = u8>(T);
-LL | | trait Tr<T = u8> {
-...  |
-LL | |
-LL | | fn main() {}
-   | |____________^
+   = note: replace `Self` with a different type
 
-error[E0391]: cycle detected when computing type of `<impl at $DIR/resolve-self-in-impl.rs:17:1: 17:13>`
+error: `Self` is not valid in the self type of an impl block
   --> $DIR/resolve-self-in-impl.rs:17:8
    |
 LL | impl S<Self> {}
    |        ^^^^
    |
-   = note: ...which immediately requires computing type of `<impl at $DIR/resolve-self-in-impl.rs:17:1: 17:13>` again
-note: cycle used when collecting item types in top-level module
-  --> $DIR/resolve-self-in-impl.rs:1:1
+   = note: replace `Self` with a different type
+
+error: `Self` is not valid in the self type of an impl block
+  --> $DIR/resolve-self-in-impl.rs:18:7
    |
-LL | / #![feature(associated_type_defaults)]
-LL | |
-LL | | struct S<T = u8>(T);
-LL | | trait Tr<T = u8> {
-...  |
-LL | |
-LL | | fn main() {}
-   | |____________^
+LL | impl (Self, Self) {}
+   |       ^^^^  ^^^^
+   |
+   = note: replace `Self` with a different type
 
-error[E0391]: cycle detected when computing trait implemented by `<impl at $DIR/resolve-self-in-impl.rs:18:1: 18:23>`
-  --> $DIR/resolve-self-in-impl.rs:18:1
+error[E0391]: cycle detected when computing trait implemented by `<impl at $DIR/resolve-self-in-impl.rs:19:1: 19:23>`
+  --> $DIR/resolve-self-in-impl.rs:19:1
    |
 LL | impl Tr<Self::A> for S {}
    | ^^^^^^^^^^^^^^^^^^^^^^
    |
-   = note: ...which immediately requires computing trait implemented by `<impl at $DIR/resolve-self-in-impl.rs:18:1: 18:23>` again
+   = note: ...which immediately requires computing trait implemented by `<impl at $DIR/resolve-self-in-impl.rs:19:1: 19:23>` again
 note: cycle used when collecting item types in top-level module
   --> $DIR/resolve-self-in-impl.rs:1:1
    |
@@ -93,6 +57,6 @@ LL | |
 LL | | fn main() {}
    | |____________^
 
-error: aborting due to 5 previous errors
+error: aborting due to 6 previous errors
 
 For more information about this error, try `rustc --explain E0391`.
diff --git a/src/test/ui/rfc-2632-const-trait-impl/issue-102985.rs b/src/test/ui/rfc-2632-const-trait-impl/issue-102985.rs
index e0df7200384..07d3f51edce 100644
--- a/src/test/ui/rfc-2632-const-trait-impl/issue-102985.rs
+++ b/src/test/ui/rfc-2632-const-trait-impl/issue-102985.rs
@@ -4,7 +4,8 @@ struct Bug {
     inner: [(); match || 1 {
         n => n(),
         //~^ ERROR the trait bound
-        //~| ERROR cannot call non-const fn `Bug::inner::{constant#0}::{closure#0}` in constants
+        //~| ERROR the trait bound
+        //~| ERROR cannot call non-const closure in constants
     }],
 }
 
diff --git a/src/test/ui/rfc-2632-const-trait-impl/issue-102985.stderr b/src/test/ui/rfc-2632-const-trait-impl/issue-102985.stderr
index 14d87e7cdc6..b98ccbe5d03 100644
--- a/src/test/ui/rfc-2632-const-trait-impl/issue-102985.stderr
+++ b/src/test/ui/rfc-2632-const-trait-impl/issue-102985.stderr
@@ -12,15 +12,30 @@ LL |         n => n(),
    |              ^^^
    = note: wrap the `[closure@$DIR/issue-102985.rs:4:23: 4:25]` in a closure with no arguments: `|| { /* code */ }`
 
-error[E0015]: cannot call non-const fn `Bug::inner::{constant#0}::{closure#0}` in constants
+error[E0277]: the trait bound `[closure@$DIR/issue-102985.rs:4:23: 4:25]: ~const Fn<()>` is not satisfied
+  --> $DIR/issue-102985.rs:5:14
+   |
+LL |         n => n(),
+   |              ^^^ expected an `Fn<()>` closure, found `[closure@$DIR/issue-102985.rs:4:23: 4:25]`
+   |
+   = help: the trait `~const Fn<()>` is not implemented for closure `[closure@$DIR/issue-102985.rs:4:23: 4:25]`
+note: the trait `Fn<()>` is implemented for `[closure@$DIR/issue-102985.rs:4:23: 4:25]`, but that implementation is not `const`
+  --> $DIR/issue-102985.rs:5:14
+   |
+LL |         n => n(),
+   |              ^^^
+   = note: wrap the `[closure@$DIR/issue-102985.rs:4:23: 4:25]` in a closure with no arguments: `|| { /* code */ }`
+
+error[E0015]: cannot call non-const closure in constants
   --> $DIR/issue-102985.rs:5:14
    |
 LL |         n => n(),
    |              ^^^
    |
+   = note: closures need an RFC before allowed to be called in constants
    = note: calls in constants are limited to constant functions, tuple structs and tuple variants
 
-error: aborting due to 2 previous errors
+error: aborting due to 3 previous errors
 
 Some errors have detailed explanations: E0015, E0277.
 For more information about an error, try `rustc --explain E0015`.
diff --git a/src/test/ui/rfc-2632-const-trait-impl/issue-103677.rs b/src/test/ui/rfc-2632-const-trait-impl/issue-103677.rs
new file mode 100644
index 00000000000..d81724a3685
--- /dev/null
+++ b/src/test/ui/rfc-2632-const-trait-impl/issue-103677.rs
@@ -0,0 +1,5 @@
+// check-pass
+
+const _: fn(&String) = |s| { &*s as &str; };
+
+fn main() {}
diff --git a/src/test/ui/rfc-2632-const-trait-impl/super-traits-fail-2.nn.stderr b/src/test/ui/rfc-2632-const-trait-impl/super-traits-fail-2.nn.stderr
index b86acb2cc9a..d4f42b787e4 100644
--- a/src/test/ui/rfc-2632-const-trait-impl/super-traits-fail-2.nn.stderr
+++ b/src/test/ui/rfc-2632-const-trait-impl/super-traits-fail-2.nn.stderr
@@ -1,8 +1,8 @@
 error: ~const can only be applied to `#[const_trait]` traits
-  --> $DIR/super-traits-fail-2.rs:11:12
+  --> $DIR/super-traits-fail-2.rs:11:19
    |
 LL | trait Bar: ~const Foo {}
-   |            ^^^^^^^^^^
+   |                   ^^^
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/rfc-2632-const-trait-impl/super-traits-fail-2.ny.stderr b/src/test/ui/rfc-2632-const-trait-impl/super-traits-fail-2.ny.stderr
index b86acb2cc9a..d4f42b787e4 100644
--- a/src/test/ui/rfc-2632-const-trait-impl/super-traits-fail-2.ny.stderr
+++ b/src/test/ui/rfc-2632-const-trait-impl/super-traits-fail-2.ny.stderr
@@ -1,8 +1,8 @@
 error: ~const can only be applied to `#[const_trait]` traits
-  --> $DIR/super-traits-fail-2.rs:11:12
+  --> $DIR/super-traits-fail-2.rs:11:19
    |
 LL | trait Bar: ~const Foo {}
-   |            ^^^^^^^^^^
+   |                   ^^^
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/rfc-2632-const-trait-impl/super-traits-fail-3.nn.stderr b/src/test/ui/rfc-2632-const-trait-impl/super-traits-fail-3.nn.stderr
index 191edca1761..d433e1cfa69 100644
--- a/src/test/ui/rfc-2632-const-trait-impl/super-traits-fail-3.nn.stderr
+++ b/src/test/ui/rfc-2632-const-trait-impl/super-traits-fail-3.nn.stderr
@@ -1,14 +1,14 @@
 error: ~const can only be applied to `#[const_trait]` traits
-  --> $DIR/super-traits-fail-3.rs:12:12
+  --> $DIR/super-traits-fail-3.rs:12:19
    |
 LL | trait Bar: ~const Foo {}
-   |            ^^^^^^^^^^
+   |                   ^^^
 
 error: ~const can only be applied to `#[const_trait]` traits
-  --> $DIR/super-traits-fail-3.rs:15:17
+  --> $DIR/super-traits-fail-3.rs:15:24
    |
 LL | const fn foo<T: ~const Bar>(x: &T) {
-   |                 ^^^^^^^^^^
+   |                        ^^^
 
 error: aborting due to 2 previous errors
 
diff --git a/src/test/ui/rfc-2632-const-trait-impl/super-traits-fail-3.ny.stderr b/src/test/ui/rfc-2632-const-trait-impl/super-traits-fail-3.ny.stderr
index a3b4c302a57..2a7e8e00bc7 100644
--- a/src/test/ui/rfc-2632-const-trait-impl/super-traits-fail-3.ny.stderr
+++ b/src/test/ui/rfc-2632-const-trait-impl/super-traits-fail-3.ny.stderr
@@ -1,8 +1,8 @@
 error: ~const can only be applied to `#[const_trait]` traits
-  --> $DIR/super-traits-fail-3.rs:12:12
+  --> $DIR/super-traits-fail-3.rs:12:19
    |
 LL | trait Bar: ~const Foo {}
-   |            ^^^^^^^^^^
+   |                   ^^^
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/rfc-2632-const-trait-impl/super-traits-fail-3.yn.stderr b/src/test/ui/rfc-2632-const-trait-impl/super-traits-fail-3.yn.stderr
index 9d611665465..e5978c12a09 100644
--- a/src/test/ui/rfc-2632-const-trait-impl/super-traits-fail-3.yn.stderr
+++ b/src/test/ui/rfc-2632-const-trait-impl/super-traits-fail-3.yn.stderr
@@ -1,8 +1,8 @@
 error: ~const can only be applied to `#[const_trait]` traits
-  --> $DIR/super-traits-fail-3.rs:15:17
+  --> $DIR/super-traits-fail-3.rs:15:24
    |
 LL | const fn foo<T: ~const Bar>(x: &T) {
-   |                 ^^^^^^^^^^
+   |                        ^^^
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/save-analysis/issue-68621.stderr b/src/test/ui/save-analysis/issue-68621.stderr
index 4a4bf9a6996..4452ee7915b 100644
--- a/src/test/ui/save-analysis/issue-68621.stderr
+++ b/src/test/ui/save-analysis/issue-68621.stderr
@@ -4,7 +4,7 @@ error: unconstrained opaque type
 LL |     type Future = impl Trait;
    |                   ^^^^^^^^^^
    |
-   = note: `Future` must be used in combination with a concrete type within the same module
+   = note: `Future` must be used in combination with a concrete type within the same impl
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/self/arbitrary_self_types_pin_lifetime_impl_trait-async.stderr b/src/test/ui/self/arbitrary_self_types_pin_lifetime_impl_trait-async.stderr
index 7e7d60d0ff9..eb3d3e4a67a 100644
--- a/src/test/ui/self/arbitrary_self_types_pin_lifetime_impl_trait-async.stderr
+++ b/src/test/ui/self/arbitrary_self_types_pin_lifetime_impl_trait-async.stderr
@@ -6,7 +6,7 @@ LL |     async fn f(self: Pin<&Self>) -> impl Clone { self }
    |                          |
    |                          hidden type `Pin<&Foo>` captures the anonymous lifetime defined here
    |
-help: to declare that the `impl Trait` captures `'_`, you can add an explicit `'_` lifetime bound
+help: to declare that `impl Clone` captures `'_`, you can add an explicit `'_` lifetime bound
    |
 LL |     async fn f(self: Pin<&Self>) -> impl Clone + '_ { self }
    |                                                ++++
diff --git a/src/test/ui/self/arbitrary_self_types_pin_lifetime_impl_trait.stderr b/src/test/ui/self/arbitrary_self_types_pin_lifetime_impl_trait.stderr
index 30d2250c0c8..2c0b2a0d919 100644
--- a/src/test/ui/self/arbitrary_self_types_pin_lifetime_impl_trait.stderr
+++ b/src/test/ui/self/arbitrary_self_types_pin_lifetime_impl_trait.stderr
@@ -6,7 +6,7 @@ LL |     fn f(self: Pin<&Self>) -> impl Clone { self }
    |                    |
    |                    hidden type `Pin<&Foo>` captures the anonymous lifetime defined here
    |
-help: to declare that the `impl Trait` captures `'_`, you can add an explicit `'_` lifetime bound
+help: to declare that `impl Clone` captures `'_`, you can add an explicit `'_` lifetime bound
    |
 LL |     fn f(self: Pin<&Self>) -> impl Clone + '_ { self }
    |                                          ++++
diff --git a/src/test/ui/suggestions/format-borrow.stderr b/src/test/ui/suggestions/format-borrow.stderr
index fac6a5a5f48..8ed2b9c9a63 100644
--- a/src/test/ui/suggestions/format-borrow.stderr
+++ b/src/test/ui/suggestions/format-borrow.stderr
@@ -11,6 +11,10 @@ help: consider removing the borrow
 LL -     let a: String = &String::from("a");
 LL +     let a: String = String::from("a");
    |
+help: alternatively, consider changing the type annotation
+   |
+LL |     let a: &String = &String::from("a");
+   |            +
 
 error[E0308]: mismatched types
   --> $DIR/format-borrow.rs:4:21
@@ -25,6 +29,10 @@ help: consider removing the borrow
 LL -     let b: String = &format!("b");
 LL +     let b: String = format!("b");
    |
+help: alternatively, consider changing the type annotation
+   |
+LL |     let b: &String = &format!("b");
+   |            +
 
 error[E0308]: mismatched types
   --> $DIR/format-borrow.rs:6:21
@@ -39,6 +47,10 @@ help: consider removing the borrow
 LL -     let c: String = &mut format!("c");
 LL +     let c: String = format!("c");
    |
+help: alternatively, consider changing the type annotation
+   |
+LL |     let c: &mut String = &mut format!("c");
+   |            ++++
 
 error[E0308]: mismatched types
   --> $DIR/format-borrow.rs:8:21
@@ -53,6 +65,10 @@ help: consider removing the borrow
 LL -     let d: String = &mut (format!("d"));
 LL +     let d: String = format!("d"));
    |
+help: alternatively, consider changing the type annotation
+   |
+LL |     let d: &mut String = &mut (format!("d"));
+   |            ++++
 
 error: aborting due to 4 previous errors
 
diff --git a/src/test/ui/suggestions/issue-102354.rs b/src/test/ui/suggestions/issue-102354.rs
new file mode 100644
index 00000000000..f881feb0060
--- /dev/null
+++ b/src/test/ui/suggestions/issue-102354.rs
@@ -0,0 +1,10 @@
+trait Trait {
+    fn func() {}
+}
+
+impl Trait for i32 {}
+
+fn main() {
+    let x: i32 = 123;
+    x.func(); //~ERROR no method
+}
diff --git a/src/test/ui/suggestions/issue-102354.stderr b/src/test/ui/suggestions/issue-102354.stderr
new file mode 100644
index 00000000000..4f76c5f2e75
--- /dev/null
+++ b/src/test/ui/suggestions/issue-102354.stderr
@@ -0,0 +1,24 @@
+error[E0599]: no method named `func` found for type `i32` in the current scope
+  --> $DIR/issue-102354.rs:9:7
+   |
+LL |     x.func();
+   |       ^^^^ this is an associated function, not a method
+   |
+   = note: found the following associated functions; to be used as methods, functions must have a `self` parameter
+note: the candidate is defined in the trait `Trait`
+  --> $DIR/issue-102354.rs:2:5
+   |
+LL |     fn func() {}
+   |     ^^^^^^^^^
+help: use associated function syntax instead
+   |
+LL |     i32::func();
+   |     ~~~~~~~~~
+help: disambiguate the associated function for the candidate
+   |
+LL |     <i32 as Trait>::func(x);
+   |     ~~~~~~~~~~~~~~~~~~~~~~~
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0599`.
diff --git a/src/test/ui/suggestions/issue-102892.rs b/src/test/ui/suggestions/issue-102892.rs
new file mode 100644
index 00000000000..c1a791d8d85
--- /dev/null
+++ b/src/test/ui/suggestions/issue-102892.rs
@@ -0,0 +1,25 @@
+#![allow(dead_code, unused_variables)]
+
+use std::sync::Arc;
+
+#[derive(Debug)]
+struct A;
+#[derive(Debug)]
+struct B;
+
+fn process_without_annot(arc: &Arc<(A, B)>) {
+    let (a, b) = **arc; // suggests putting `&**arc` here; with that, fixed!
+}
+
+fn process_with_annot(arc: &Arc<(A, B)>) {
+    let (a, b): (A, B) = &**arc; // suggests putting `&**arc` here too
+    //~^ ERROR mismatched types
+}
+
+fn process_with_tuple_annot(mutation: &mut (A, B), arc: &Arc<(A, B)>) {
+    let (a, b): ((A, B), A) = (&mut *mutation, &(**arc).0); // suggests putting `&**arc` here too
+    //~^ ERROR mismatched types
+    //~| ERROR mismatched types
+}
+
+fn main() {}
diff --git a/src/test/ui/suggestions/issue-102892.stderr b/src/test/ui/suggestions/issue-102892.stderr
new file mode 100644
index 00000000000..a3dbc7cb861
--- /dev/null
+++ b/src/test/ui/suggestions/issue-102892.stderr
@@ -0,0 +1,57 @@
+error[E0308]: mismatched types
+  --> $DIR/issue-102892.rs:15:26
+   |
+LL |     let (a, b): (A, B) = &**arc; // suggests putting `&**arc` here too
+   |                 ------   ^^^^^^ expected tuple, found `&(A, B)`
+   |                 |
+   |                 expected due to this
+   |
+   = note:  expected tuple `(A, B)`
+           found reference `&(A, B)`
+help: consider removing the borrow
+   |
+LL -     let (a, b): (A, B) = &**arc; // suggests putting `&**arc` here too
+LL +     let (a, b): (A, B) = **arc; // suggests putting `&**arc` here too
+   |
+help: alternatively, consider changing the type annotation
+   |
+LL |     let (a, b): &(A, B) = &**arc; // suggests putting `&**arc` here too
+   |                 +
+
+error[E0308]: mismatched types
+  --> $DIR/issue-102892.rs:20:32
+   |
+LL |     let (a, b): ((A, B), A) = (&mut *mutation, &(**arc).0); // suggests putting `&**arc` here too
+   |                                ^^^^^^^^^^^^^^ expected tuple, found `&mut (A, B)`
+   |
+   = note:          expected tuple `(A, B)`
+           found mutable reference `&mut (A, B)`
+help: consider removing the borrow
+   |
+LL -     let (a, b): ((A, B), A) = (&mut *mutation, &(**arc).0); // suggests putting `&**arc` here too
+LL +     let (a, b): ((A, B), A) = (*mutation, &(**arc).0); // suggests putting `&**arc` here too
+   |
+help: alternatively, consider changing the type annotation
+   |
+LL |     let (a, b): (&mut (A, B), A) = (&mut *mutation, &(**arc).0); // suggests putting `&**arc` here too
+   |                  ++++
+
+error[E0308]: mismatched types
+  --> $DIR/issue-102892.rs:20:48
+   |
+LL |     let (a, b): ((A, B), A) = (&mut *mutation, &(**arc).0); // suggests putting `&**arc` here too
+   |                                                ^^^^^^^^^^ expected struct `A`, found `&A`
+   |
+help: consider removing the borrow
+   |
+LL -     let (a, b): ((A, B), A) = (&mut *mutation, &(**arc).0); // suggests putting `&**arc` here too
+LL +     let (a, b): ((A, B), A) = (&mut *mutation, (**arc).0); // suggests putting `&**arc` here too
+   |
+help: alternatively, consider changing the type annotation
+   |
+LL |     let (a, b): ((A, B), &A) = (&mut *mutation, &(**arc).0); // suggests putting `&**arc` here too
+   |                          +
+
+error: aborting due to 3 previous errors
+
+For more information about this error, try `rustc --explain E0308`.
diff --git a/src/test/ui/suggestions/lifetimes/missing-lifetimes-in-signature.stderr b/src/test/ui/suggestions/lifetimes/missing-lifetimes-in-signature.stderr
index 171f4b333db..fa758bf05df 100644
--- a/src/test/ui/suggestions/lifetimes/missing-lifetimes-in-signature.stderr
+++ b/src/test/ui/suggestions/lifetimes/missing-lifetimes-in-signature.stderr
@@ -18,7 +18,7 @@ LL | |         *dest = g.get();
 LL | |     }
    | |_____^
    |
-help: to declare that the `impl Trait` captures `'_`, you can add an explicit `'_` lifetime bound
+help: to declare that `impl FnOnce()` captures `'_`, you can add an explicit `'_` lifetime bound
    |
 LL | fn foo<G, T>(g: G, dest: &mut T) -> impl FnOnce() + '_
    |                                                   ++++
diff --git a/src/test/ui/suggestions/lifetimes/trait-object-nested-in-impl-trait.stderr b/src/test/ui/suggestions/lifetimes/trait-object-nested-in-impl-trait.stderr
index f49876bcd3f..c77ef79e7ed 100644
--- a/src/test/ui/suggestions/lifetimes/trait-object-nested-in-impl-trait.stderr
+++ b/src/test/ui/suggestions/lifetimes/trait-object-nested-in-impl-trait.stderr
@@ -10,7 +10,7 @@ LL | |             remaining: self.0.iter(),
 LL | |         }
    | |_________^ returning this value requires that `'1` must outlive `'static`
    |
-help: to declare that the `impl Trait` captures data from argument `self`, you can add an explicit `'_` lifetime bound
+help: to declare that `impl Iterator<Item = Box<(dyn Foo + 'static)>>` captures data from argument `self`, you can add an explicit `'_` lifetime bound
    |
 LL |     fn iter(&self) -> impl Iterator<Item = Box<dyn Foo>> + '_ {
    |                                                          ++++
@@ -65,7 +65,7 @@ LL | |             remaining: self.0.iter(),
 LL | |         }
    | |_________^ returning this value requires that `'a` must outlive `'static`
    |
-help: to declare that the `impl Trait` captures data from argument `self`, you can add an explicit `'a` lifetime bound
+help: to declare that `impl Iterator<Item = Box<(dyn Foo + 'static)>>` captures data from argument `self`, you can add an explicit `'a` lifetime bound
    |
 LL |     fn iter<'a>(&'a self) -> impl Iterator<Item = Box<dyn Foo>> + 'a {
    |                                                                 ++++
diff --git a/src/test/ui/traits/safety-trait-impl-cc.stderr b/src/test/ui/traits/safety-trait-impl-cc.stderr
index 5a0f8d3b8ca..0b1fb30478f 100644
--- a/src/test/ui/traits/safety-trait-impl-cc.stderr
+++ b/src/test/ui/traits/safety-trait-impl-cc.stderr
@@ -7,6 +7,12 @@ LL | |         panic!();
 LL | |     }
 LL | | }
    | |_^
+   |
+   = note: the trait `Foo` enforces invariants that the compiler can't check. Review the trait documentation and make sure this implementation upholds those invariants before adding the `unsafe` keyword
+help: add `unsafe` to this trait implementation
+   |
+LL | unsafe impl lib::Foo for Bar {
+   | ++++++
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/traits/safety-trait-impl.stderr b/src/test/ui/traits/safety-trait-impl.stderr
index fc0f6c69308..721e2b48b95 100644
--- a/src/test/ui/traits/safety-trait-impl.stderr
+++ b/src/test/ui/traits/safety-trait-impl.stderr
@@ -3,12 +3,24 @@ error[E0200]: the trait `UnsafeTrait` requires an `unsafe impl` declaration
    |
 LL | impl UnsafeTrait for u16 { }
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: the trait `UnsafeTrait` enforces invariants that the compiler can't check. Review the trait documentation and make sure this implementation upholds those invariants before adding the `unsafe` keyword
+help: add `unsafe` to this trait implementation
+   |
+LL | unsafe impl UnsafeTrait for u16 { }
+   | ++++++
 
 error[E0199]: implementing the trait `SafeTrait` is not unsafe
   --> $DIR/safety-trait-impl.rs:16:1
    |
 LL | unsafe impl SafeTrait for u32 { }
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+help: remove `unsafe` from this trait implementation
+   |
+LL - unsafe impl SafeTrait for u32 { }
+LL + impl SafeTrait for u32 { }
+   |
 
 error: aborting due to 2 previous errors
 
diff --git a/src/test/ui/transmutability/enums/should_order_correctly.rs b/src/test/ui/transmutability/enums/should_order_correctly.rs
index b753cf0e62d..1335cc9d2b1 100644
--- a/src/test/ui/transmutability/enums/should_order_correctly.rs
+++ b/src/test/ui/transmutability/enums/should_order_correctly.rs
@@ -2,7 +2,6 @@
 //! The payloads of an enum variant should be ordered after its tag.
 
 #![crate_type = "lib"]
-#![feature(arbitrary_enum_discriminant)]
 #![feature(transmutability)]
 #![allow(dead_code)]
 
diff --git a/src/test/ui/transmutability/enums/should_respect_endianness.rs b/src/test/ui/transmutability/enums/should_respect_endianness.rs
index 19ff6900500..f3567b405f4 100644
--- a/src/test/ui/transmutability/enums/should_respect_endianness.rs
+++ b/src/test/ui/transmutability/enums/should_respect_endianness.rs
@@ -2,7 +2,6 @@
 //! an enum with a multi-byte tag.
 
 #![crate_type = "lib"]
-#![feature(arbitrary_enum_discriminant)]
 #![feature(transmutability)]
 #![allow(dead_code)]
 
diff --git a/src/test/ui/transmutability/enums/should_respect_endianness.stderr b/src/test/ui/transmutability/enums/should_respect_endianness.stderr
index fcb70813bd9..0845a5edf32 100644
--- a/src/test/ui/transmutability/enums/should_respect_endianness.stderr
+++ b/src/test/ui/transmutability/enums/should_respect_endianness.stderr
@@ -1,12 +1,12 @@
 error[E0277]: `Src` cannot be safely transmuted into `Unexpected` in the defining scope of `assert::Context`.
-  --> $DIR/should_respect_endianness.rs:37:36
+  --> $DIR/should_respect_endianness.rs:36:36
    |
 LL |     assert::is_transmutable::<Src, Unexpected>();
    |                                    ^^^^^^^^^^ `Src` cannot be safely transmuted into `Unexpected` in the defining scope of `assert::Context`.
    |
    = help: the trait `BikeshedIntrinsicFrom<Src, assert::Context, Assume { alignment: true, lifetimes: true, safety: true, validity: true }>` is not implemented for `Unexpected`
 note: required by a bound in `is_transmutable`
-  --> $DIR/should_respect_endianness.rs:15:14
+  --> $DIR/should_respect_endianness.rs:14:14
    |
 LL |       pub fn is_transmutable<Src, Dst>()
    |              --------------- required by a bound in this
diff --git a/src/test/ui/type-alias-impl-trait/issue-101750.rs b/src/test/ui/type-alias-impl-trait/issue-101750.rs
new file mode 100644
index 00000000000..f564f4fa702
--- /dev/null
+++ b/src/test/ui/type-alias-impl-trait/issue-101750.rs
@@ -0,0 +1,37 @@
+#![feature(type_alias_impl_trait)]
+
+// check-pass
+
+trait Trait {}
+
+type TAIT = impl Trait;
+
+struct Concrete;
+impl Trait for Concrete {}
+
+fn tait() -> TAIT {
+    Concrete
+}
+
+trait OuterTrait {
+    type Item;
+}
+struct Dummy<T> {
+    t: T,
+}
+impl<T> OuterTrait for Dummy<T> {
+    type Item = T;
+}
+
+fn tait_and_impl_trait() -> impl OuterTrait<Item = (TAIT, impl Trait)> {
+    Dummy {
+        t: (tait(), Concrete),
+    }
+}
+
+fn tait_and_dyn_trait() -> impl OuterTrait<Item = (TAIT, Box<dyn Trait>)> {
+    let b: Box<dyn Trait> = Box::new(Concrete);
+    Dummy { t: (tait(), b) }
+}
+
+fn main() {}
diff --git a/src/test/ui/type/issue-94187-verbose-type-name.rs b/src/test/ui/type/issue-94187-verbose-type-name.rs
new file mode 100644
index 00000000000..902ef5ade2b
--- /dev/null
+++ b/src/test/ui/type/issue-94187-verbose-type-name.rs
@@ -0,0 +1,13 @@
+// Check to insure that the output of `std::any::type_name` does not change based on -Zverbose
+// when printing constants
+// run-pass
+// edition: 2018
+// revisions: normal verbose
+// [verbose]compile-flags:-Zverbose
+
+struct Wrapper<const VALUE: usize>;
+
+fn main() {
+    assert_eq!(std::any::type_name::<[u32; 0]>(), "[u32; 0]");
+    assert_eq!(std::any::type_name::<Wrapper<0>>(), "issue_94187_verbose_type_name::Wrapper<0>");
+}
diff --git a/src/test/ui/wf/issue-103573.rs b/src/test/ui/wf/issue-103573.rs
new file mode 100644
index 00000000000..bcbf4f941ec
--- /dev/null
+++ b/src/test/ui/wf/issue-103573.rs
@@ -0,0 +1,22 @@
+trait TraitA {
+    type TypeA;
+}
+
+trait TraitD {
+    type TypeD;
+}
+
+pub trait TraitB {
+    type TypeB: TraitD;
+
+    fn f(_: &<Self::TypeB as TraitD>::TypeD);
+}
+
+pub trait TraitC<E> {
+    type TypeC<'a>: TraitB;
+
+    fn g<'a>(_: &<<Self::TypeC<'a> as TraitB>::TypeB as TraitA>::TypeA);
+    //~^ ERROR the trait bound `<<Self as TraitC<E>>::TypeC<'a> as TraitB>::TypeB: TraitA` is not satisfied
+}
+
+fn main() {}
diff --git a/src/test/ui/wf/issue-103573.stderr b/src/test/ui/wf/issue-103573.stderr
new file mode 100644
index 00000000000..fcf3f15e4d3
--- /dev/null
+++ b/src/test/ui/wf/issue-103573.stderr
@@ -0,0 +1,14 @@
+error[E0277]: the trait bound `<<Self as TraitC<E>>::TypeC<'a> as TraitB>::TypeB: TraitA` is not satisfied
+  --> $DIR/issue-103573.rs:18:5
+   |
+LL |     fn g<'a>(_: &<<Self::TypeC<'a> as TraitB>::TypeB as TraitA>::TypeA);
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `TraitA` is not implemented for `<<Self as TraitC<E>>::TypeC<'a> as TraitB>::TypeB`
+   |
+help: consider further restricting the associated type
+   |
+LL |     fn g<'a>(_: &<<Self::TypeC<'a> as TraitB>::TypeB as TraitA>::TypeA) where <<Self as TraitC<E>>::TypeC<'a> as TraitB>::TypeB: TraitA;
+   |                                                                         +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0277`.
diff --git a/src/tools/cargo b/src/tools/cargo
-Subproject 071eeaf210708219a5a1b2c4728ca2f97df7f2a
+Subproject 7e484fc1a766f56dbc95380f45719698e0c8274
diff --git a/src/tools/clippy/clippy_lints/src/casts/ptr_as_ptr.rs b/src/tools/clippy/clippy_lints/src/casts/ptr_as_ptr.rs
index c2b9253ec35..b9509ca656f 100644
--- a/src/tools/clippy/clippy_lints/src/casts/ptr_as_ptr.rs
+++ b/src/tools/clippy/clippy_lints/src/casts/ptr_as_ptr.rs
@@ -26,7 +26,7 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, msrv: Option<RustcVer
             (Mutability::Not, Mutability::Not) | (Mutability::Mut, Mutability::Mut));
         // The `U` in `pointer::cast` have to be `Sized`
         // as explained here: https://github.com/rust-lang/rust/issues/60602.
-        if to_pointee_ty.is_sized(cx.tcx.at(expr.span), cx.param_env);
+        if to_pointee_ty.is_sized(cx.tcx, cx.param_env);
         then {
             let mut applicability = Applicability::MachineApplicable;
             let cast_expr_sugg = Sugg::hir_with_applicability(cx, cast_expr, "_", &mut applicability);
diff --git a/src/tools/clippy/clippy_lints/src/copy_iterator.rs b/src/tools/clippy/clippy_lints/src/copy_iterator.rs
index 026683f6006..e38f7726853 100644
--- a/src/tools/clippy/clippy_lints/src/copy_iterator.rs
+++ b/src/tools/clippy/clippy_lints/src/copy_iterator.rs
@@ -43,7 +43,7 @@ impl<'tcx> LateLintPass<'tcx> for CopyIterator {
                 of_trait: Some(ref trait_ref),
                 ..
             }) = item.kind;
-            let ty = cx.tcx.type_of(item.def_id);
+            let ty = cx.tcx.type_of(item.owner_id);
             if is_copy(cx, ty);
             if let Some(trait_id) = trait_ref.trait_def_id();
             if cx.tcx.is_diagnostic_item(sym::Iterator, trait_id);
diff --git a/src/tools/clippy/clippy_lints/src/default_union_representation.rs b/src/tools/clippy/clippy_lints/src/default_union_representation.rs
index 741edc13196..dec357ab75c 100644
--- a/src/tools/clippy/clippy_lints/src/default_union_representation.rs
+++ b/src/tools/clippy/clippy_lints/src/default_union_representation.rs
@@ -61,7 +61,7 @@ impl<'tcx> LateLintPass<'tcx> for DefaultUnionRepresentation {
                 None,
                 &format!(
                     "consider annotating `{}` with `#[repr(C)]` to explicitly specify memory layout",
-                    cx.tcx.def_path_str(item.def_id.to_def_id())
+                    cx.tcx.def_path_str(item.owner_id.to_def_id())
                 ),
             );
         }
diff --git a/src/tools/clippy/clippy_lints/src/dereference.rs b/src/tools/clippy/clippy_lints/src/dereference.rs
index a95d9f5390d..a37ee82d4c8 100644
--- a/src/tools/clippy/clippy_lints/src/dereference.rs
+++ b/src/tools/clippy/clippy_lints/src/dereference.rs
@@ -29,7 +29,7 @@ use rustc_middle::ty::{
 };
 use rustc_semver::RustcVersion;
 use rustc_session::{declare_tool_lint, impl_lint_pass};
-use rustc_span::{symbol::sym, Span, Symbol, DUMMY_SP};
+use rustc_span::{symbol::sym, Span, Symbol};
 use rustc_trait_selection::infer::InferCtxtExt as _;
 use rustc_trait_selection::traits::{query::evaluate_obligation::InferCtxtExt as _, Obligation, ObligationCause};
 use std::collections::VecDeque;
@@ -715,47 +715,47 @@ fn walk_parents<'tcx>(
             },
             Node::Item(&Item {
                 kind: ItemKind::Static(..) | ItemKind::Const(..),
-                def_id,
+                owner_id,
                 span,
                 ..
             })
             | Node::TraitItem(&TraitItem {
                 kind: TraitItemKind::Const(..),
-                def_id,
+                owner_id,
                 span,
                 ..
             })
             | Node::ImplItem(&ImplItem {
                 kind: ImplItemKind::Const(..),
-                def_id,
+                owner_id,
                 span,
                 ..
             }) if span.ctxt() == ctxt => {
-                let ty = cx.tcx.type_of(def_id.def_id);
+                let ty = cx.tcx.type_of(owner_id.def_id);
                 Some(ty_auto_deref_stability(cx, ty, precedence).position_for_result(cx))
             },
 
             Node::Item(&Item {
                 kind: ItemKind::Fn(..),
-                def_id,
+                owner_id,
                 span,
                 ..
             })
             | Node::TraitItem(&TraitItem {
                 kind: TraitItemKind::Fn(..),
-                def_id,
+                owner_id,
                 span,
                 ..
             })
             | Node::ImplItem(&ImplItem {
                 kind: ImplItemKind::Fn(..),
-                def_id,
+                owner_id,
                 span,
                 ..
             }) if span.ctxt() == ctxt => {
                 let output = cx
                     .tcx
-                    .erase_late_bound_regions(cx.tcx.fn_sig(def_id.to_def_id()).output());
+                    .erase_late_bound_regions(cx.tcx.fn_sig(owner_id.to_def_id()).output());
                 Some(ty_auto_deref_stability(cx, output, precedence).position_for_result(cx))
             },
 
@@ -990,7 +990,7 @@ fn binding_ty_auto_deref_stability<'tcx>(
                                 cx.typeck_results().node_type(ty.ty.hir_id),
                                 binder_args,
                             ))
-                            .is_sized(cx.tcx.at(DUMMY_SP), cx.param_env.without_caller_bounds()),
+                            .is_sized(cx.tcx, cx.param_env.without_caller_bounds()),
                     )
                 }
             },
@@ -1005,7 +1005,7 @@ fn binding_ty_auto_deref_stability<'tcx>(
                         cx.typeck_results().node_type(ty.ty.hir_id),
                         binder_args,
                     ))
-                    .is_sized(cx.tcx.at(DUMMY_SP), cx.param_env.without_caller_bounds()),
+                    .is_sized(cx.tcx, cx.param_env.without_caller_bounds()),
             ),
             TyKind::OpaqueDef(..) | TyKind::Infer | TyKind::Typeof(..) | TyKind::TraitObject(..) | TyKind::Err => {
                 Position::ReborrowStable(precedence)
@@ -1297,7 +1297,7 @@ impl<'tcx> TyPosition<'tcx> {
     fn position_for_result(self, cx: &LateContext<'tcx>) -> Position {
         match (self.position, self.ty) {
             (Position::ReborrowStable(precedence), Some(ty)) => {
-                Position::DerefStable(precedence, ty.is_sized(cx.tcx.at(DUMMY_SP), cx.param_env))
+                Position::DerefStable(precedence, ty.is_sized(cx.tcx, cx.param_env))
             },
             (position, _) => position,
         }
@@ -1348,7 +1348,7 @@ fn ty_auto_deref_stability<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>, precedenc
             | ty::Tuple(_)
             | ty::Projection(_) => Position::DerefStable(
                 precedence,
-                ty.is_sized(cx.tcx.at(DUMMY_SP), cx.param_env.without_caller_bounds()),
+                ty.is_sized(cx.tcx, cx.param_env.without_caller_bounds()),
             )
             .into(),
         };
diff --git a/src/tools/clippy/clippy_lints/src/derivable_impls.rs b/src/tools/clippy/clippy_lints/src/derivable_impls.rs
index 06ae5abeaeb..ae8f6b79449 100644
--- a/src/tools/clippy/clippy_lints/src/derivable_impls.rs
+++ b/src/tools/clippy/clippy_lints/src/derivable_impls.rs
@@ -70,7 +70,7 @@ impl<'tcx> LateLintPass<'tcx> for DerivableImpls {
                 self_ty,
                 ..
             }) = item.kind;
-            if !cx.tcx.has_attr(item.def_id.to_def_id(), sym::automatically_derived);
+            if !cx.tcx.has_attr(item.owner_id.to_def_id(), sym::automatically_derived);
             if !item.span.from_expansion();
             if let Some(def_id) = trait_ref.trait_def_id();
             if cx.tcx.is_diagnostic_item(sym::Default, def_id);
@@ -78,7 +78,7 @@ impl<'tcx> LateLintPass<'tcx> for DerivableImpls {
             if let Some(Node::ImplItem(impl_item)) = cx.tcx.hir().find(impl_item_hir);
             if let ImplItemKind::Fn(_, b) = &impl_item.kind;
             if let Body { value: func_expr, .. } = cx.tcx.hir().body(*b);
-            if let Some(adt_def) = cx.tcx.type_of(item.def_id).ty_adt_def();
+            if let Some(adt_def) = cx.tcx.type_of(item.owner_id).ty_adt_def();
             if let attrs = cx.tcx.hir().attrs(item.hir_id());
             if !attrs.iter().any(|attr| attr.doc_str().is_some());
             if let child_attrs = cx.tcx.hir().attrs(impl_item_hir);
diff --git a/src/tools/clippy/clippy_lints/src/derive.rs b/src/tools/clippy/clippy_lints/src/derive.rs
index fad984d05ca..102a02138bc 100644
--- a/src/tools/clippy/clippy_lints/src/derive.rs
+++ b/src/tools/clippy/clippy_lints/src/derive.rs
@@ -210,8 +210,8 @@ impl<'tcx> LateLintPass<'tcx> for Derive {
             ..
         }) = item.kind
         {
-            let ty = cx.tcx.type_of(item.def_id);
-            let is_automatically_derived = cx.tcx.has_attr(item.def_id.to_def_id(), sym::automatically_derived);
+            let ty = cx.tcx.type_of(item.owner_id);
+            let is_automatically_derived = cx.tcx.has_attr(item.owner_id.to_def_id(), sym::automatically_derived);
 
             check_hash_peq(cx, item.span, trait_ref, ty, is_automatically_derived);
             check_ord_partial_ord(cx, item.span, trait_ref, ty, is_automatically_derived);
diff --git a/src/tools/clippy/clippy_lints/src/doc.rs b/src/tools/clippy/clippy_lints/src/doc.rs
index 36dc7e3396b..24d6a6951af 100644
--- a/src/tools/clippy/clippy_lints/src/doc.rs
+++ b/src/tools/clippy/clippy_lints/src/doc.rs
@@ -257,17 +257,17 @@ impl<'tcx> LateLintPass<'tcx> for DocMarkdown {
         let headers = check_attrs(cx, &self.valid_idents, attrs);
         match item.kind {
             hir::ItemKind::Fn(ref sig, _, body_id) => {
-                if !(is_entrypoint_fn(cx, item.def_id.to_def_id()) || in_external_macro(cx.tcx.sess, item.span)) {
+                if !(is_entrypoint_fn(cx, item.owner_id.to_def_id()) || in_external_macro(cx.tcx.sess, item.span)) {
                     let body = cx.tcx.hir().body(body_id);
                     let mut fpu = FindPanicUnwrap {
                         cx,
-                        typeck_results: cx.tcx.typeck(item.def_id.def_id),
+                        typeck_results: cx.tcx.typeck(item.owner_id.def_id),
                         panic_span: None,
                     };
                     fpu.visit_expr(body.value);
                     lint_for_missing_headers(
                         cx,
-                        item.def_id.def_id,
+                        item.owner_id.def_id,
                         item.span,
                         sig,
                         headers,
@@ -304,7 +304,7 @@ impl<'tcx> LateLintPass<'tcx> for DocMarkdown {
         let headers = check_attrs(cx, &self.valid_idents, attrs);
         if let hir::TraitItemKind::Fn(ref sig, ..) = item.kind {
             if !in_external_macro(cx.tcx.sess, item.span) {
-                lint_for_missing_headers(cx, item.def_id.def_id, item.span, sig, headers, None, None);
+                lint_for_missing_headers(cx, item.owner_id.def_id, item.span, sig, headers, None, None);
             }
         }
     }
@@ -319,13 +319,13 @@ impl<'tcx> LateLintPass<'tcx> for DocMarkdown {
             let body = cx.tcx.hir().body(body_id);
             let mut fpu = FindPanicUnwrap {
                 cx,
-                typeck_results: cx.tcx.typeck(item.def_id.def_id),
+                typeck_results: cx.tcx.typeck(item.owner_id.def_id),
                 panic_span: None,
             };
             fpu.visit_expr(body.value);
             lint_for_missing_headers(
                 cx,
-                item.def_id.def_id,
+                item.owner_id.def_id,
                 item.span,
                 sig,
                 headers,
@@ -345,7 +345,7 @@ fn lint_for_missing_headers<'tcx>(
     body_id: Option<hir::BodyId>,
     panic_span: Option<Span>,
 ) {
-    if !cx.access_levels.is_exported(def_id) {
+    if !cx.effective_visibilities.is_exported(def_id) {
         return; // Private functions do not require doc comments
     }
 
diff --git a/src/tools/clippy/clippy_lints/src/empty_enum.rs b/src/tools/clippy/clippy_lints/src/empty_enum.rs
index bbebc024414..0570c2a1013 100644
--- a/src/tools/clippy/clippy_lints/src/empty_enum.rs
+++ b/src/tools/clippy/clippy_lints/src/empty_enum.rs
@@ -49,7 +49,7 @@ impl<'tcx> LateLintPass<'tcx> for EmptyEnum {
         }
 
         if let ItemKind::Enum(..) = item.kind {
-            let ty = cx.tcx.type_of(item.def_id);
+            let ty = cx.tcx.type_of(item.owner_id);
             let adt = ty.ty_adt_def().expect("already checked whether this is an enum");
             if adt.variants().is_empty() {
                 span_lint_and_help(
diff --git a/src/tools/clippy/clippy_lints/src/enum_variants.rs b/src/tools/clippy/clippy_lints/src/enum_variants.rs
index b019d07d53d..223545fa798 100644
--- a/src/tools/clippy/clippy_lints/src/enum_variants.rs
+++ b/src/tools/clippy/clippy_lints/src/enum_variants.rs
@@ -265,7 +265,7 @@ impl LateLintPass<'_> for EnumVariantNames {
                     }
                     // The `module_name_repetitions` lint should only trigger if the item has the module in its
                     // name. Having the same name is accepted.
-                    if cx.tcx.visibility(item.def_id).is_public() && item_camel.len() > mod_camel.len() {
+                    if cx.tcx.visibility(item.owner_id).is_public() && item_camel.len() > mod_camel.len() {
                         let matching = count_match_start(mod_camel, &item_camel);
                         let rmatching = count_match_end(mod_camel, &item_camel);
                         let nchars = mod_camel.chars().count();
@@ -296,7 +296,7 @@ impl LateLintPass<'_> for EnumVariantNames {
             }
         }
         if let ItemKind::Enum(ref def, _) = item.kind {
-            if !(self.avoid_breaking_exported_api && cx.access_levels.is_exported(item.def_id.def_id)) {
+            if !(self.avoid_breaking_exported_api && cx.effective_visibilities.is_exported(item.owner_id.def_id)) {
                 check_variant(cx, self.threshold, def, item_name, item.span);
             }
         }
diff --git a/src/tools/clippy/clippy_lints/src/escape.rs b/src/tools/clippy/clippy_lints/src/escape.rs
index c9a8307eba4..7f1a4c4beb1 100644
--- a/src/tools/clippy/clippy_lints/src/escape.rs
+++ b/src/tools/clippy/clippy_lints/src/escape.rs
@@ -88,7 +88,7 @@ impl<'tcx> LateLintPass<'tcx> for BoxedLocal {
                         // 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.def_id.to_def_id())
+                                TraitRef::identity(cx.tcx, trait_item.id.owner_id.to_def_id())
                                     .self_ty()
                                     .skip_binder(),
                             );
diff --git a/src/tools/clippy/clippy_lints/src/exhaustive_items.rs b/src/tools/clippy/clippy_lints/src/exhaustive_items.rs
index be6242bd20b..1fece5d1c48 100644
--- a/src/tools/clippy/clippy_lints/src/exhaustive_items.rs
+++ b/src/tools/clippy/clippy_lints/src/exhaustive_items.rs
@@ -73,7 +73,7 @@ impl LateLintPass<'_> for ExhaustiveItems {
     fn check_item(&mut self, cx: &LateContext<'_>, item: &Item<'_>) {
         if_chain! {
             if let ItemKind::Enum(..) | ItemKind::Struct(..) = item.kind;
-            if cx.access_levels.is_exported(item.def_id.def_id);
+            if cx.effective_visibilities.is_exported(item.owner_id.def_id);
             let attrs = cx.tcx.hir().attrs(item.hir_id());
             if !attrs.iter().any(|a| a.has_name(sym::non_exhaustive));
             then {
diff --git a/src/tools/clippy/clippy_lints/src/fallible_impl_from.rs b/src/tools/clippy/clippy_lints/src/fallible_impl_from.rs
index ef24a5d06ad..0a633f242a5 100644
--- a/src/tools/clippy/clippy_lints/src/fallible_impl_from.rs
+++ b/src/tools/clippy/clippy_lints/src/fallible_impl_from.rs
@@ -55,7 +55,7 @@ impl<'tcx> LateLintPass<'tcx> for FallibleImplFrom {
         // check for `impl From<???> for ..`
         if_chain! {
             if let hir::ItemKind::Impl(impl_) = &item.kind;
-            if let Some(impl_trait_ref) = cx.tcx.impl_trait_ref(item.def_id);
+            if let Some(impl_trait_ref) = cx.tcx.impl_trait_ref(item.owner_id);
             if cx.tcx.is_diagnostic_item(sym::From, impl_trait_ref.def_id);
             then {
                 lint_impl_body(cx, item.span, impl_.items);
@@ -107,7 +107,7 @@ fn lint_impl_body<'tcx>(cx: &LateContext<'tcx>, impl_span: Span, impl_items: &[h
                 let body = cx.tcx.hir().body(body_id);
                 let mut fpu = FindPanicUnwrap {
                     lcx: cx,
-                    typeck_results: cx.tcx.typeck(impl_item.id.def_id.def_id),
+                    typeck_results: cx.tcx.typeck(impl_item.id.owner_id.def_id),
                     result: Vec::new(),
                 };
                 fpu.visit_expr(body.value);
diff --git a/src/tools/clippy/clippy_lints/src/format_args.rs b/src/tools/clippy/clippy_lints/src/format_args.rs
index 32073536b45..f0fe845d330 100644
--- a/src/tools/clippy/clippy_lints/src/format_args.rs
+++ b/src/tools/clippy/clippy_lints/src/format_args.rs
@@ -115,7 +115,7 @@ declare_clippy_lint! {
     /// nothing will be suggested, e.g. `println!("{0}={1}", var, 1+2)`.
     #[clippy::version = "1.65.0"]
     pub UNINLINED_FORMAT_ARGS,
-    style,
+    pedantic,
     "using non-inlined variables in `format!` calls"
 }
 
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 95eda4ea882..8b24a4962fb 100644
--- a/src/tools/clippy/clippy_lints/src/from_over_into.rs
+++ b/src/tools/clippy/clippy_lints/src/from_over_into.rs
@@ -76,7 +76,7 @@ impl<'tcx> LateLintPass<'tcx> for FromOverInto {
             && let Some(into_trait_seg) = hir_trait_ref.path.segments.last()
             // `impl Into<target_ty> for self_ty`
             && let Some(GenericArgs { args: [GenericArg::Type(target_ty)], .. }) = into_trait_seg.args
-            && let Some(middle_trait_ref) = cx.tcx.impl_trait_ref(item.def_id)
+            && let Some(middle_trait_ref) = cx.tcx.impl_trait_ref(item.owner_id)
             && cx.tcx.is_diagnostic_item(sym::Into, middle_trait_ref.def_id)
         {
             span_lint_and_then(
diff --git a/src/tools/clippy/clippy_lints/src/functions/must_use.rs b/src/tools/clippy/clippy_lints/src/functions/must_use.rs
index 3064b6c9d22..bff69f91518 100644
--- a/src/tools/clippy/clippy_lints/src/functions/must_use.rs
+++ b/src/tools/clippy/clippy_lints/src/functions/must_use.rs
@@ -22,9 +22,9 @@ use super::{DOUBLE_MUST_USE, MUST_USE_CANDIDATE, MUST_USE_UNIT};
 
 pub(super) fn check_item<'tcx>(cx: &LateContext<'tcx>, item: &'tcx hir::Item<'_>) {
     let attrs = cx.tcx.hir().attrs(item.hir_id());
-    let attr = cx.tcx.get_attr(item.def_id.to_def_id(), sym::must_use);
+    let attr = cx.tcx.get_attr(item.owner_id.to_def_id(), sym::must_use);
     if let hir::ItemKind::Fn(ref sig, _generics, ref body_id) = item.kind {
-        let is_public = cx.access_levels.is_exported(item.def_id.def_id);
+        let is_public = cx.effective_visibilities.is_exported(item.owner_id.def_id);
         let fn_header_span = item.span.with_hi(sig.decl.output.span().hi());
         if let Some(attr) = attr {
             check_needless_must_use(cx, sig.decl, item.hir_id(), item.span, fn_header_span, attr);
@@ -34,7 +34,7 @@ pub(super) fn check_item<'tcx>(cx: &LateContext<'tcx>, item: &'tcx hir::Item<'_>
                 sig.decl,
                 cx.tcx.hir().body(*body_id),
                 item.span,
-                item.def_id.def_id,
+                item.owner_id.def_id,
                 item.span.with_hi(sig.decl.output.span().hi()),
                 "this function could have a `#[must_use]` attribute",
             );
@@ -44,20 +44,20 @@ pub(super) fn check_item<'tcx>(cx: &LateContext<'tcx>, item: &'tcx hir::Item<'_>
 
 pub(super) fn check_impl_item<'tcx>(cx: &LateContext<'tcx>, item: &'tcx hir::ImplItem<'_>) {
     if let hir::ImplItemKind::Fn(ref sig, ref body_id) = item.kind {
-        let is_public = cx.access_levels.is_exported(item.def_id.def_id);
+        let is_public = cx.effective_visibilities.is_exported(item.owner_id.def_id);
         let fn_header_span = item.span.with_hi(sig.decl.output.span().hi());
         let attrs = cx.tcx.hir().attrs(item.hir_id());
-        let attr = cx.tcx.get_attr(item.def_id.to_def_id(), sym::must_use);
+        let attr = cx.tcx.get_attr(item.owner_id.to_def_id(), sym::must_use);
         if let Some(attr) = attr {
             check_needless_must_use(cx, sig.decl, item.hir_id(), item.span, fn_header_span, attr);
-        } else if is_public && !is_proc_macro(cx.sess(), attrs) && trait_ref_of_method(cx, item.def_id.def_id).is_none()
+        } else if is_public && !is_proc_macro(cx.sess(), attrs) && trait_ref_of_method(cx, item.owner_id.def_id).is_none()
         {
             check_must_use_candidate(
                 cx,
                 sig.decl,
                 cx.tcx.hir().body(*body_id),
                 item.span,
-                item.def_id.def_id,
+                item.owner_id.def_id,
                 item.span.with_hi(sig.decl.output.span().hi()),
                 "this method could have a `#[must_use]` attribute",
             );
@@ -67,11 +67,11 @@ pub(super) fn check_impl_item<'tcx>(cx: &LateContext<'tcx>, item: &'tcx hir::Imp
 
 pub(super) fn check_trait_item<'tcx>(cx: &LateContext<'tcx>, item: &'tcx hir::TraitItem<'_>) {
     if let hir::TraitItemKind::Fn(ref sig, ref eid) = item.kind {
-        let is_public = cx.access_levels.is_exported(item.def_id.def_id);
+        let is_public = cx.effective_visibilities.is_exported(item.owner_id.def_id);
         let fn_header_span = item.span.with_hi(sig.decl.output.span().hi());
 
         let attrs = cx.tcx.hir().attrs(item.hir_id());
-        let attr = cx.tcx.get_attr(item.def_id.to_def_id(), sym::must_use);
+        let attr = cx.tcx.get_attr(item.owner_id.to_def_id(), sym::must_use);
         if let Some(attr) = attr {
             check_needless_must_use(cx, sig.decl, item.hir_id(), item.span, fn_header_span, attr);
         } else if let hir::TraitFn::Provided(eid) = *eid {
@@ -82,7 +82,7 @@ pub(super) fn check_trait_item<'tcx>(cx: &LateContext<'tcx>, item: &'tcx hir::Tr
                     sig.decl,
                     body,
                     item.span,
-                    item.def_id.def_id,
+                    item.owner_id.def_id,
                     item.span.with_hi(sig.decl.output.span().hi()),
                     "this method could have a `#[must_use]` attribute",
                 );
@@ -137,7 +137,7 @@ fn check_must_use_candidate<'tcx>(
         || mutates_static(cx, body)
         || in_external_macro(cx.sess(), item_span)
         || returns_unit(decl)
-        || !cx.access_levels.is_exported(item_id)
+        || !cx.effective_visibilities.is_exported(item_id)
         || is_must_use_ty(cx, return_ty(cx, cx.tcx.hir().local_def_id_to_hir_id(item_id)))
     {
         return;
@@ -188,7 +188,7 @@ fn is_mutable_ty<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>, span: Span, tys: &m
         // primitive types are never mutable
         ty::Bool | ty::Char | ty::Int(_) | ty::Uint(_) | ty::Float(_) | ty::Str => false,
         ty::Adt(adt, substs) => {
-            tys.insert(adt.did()) && !ty.is_freeze(cx.tcx.at(span), cx.param_env)
+            tys.insert(adt.did()) && !ty.is_freeze(cx.tcx, cx.param_env)
                 || KNOWN_WRAPPER_TYS
                     .iter()
                     .any(|&sym| cx.tcx.is_diagnostic_item(sym, adt.did()))
diff --git a/src/tools/clippy/clippy_lints/src/functions/not_unsafe_ptr_arg_deref.rs b/src/tools/clippy/clippy_lints/src/functions/not_unsafe_ptr_arg_deref.rs
index b7595d101e0..2c0bf551fd7 100644
--- a/src/tools/clippy/clippy_lints/src/functions/not_unsafe_ptr_arg_deref.rs
+++ b/src/tools/clippy/clippy_lints/src/functions/not_unsafe_ptr_arg_deref.rs
@@ -31,7 +31,7 @@ pub(super) fn check_fn<'tcx>(
 pub(super) fn check_trait_item<'tcx>(cx: &LateContext<'tcx>, item: &'tcx hir::TraitItem<'_>) {
     if let hir::TraitItemKind::Fn(ref sig, hir::TraitFn::Provided(eid)) = item.kind {
         let body = cx.tcx.hir().body(eid);
-        check_raw_ptr(cx, sig.header.unsafety, sig.decl, body, item.def_id.def_id);
+        check_raw_ptr(cx, sig.header.unsafety, sig.decl, body, item.owner_id.def_id);
     }
 }
 
@@ -42,7 +42,7 @@ fn check_raw_ptr<'tcx>(
     body: &'tcx hir::Body<'tcx>,
     def_id: LocalDefId,
 ) {
-    if unsafety == hir::Unsafety::Normal && cx.access_levels.is_exported(def_id) {
+    if unsafety == hir::Unsafety::Normal && cx.effective_visibilities.is_exported(def_id) {
         let raw_ptrs = iter_input_pats(decl, body)
             .filter_map(|arg| raw_ptr_arg(cx, arg))
             .collect::<HirIdSet>();
diff --git a/src/tools/clippy/clippy_lints/src/functions/result.rs b/src/tools/clippy/clippy_lints/src/functions/result.rs
index 113c4e9f509..5c63fb2acb1 100644
--- a/src/tools/clippy/clippy_lints/src/functions/result.rs
+++ b/src/tools/clippy/clippy_lints/src/functions/result.rs
@@ -34,9 +34,9 @@ fn result_err_ty<'tcx>(
 
 pub(super) fn check_item<'tcx>(cx: &LateContext<'tcx>, item: &hir::Item<'tcx>, large_err_threshold: u64) {
     if let hir::ItemKind::Fn(ref sig, _generics, _) = item.kind
-        && let Some((hir_ty, err_ty)) = result_err_ty(cx, sig.decl, item.def_id.def_id, item.span)
+        && let Some((hir_ty, err_ty)) = result_err_ty(cx, sig.decl, item.owner_id.def_id, item.span)
     {
-        if cx.access_levels.is_exported(item.def_id.def_id) {
+        if cx.effective_visibilities.is_exported(item.owner_id.def_id) {
             let fn_header_span = item.span.with_hi(sig.decl.output.span().hi());
             check_result_unit_err(cx, err_ty, fn_header_span);
         }
@@ -47,10 +47,10 @@ pub(super) fn check_item<'tcx>(cx: &LateContext<'tcx>, item: &hir::Item<'tcx>, l
 pub(super) fn check_impl_item<'tcx>(cx: &LateContext<'tcx>, item: &hir::ImplItem<'tcx>, large_err_threshold: u64) {
     // Don't lint if method is a trait's implementation, we can't do anything about those
     if let hir::ImplItemKind::Fn(ref sig, _) = item.kind
-        && let Some((hir_ty, err_ty)) = result_err_ty(cx, sig.decl, item.def_id.def_id, item.span)
-        && trait_ref_of_method(cx, item.def_id.def_id).is_none()
+        && let Some((hir_ty, err_ty)) = result_err_ty(cx, sig.decl, item.owner_id.def_id, item.span)
+        && trait_ref_of_method(cx, item.owner_id.def_id).is_none()
     {
-        if cx.access_levels.is_exported(item.def_id.def_id) {
+        if cx.effective_visibilities.is_exported(item.owner_id.def_id) {
             let fn_header_span = item.span.with_hi(sig.decl.output.span().hi());
             check_result_unit_err(cx, err_ty, fn_header_span);
         }
@@ -61,8 +61,8 @@ pub(super) fn check_impl_item<'tcx>(cx: &LateContext<'tcx>, item: &hir::ImplItem
 pub(super) fn check_trait_item<'tcx>(cx: &LateContext<'tcx>, item: &hir::TraitItem<'tcx>, large_err_threshold: u64) {
     if let hir::TraitItemKind::Fn(ref sig, _) = item.kind {
         let fn_header_span = item.span.with_hi(sig.decl.output.span().hi());
-        if let Some((hir_ty, err_ty)) = result_err_ty(cx, sig.decl, item.def_id.def_id, item.span) {
-            if cx.access_levels.is_exported(item.def_id.def_id) {
+        if let Some((hir_ty, err_ty)) = result_err_ty(cx, sig.decl, item.owner_id.def_id, item.span) {
+            if cx.effective_visibilities.is_exported(item.owner_id.def_id) {
                 check_result_unit_err(cx, err_ty, fn_header_span);
             }
             check_result_large_err(cx, err_ty, hir_ty.span, large_err_threshold);
diff --git a/src/tools/clippy/clippy_lints/src/implicit_hasher.rs b/src/tools/clippy/clippy_lints/src/implicit_hasher.rs
index 93efe957b1d..94e06cf704b 100644
--- a/src/tools/clippy/clippy_lints/src/implicit_hasher.rs
+++ b/src/tools/clippy/clippy_lints/src/implicit_hasher.rs
@@ -111,7 +111,7 @@ impl<'tcx> LateLintPass<'tcx> for ImplicitHasher {
             }
         }
 
-        if !cx.access_levels.is_exported(item.def_id.def_id) {
+        if !cx.effective_visibilities.is_exported(item.owner_id.def_id) {
             return;
         }
 
diff --git a/src/tools/clippy/clippy_lints/src/inherent_to_string.rs b/src/tools/clippy/clippy_lints/src/inherent_to_string.rs
index 676136df572..14a37f535b4 100644
--- a/src/tools/clippy/clippy_lints/src/inherent_to_string.rs
+++ b/src/tools/clippy/clippy_lints/src/inherent_to_string.rs
@@ -108,7 +108,7 @@ impl<'tcx> LateLintPass<'tcx> for InherentToString {
             if is_type_diagnostic_item(cx, return_ty(cx, impl_item.hir_id()), sym::String);
 
             // Filters instances of to_string which are required by a trait
-            if trait_ref_of_method(cx, impl_item.def_id.def_id).is_none();
+            if trait_ref_of_method(cx, impl_item.owner_id.def_id).is_none();
 
             then {
                 show_lint(cx, impl_item);
@@ -124,7 +124,7 @@ fn show_lint(cx: &LateContext<'_>, item: &ImplItem<'_>) {
         .expect("Failed to get trait ID of `Display`!");
 
     // Get the real type of 'self'
-    let self_type = cx.tcx.fn_sig(item.def_id).input(0);
+    let self_type = cx.tcx.fn_sig(item.owner_id).input(0);
     let self_type = self_type.skip_binder().peel_refs();
 
     // Emit either a warning or an error
diff --git a/src/tools/clippy/clippy_lints/src/iter_not_returning_iterator.rs b/src/tools/clippy/clippy_lints/src/iter_not_returning_iterator.rs
index ea9f046fb97..e76de77f195 100644
--- a/src/tools/clippy/clippy_lints/src/iter_not_returning_iterator.rs
+++ b/src/tools/clippy/clippy_lints/src/iter_not_returning_iterator.rs
@@ -44,7 +44,7 @@ impl<'tcx> LateLintPass<'tcx> for IterNotReturningIterator {
         let name = item.ident.name.as_str();
         if matches!(name, "iter" | "iter_mut") {
             if let TraitItemKind::Fn(fn_sig, _) = &item.kind {
-                check_sig(cx, name, fn_sig, item.def_id.def_id);
+                check_sig(cx, name, fn_sig, item.owner_id.def_id);
             }
         }
     }
@@ -58,7 +58,7 @@ impl<'tcx> LateLintPass<'tcx> for IterNotReturningIterator {
             )
         {
             if let ImplItemKind::Fn(fn_sig, _) = &item.kind {
-                check_sig(cx, name, fn_sig, item.def_id.def_id);
+                check_sig(cx, name, fn_sig, item.owner_id.def_id);
             }
         }
     }
diff --git a/src/tools/clippy/clippy_lints/src/large_enum_variant.rs b/src/tools/clippy/clippy_lints/src/large_enum_variant.rs
index 8ed7e4bb196..06e95728549 100644
--- a/src/tools/clippy/clippy_lints/src/large_enum_variant.rs
+++ b/src/tools/clippy/clippy_lints/src/large_enum_variant.rs
@@ -123,7 +123,7 @@ impl<'tcx> LateLintPass<'tcx> for LargeEnumVariant {
             return;
         }
         if let ItemKind::Enum(ref def, _) = item.kind {
-            let ty = cx.tcx.type_of(item.def_id);
+            let ty = cx.tcx.type_of(item.owner_id);
             let Adt(adt, subst) = ty.kind() else {
                 panic!("already checked whether this is an enum")
             };
diff --git a/src/tools/clippy/clippy_lints/src/len_zero.rs b/src/tools/clippy/clippy_lints/src/len_zero.rs
index 3a563736fb0..b0cba40c27a 100644
--- a/src/tools/clippy/clippy_lints/src/len_zero.rs
+++ b/src/tools/clippy/clippy_lints/src/len_zero.rs
@@ -134,7 +134,7 @@ impl<'tcx> LateLintPass<'tcx> for LenZero {
             if item.ident.name == sym::len;
             if let ImplItemKind::Fn(sig, _) = &item.kind;
             if sig.decl.implicit_self.has_implicit_self();
-            if cx.access_levels.is_exported(item.def_id.def_id);
+            if cx.effective_visibilities.is_exported(item.owner_id.def_id);
             if matches!(sig.decl.output, FnRetTy::Return(_));
             if let Some(imp) = get_parent_as_impl(cx.tcx, item.hir_id());
             if imp.of_trait.is_none();
@@ -143,7 +143,7 @@ impl<'tcx> LateLintPass<'tcx> for LenZero {
             if let Some(local_id) = ty_id.as_local();
             let ty_hir_id = cx.tcx.hir().local_def_id_to_hir_id(local_id);
             if !is_lint_allowed(cx, LEN_WITHOUT_IS_EMPTY, ty_hir_id);
-            if let Some(output) = parse_len_output(cx, cx.tcx.fn_sig(item.def_id).skip_binder());
+            if let Some(output) = parse_len_output(cx, cx.tcx.fn_sig(item.owner_id).skip_binder());
             then {
                 let (name, kind) = match cx.tcx.hir().find(ty_hir_id) {
                     Some(Node::ForeignItem(x)) => (x.ident.name, "extern type"),
@@ -195,7 +195,7 @@ fn check_trait_items(cx: &LateContext<'_>, visited_trait: &Item<'_>, trait_items
     fn is_named_self(cx: &LateContext<'_>, item: &TraitItemRef, name: Symbol) -> bool {
         item.ident.name == name
             && if let AssocItemKind::Fn { has_self } = item.kind {
-                has_self && { cx.tcx.fn_sig(item.id.def_id).inputs().skip_binder().len() == 1 }
+                has_self && { cx.tcx.fn_sig(item.id.owner_id).inputs().skip_binder().len() == 1 }
             } else {
                 false
             }
@@ -210,11 +210,11 @@ fn check_trait_items(cx: &LateContext<'_>, visited_trait: &Item<'_>, trait_items
         }
     }
 
-    if cx.access_levels.is_exported(visited_trait.def_id.def_id)
+    if cx.effective_visibilities.is_exported(visited_trait.owner_id.def_id)
         && trait_items.iter().any(|i| is_named_self(cx, i, sym::len))
     {
         let mut current_and_super_traits = DefIdSet::default();
-        fill_trait_set(visited_trait.def_id.to_def_id(), &mut current_and_super_traits, cx);
+        fill_trait_set(visited_trait.owner_id.to_def_id(), &mut current_and_super_traits, cx);
         let is_empty = sym!(is_empty);
 
         let is_empty_method_found = current_and_super_traits
@@ -331,7 +331,7 @@ fn check_for_is_empty<'tcx>(
             None,
             None,
         ),
-        Some(is_empty) if !cx.access_levels.is_exported(is_empty.def_id.expect_local()) => (
+        Some(is_empty) if !cx.effective_visibilities.is_exported(is_empty.def_id.expect_local()) => (
             format!(
                 "{item_kind} `{}` has a public `len` method, but a private `is_empty` method",
                 item_name.as_str(),
diff --git a/src/tools/clippy/clippy_lints/src/let_if_seq.rs b/src/tools/clippy/clippy_lints/src/let_if_seq.rs
index 13071d64441..db41bc67da1 100644
--- a/src/tools/clippy/clippy_lints/src/let_if_seq.rs
+++ b/src/tools/clippy/clippy_lints/src/let_if_seq.rs
@@ -74,7 +74,7 @@ impl<'tcx> LateLintPass<'tcx> for LetIfSeq {
                     let span = stmt.span.to(if_.span);
 
                     let has_interior_mutability = !cx.typeck_results().node_type(canonical_id).is_freeze(
-                        cx.tcx.at(span),
+                        cx.tcx,
                         cx.param_env,
                     );
                     if has_interior_mutability { return; }
diff --git a/src/tools/clippy/clippy_lints/src/lib.register_all.rs b/src/tools/clippy/clippy_lints/src/lib.register_all.rs
index f5ad52ba189..c455e1561b7 100644
--- a/src/tools/clippy/clippy_lints/src/lib.register_all.rs
+++ b/src/tools/clippy/clippy_lints/src/lib.register_all.rs
@@ -72,7 +72,6 @@ store.register_group(true, "clippy::all", Some("clippy_all"), vec![
     LintId::of(format::USELESS_FORMAT),
     LintId::of(format_args::FORMAT_IN_FORMAT_ARGS),
     LintId::of(format_args::TO_STRING_IN_FORMAT_ARGS),
-    LintId::of(format_args::UNINLINED_FORMAT_ARGS),
     LintId::of(format_args::UNUSED_FORMAT_SPECS),
     LintId::of(format_impl::PRINT_IN_FORMAT_IMPL),
     LintId::of(format_impl::RECURSIVE_FORMAT_IMPL),
diff --git a/src/tools/clippy/clippy_lints/src/lib.register_pedantic.rs b/src/tools/clippy/clippy_lints/src/lib.register_pedantic.rs
index 060d3bdc7c6..44e969585b5 100644
--- a/src/tools/clippy/clippy_lints/src/lib.register_pedantic.rs
+++ b/src/tools/clippy/clippy_lints/src/lib.register_pedantic.rs
@@ -29,6 +29,7 @@ store.register_group(true, "clippy::pedantic", Some("clippy_pedantic"), vec![
     LintId::of(eta_reduction::REDUNDANT_CLOSURE_FOR_METHOD_CALLS),
     LintId::of(excessive_bools::FN_PARAMS_EXCESSIVE_BOOLS),
     LintId::of(excessive_bools::STRUCT_EXCESSIVE_BOOLS),
+    LintId::of(format_args::UNINLINED_FORMAT_ARGS),
     LintId::of(functions::MUST_USE_CANDIDATE),
     LintId::of(functions::TOO_MANY_LINES),
     LintId::of(if_not_else::IF_NOT_ELSE),
diff --git a/src/tools/clippy/clippy_lints/src/lib.register_style.rs b/src/tools/clippy/clippy_lints/src/lib.register_style.rs
index 6894d69e928..3312f564855 100644
--- a/src/tools/clippy/clippy_lints/src/lib.register_style.rs
+++ b/src/tools/clippy/clippy_lints/src/lib.register_style.rs
@@ -25,7 +25,6 @@ store.register_group(true, "clippy::style", Some("clippy_style"), vec![
     LintId::of(enum_variants::MODULE_INCEPTION),
     LintId::of(eta_reduction::REDUNDANT_CLOSURE),
     LintId::of(float_literal::EXCESSIVE_PRECISION),
-    LintId::of(format_args::UNINLINED_FORMAT_ARGS),
     LintId::of(from_over_into::FROM_OVER_INTO),
     LintId::of(from_str_radix_10::FROM_STR_RADIX_10),
     LintId::of(functions::DOUBLE_MUST_USE),
diff --git a/src/tools/clippy/clippy_lints/src/lifetimes.rs b/src/tools/clippy/clippy_lints/src/lifetimes.rs
index aef253303a8..3bf2d7e4ea4 100644
--- a/src/tools/clippy/clippy_lints/src/lifetimes.rs
+++ b/src/tools/clippy/clippy_lints/src/lifetimes.rs
@@ -102,7 +102,7 @@ impl<'tcx> LateLintPass<'tcx> for Lifetimes {
 
     fn check_impl_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx ImplItem<'_>) {
         if let ImplItemKind::Fn(ref sig, id) = item.kind {
-            let report_extra_lifetimes = trait_ref_of_method(cx, item.def_id.def_id).is_none();
+            let report_extra_lifetimes = trait_ref_of_method(cx, item.owner_id.def_id).is_none();
             check_fn_inner(
                 cx,
                 sig.decl,
diff --git a/src/tools/clippy/clippy_lints/src/manual_non_exhaustive.rs b/src/tools/clippy/clippy_lints/src/manual_non_exhaustive.rs
index 6a42275322b..6806c146696 100644
--- a/src/tools/clippy/clippy_lints/src/manual_non_exhaustive.rs
+++ b/src/tools/clippy/clippy_lints/src/manual_non_exhaustive.rs
@@ -166,7 +166,7 @@ impl<'tcx> LateLintPass<'tcx> for ManualNonExhaustiveEnum {
             if let Some((id, span)) = iter.next()
                 && iter.next().is_none()
             {
-                self.potential_enums.push((item.def_id.def_id, id, item.span, span));
+                self.potential_enums.push((item.owner_id.def_id, id, item.span, span));
             }
         }
     }
diff --git a/src/tools/clippy/clippy_lints/src/methods/mod.rs b/src/tools/clippy/clippy_lints/src/methods/mod.rs
index fb92779be2a..8a76ba0b064 100644
--- a/src/tools/clippy/clippy_lints/src/methods/mod.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/mod.rs
@@ -3250,15 +3250,15 @@ impl<'tcx> LateLintPass<'tcx> for Methods {
         let name = impl_item.ident.name.as_str();
         let parent = cx.tcx.hir().get_parent_item(impl_item.hir_id()).def_id;
         let item = cx.tcx.hir().expect_item(parent);
-        let self_ty = cx.tcx.type_of(item.def_id);
+        let self_ty = cx.tcx.type_of(item.owner_id);
 
         let implements_trait = matches!(item.kind, hir::ItemKind::Impl(hir::Impl { of_trait: Some(_), .. }));
         if let hir::ImplItemKind::Fn(ref sig, id) = impl_item.kind {
-            let method_sig = cx.tcx.fn_sig(impl_item.def_id);
+            let method_sig = cx.tcx.fn_sig(impl_item.owner_id);
             let method_sig = cx.tcx.erase_late_bound_regions(method_sig);
             let first_arg_ty_opt = method_sig.inputs().iter().next().copied();
             // if this impl block implements a trait, lint in trait definition instead
-            if !implements_trait && cx.access_levels.is_exported(impl_item.def_id.def_id) {
+            if !implements_trait && cx.effective_visibilities.is_exported(impl_item.owner_id.def_id) {
                 // check missing trait implementations
                 for method_config in &TRAIT_METHODS {
                     if name == method_config.method_name
@@ -3292,7 +3292,7 @@ impl<'tcx> LateLintPass<'tcx> for Methods {
 
             if sig.decl.implicit_self.has_implicit_self()
                     && !(self.avoid_breaking_exported_api
-                    && cx.access_levels.is_exported(impl_item.def_id.def_id))
+                    && cx.effective_visibilities.is_exported(impl_item.owner_id.def_id))
                     && let Some(first_arg) = iter_input_pats(sig.decl, cx.tcx.hir().body(id)).next()
                     && let Some(first_arg_ty) = first_arg_ty_opt
                 {
@@ -3370,7 +3370,7 @@ impl<'tcx> LateLintPass<'tcx> for Methods {
             then {
                 let first_arg_span = first_arg_ty.span;
                 let first_arg_ty = hir_ty_to_ty(cx.tcx, first_arg_ty);
-                let self_ty = TraitRef::identity(cx.tcx, item.def_id.to_def_id())
+                let self_ty = TraitRef::identity(cx.tcx, item.owner_id.to_def_id())
                     .self_ty()
                     .skip_binder();
                 wrong_self_convention::check(
@@ -3389,7 +3389,7 @@ impl<'tcx> LateLintPass<'tcx> for Methods {
             if item.ident.name == sym::new;
             if let TraitItemKind::Fn(_, _) = item.kind;
             let ret_ty = return_ty(cx, item.hir_id());
-            let self_ty = TraitRef::identity(cx.tcx, item.def_id.to_def_id())
+            let self_ty = TraitRef::identity(cx.tcx, item.owner_id.to_def_id())
                 .self_ty()
                 .skip_binder();
             if !ret_ty.contains(self_ty);
diff --git a/src/tools/clippy/clippy_lints/src/missing_doc.rs b/src/tools/clippy/clippy_lints/src/missing_doc.rs
index b3f1553cfea..2a63681db60 100644
--- a/src/tools/clippy/clippy_lints/src/missing_doc.rs
+++ b/src/tools/clippy/clippy_lints/src/missing_doc.rs
@@ -131,7 +131,7 @@ impl<'tcx> LateLintPass<'tcx> for MissingDoc {
             hir::ItemKind::Fn(..) => {
                 // ignore main()
                 if it.ident.name == sym::main {
-                    let at_root = cx.tcx.local_parent(it.def_id.def_id) == CRATE_DEF_ID;
+                    let at_root = cx.tcx.local_parent(it.owner_id.def_id) == CRATE_DEF_ID;
                     if at_root {
                         return;
                     }
@@ -155,7 +155,7 @@ impl<'tcx> LateLintPass<'tcx> for MissingDoc {
             | hir::ItemKind::Use(..) => return,
         };
 
-        let (article, desc) = cx.tcx.article_and_description(it.def_id.to_def_id());
+        let (article, desc) = cx.tcx.article_and_description(it.owner_id.to_def_id());
 
         let attrs = cx.tcx.hir().attrs(it.hir_id());
         if !is_from_proc_macro(cx, it) {
@@ -164,7 +164,7 @@ impl<'tcx> LateLintPass<'tcx> for MissingDoc {
     }
 
     fn check_trait_item(&mut self, cx: &LateContext<'tcx>, trait_item: &'tcx hir::TraitItem<'_>) {
-        let (article, desc) = cx.tcx.article_and_description(trait_item.def_id.to_def_id());
+        let (article, desc) = cx.tcx.article_and_description(trait_item.owner_id.to_def_id());
 
         let attrs = cx.tcx.hir().attrs(trait_item.hir_id());
         if !is_from_proc_macro(cx, trait_item) {
@@ -174,7 +174,7 @@ impl<'tcx> LateLintPass<'tcx> for MissingDoc {
 
     fn check_impl_item(&mut self, cx: &LateContext<'tcx>, impl_item: &'tcx hir::ImplItem<'_>) {
         // If the method is an impl for a trait, don't doc.
-        if let Some(cid) = cx.tcx.associated_item(impl_item.def_id).impl_container(cx.tcx) {
+        if let Some(cid) = cx.tcx.associated_item(impl_item.owner_id).impl_container(cx.tcx) {
             if cx.tcx.impl_trait_ref(cid).is_some() {
                 return;
             }
@@ -182,7 +182,7 @@ impl<'tcx> LateLintPass<'tcx> for MissingDoc {
             return;
         }
 
-        let (article, desc) = cx.tcx.article_and_description(impl_item.def_id.to_def_id());
+        let (article, desc) = cx.tcx.article_and_description(impl_item.owner_id.to_def_id());
         let attrs = cx.tcx.hir().attrs(impl_item.hir_id());
         if !is_from_proc_macro(cx, impl_item) {
             self.check_missing_docs_attrs(cx, attrs, impl_item.span, article, desc);
diff --git a/src/tools/clippy/clippy_lints/src/missing_inline.rs b/src/tools/clippy/clippy_lints/src/missing_inline.rs
index 01c87f058ad..758ce47cf11 100644
--- a/src/tools/clippy/clippy_lints/src/missing_inline.rs
+++ b/src/tools/clippy/clippy_lints/src/missing_inline.rs
@@ -88,7 +88,7 @@ impl<'tcx> LateLintPass<'tcx> for MissingInline {
             return;
         }
 
-        if !cx.access_levels.is_exported(it.def_id.def_id) {
+        if !cx.effective_visibilities.is_exported(it.owner_id.def_id) {
             return;
         }
         match it.kind {
@@ -105,7 +105,7 @@ impl<'tcx> LateLintPass<'tcx> for MissingInline {
                     match tit_.kind {
                         hir::TraitItemKind::Const(..) | hir::TraitItemKind::Type(..) => {},
                         hir::TraitItemKind::Fn(..) => {
-                            if cx.tcx.impl_defaultness(tit.id.def_id).has_value() {
+                            if cx.tcx.impl_defaultness(tit.id.owner_id).has_value() {
                                 // trait method with default body needs inline in case
                                 // an impl is not provided
                                 let desc = "a default trait method";
@@ -142,7 +142,7 @@ impl<'tcx> LateLintPass<'tcx> for MissingInline {
         }
 
         // If the item being implemented is not exported, then we don't need #[inline]
-        if !cx.access_levels.is_exported(impl_item.def_id.def_id) {
+        if !cx.effective_visibilities.is_exported(impl_item.owner_id.def_id) {
             return;
         }
 
@@ -151,7 +151,7 @@ impl<'tcx> LateLintPass<'tcx> for MissingInline {
             hir::ImplItemKind::Const(..) | hir::ImplItemKind::Type(_) => return,
         };
 
-        let assoc_item = cx.tcx.associated_item(impl_item.def_id);
+        let assoc_item = cx.tcx.associated_item(impl_item.owner_id);
         let container_id = assoc_item.container_id(cx.tcx);
         let trait_def_id = match assoc_item.container {
             TraitContainer => Some(container_id),
@@ -159,7 +159,7 @@ impl<'tcx> LateLintPass<'tcx> for MissingInline {
         };
 
         if let Some(trait_def_id) = trait_def_id {
-            if trait_def_id.is_local() && !cx.access_levels.is_exported(impl_item.def_id.def_id) {
+            if trait_def_id.is_local() && !cx.effective_visibilities.is_exported(impl_item.owner_id.def_id) {
                 // If a trait is being implemented for an item, and the
                 // trait is not exported, we don't need #[inline]
                 return;
diff --git a/src/tools/clippy/clippy_lints/src/mut_key.rs b/src/tools/clippy/clippy_lints/src/mut_key.rs
index 25d6ca83a94..4b62dcdffe2 100644
--- a/src/tools/clippy/clippy_lints/src/mut_key.rs
+++ b/src/tools/clippy/clippy_lints/src/mut_key.rs
@@ -89,7 +89,7 @@ impl<'tcx> LateLintPass<'tcx> for MutableKeyType {
 
     fn check_impl_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx hir::ImplItem<'tcx>) {
         if let hir::ImplItemKind::Fn(ref sig, ..) = item.kind {
-            if trait_ref_of_method(cx, item.def_id.def_id).is_none() {
+            if trait_ref_of_method(cx, item.owner_id.def_id).is_none() {
                 check_sig(cx, item.hir_id(), sig.decl);
             }
         }
@@ -136,12 +136,14 @@ fn check_ty<'tcx>(cx: &LateContext<'tcx>, span: Span, ty: Ty<'tcx>) {
 /// [`Hash`] or [`Ord`].
 fn is_interior_mutable_type<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>, span: Span) -> bool {
     match *ty.kind() {
-        Ref(_, inner_ty, mutbl) => mutbl == hir::Mutability::Mut || is_interior_mutable_type(cx, inner_ty, span),
+        Ref(_, inner_ty, mutbl) => {
+            mutbl == hir::Mutability::Mut || is_interior_mutable_type(cx, inner_ty, span)
+        }
         Slice(inner_ty) => is_interior_mutable_type(cx, inner_ty, span),
         Array(inner_ty, size) => {
             size.try_eval_usize(cx.tcx, cx.param_env).map_or(true, |u| u != 0)
                 && is_interior_mutable_type(cx, inner_ty, span)
-        },
+        }
         Tuple(fields) => fields.iter().any(|ty| is_interior_mutable_type(cx, ty, span)),
         Adt(def, substs) => {
             // Special case for collections in `std` who's impl of `Hash` or `Ord` delegates to
@@ -167,9 +169,9 @@ fn is_interior_mutable_type<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>, span: Sp
             } else {
                 !ty.has_escaping_bound_vars()
                     && cx.tcx.layout_of(cx.param_env.and(ty)).is_ok()
-                    && !ty.is_freeze(cx.tcx.at(span), cx.param_env)
+                    && !ty.is_freeze(cx.tcx, cx.param_env)
             }
-        },
+        }
         _ => false,
     }
 }
diff --git a/src/tools/clippy/clippy_lints/src/needless_pass_by_value.rs b/src/tools/clippy/clippy_lints/src/needless_pass_by_value.rs
index 9c949a28f44..b2e9ce5c94d 100644
--- a/src/tools/clippy/clippy_lints/src/needless_pass_by_value.rs
+++ b/src/tools/clippy/clippy_lints/src/needless_pass_by_value.rs
@@ -19,7 +19,7 @@ use rustc_middle::mir::FakeReadCause;
 use rustc_middle::ty::{self, TypeVisitable};
 use rustc_session::{declare_lint_pass, declare_tool_lint};
 use rustc_span::symbol::kw;
-use rustc_span::{sym, Span, DUMMY_SP};
+use rustc_span::{sym, Span};
 use rustc_target::spec::abi::Abi;
 use rustc_trait_selection::traits;
 use rustc_trait_selection::traits::misc::can_type_implement_copy;
@@ -184,7 +184,7 @@ impl<'tcx> LateLintPass<'tcx> for NeedlessPassByValue {
                 if !is_self(arg);
                 if !ty.is_mutable_ptr();
                 if !is_copy(cx, ty);
-                if ty.is_sized(cx.tcx.at(DUMMY_SP), cx.param_env);
+                if ty.is_sized(cx.tcx, cx.param_env);
                 if !allowed_traits.iter().any(|&t| implements_trait(cx, ty, t, &[]));
                 if !implements_borrow_trait;
                 if !all_borrowable_trait;
diff --git a/src/tools/clippy/clippy_lints/src/new_without_default.rs b/src/tools/clippy/clippy_lints/src/new_without_default.rs
index 6017117e1ec..54a3c82b713 100644
--- a/src/tools/clippy/clippy_lints/src/new_without_default.rs
+++ b/src/tools/clippy/clippy_lints/src/new_without_default.rs
@@ -84,7 +84,7 @@ impl<'tcx> LateLintPass<'tcx> for NewWithoutDefault {
                             // can't be implemented for unsafe new
                             return;
                         }
-                        if cx.tcx.is_doc_hidden(impl_item.def_id.def_id) {
+                        if cx.tcx.is_doc_hidden(impl_item.owner_id.def_id) {
                             // shouldn't be implemented when it is hidden in docs
                             return;
                         }
@@ -96,7 +96,7 @@ impl<'tcx> LateLintPass<'tcx> for NewWithoutDefault {
                         if_chain! {
                             if sig.decl.inputs.is_empty();
                             if name == sym::new;
-                            if cx.access_levels.is_reachable(impl_item.def_id.def_id);
+                            if cx.effective_visibilities.is_reachable(impl_item.owner_id.def_id);
                             let self_def_id = cx.tcx.hir().get_parent_item(id);
                             let self_ty = cx.tcx.type_of(self_def_id);
                             if self_ty == return_ty(cx, id);
diff --git a/src/tools/clippy/clippy_lints/src/non_copy_const.rs b/src/tools/clippy/clippy_lints/src/non_copy_const.rs
index a6742824bc5..2a3bd4ee6ce 100644
--- a/src/tools/clippy/clippy_lints/src/non_copy_const.rs
+++ b/src/tools/clippy/clippy_lints/src/non_copy_const.rs
@@ -20,7 +20,7 @@ use rustc_middle::mir::interpret::{ConstValue, ErrorHandled};
 use rustc_middle::ty::adjustment::Adjust;
 use rustc_middle::ty::{self, Ty};
 use rustc_session::{declare_lint_pass, declare_tool_lint};
-use rustc_span::{sym, InnerSpan, Span, DUMMY_SP};
+use rustc_span::{sym, InnerSpan, Span};
 
 // FIXME: this is a correctness problem but there's no suitable
 // warn-by-default category.
@@ -136,7 +136,7 @@ fn is_unfrozen<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> bool {
     // since it works when a pointer indirection involves (`Cell<*const T>`).
     // Making up a `ParamEnv` where every generic params and assoc types are `Freeze`is another option;
     // but I'm not sure whether it's a decent way, if possible.
-    cx.tcx.layout_of(cx.param_env.and(ty)).is_ok() && !ty.is_freeze(cx.tcx.at(DUMMY_SP), cx.param_env)
+    cx.tcx.layout_of(cx.param_env.and(ty)).is_ok() && !ty.is_freeze(cx.tcx, cx.param_env)
 }
 
 fn is_value_unfrozen_raw<'tcx>(
@@ -303,7 +303,7 @@ impl<'tcx> LateLintPass<'tcx> for NonCopyConst {
                         if let Some(of_trait_def_id) = of_trait_ref.trait_def_id();
                         if let Some(of_assoc_item) = cx
                             .tcx
-                            .associated_item(impl_item.def_id)
+                            .associated_item(impl_item.owner_id)
                             .trait_item_def_id;
                         if cx
                             .tcx
diff --git a/src/tools/clippy/clippy_lints/src/non_send_fields_in_send_ty.rs b/src/tools/clippy/clippy_lints/src/non_send_fields_in_send_ty.rs
index ddef7352de8..714c0ff227b 100644
--- a/src/tools/clippy/clippy_lints/src/non_send_fields_in_send_ty.rs
+++ b/src/tools/clippy/clippy_lints/src/non_send_fields_in_send_ty.rs
@@ -89,7 +89,7 @@ impl<'tcx> LateLintPass<'tcx> for NonSendFieldInSendTy {
             if let Some(trait_id) = trait_ref.trait_def_id();
             if send_trait == trait_id;
             if hir_impl.polarity == ImplPolarity::Positive;
-            if let Some(ty_trait_ref) = cx.tcx.impl_trait_ref(item.def_id);
+            if let Some(ty_trait_ref) = cx.tcx.impl_trait_ref(item.owner_id);
             if let self_ty = ty_trait_ref.self_ty();
             if let ty::Adt(adt_def, impl_trait_substs) = self_ty.kind();
             then {
diff --git a/src/tools/clippy/clippy_lints/src/only_used_in_recursion.rs b/src/tools/clippy/clippy_lints/src/only_used_in_recursion.rs
index d64a9cf71e1..7722a476d7b 100644
--- a/src/tools/clippy/clippy_lints/src/only_used_in_recursion.rs
+++ b/src/tools/clippy/clippy_lints/src/only_used_in_recursion.rs
@@ -227,25 +227,25 @@ impl<'tcx> LateLintPass<'tcx> for OnlyUsedInRecursion {
         // `skip_params` is either `0` or `1` to skip the `self` parameter in trait functions.
         // It can't be renamed, and it can't be removed without removing it from multiple functions.
         let (fn_id, fn_kind, skip_params) = match get_parent_node(cx.tcx, body.value.hir_id) {
-            Some(Node::Item(i)) => (i.def_id.to_def_id(), FnKind::Fn, 0),
+            Some(Node::Item(i)) => (i.owner_id.to_def_id(), FnKind::Fn, 0),
             Some(Node::TraitItem(&TraitItem {
                 kind: TraitItemKind::Fn(ref sig, _),
-                def_id,
+                owner_id,
                 ..
             })) => (
-                def_id.to_def_id(),
+                owner_id.to_def_id(),
                 FnKind::TraitFn,
                 usize::from(sig.decl.implicit_self.has_implicit_self()),
             ),
             Some(Node::ImplItem(&ImplItem {
                 kind: ImplItemKind::Fn(ref sig, _),
-                def_id,
+                owner_id,
                 ..
             })) => {
                 #[allow(trivial_casts)]
-                if let Some(Node::Item(item)) = get_parent_node(cx.tcx, def_id.into())
-                    && let Some(trait_ref) = cx.tcx.impl_trait_ref(item.def_id)
-                    && let Some(trait_item_id) = cx.tcx.associated_item(def_id).trait_item_def_id
+                if let Some(Node::Item(item)) = get_parent_node(cx.tcx, owner_id.into())
+                    && let Some(trait_ref) = cx.tcx.impl_trait_ref(item.owner_id)
+                    && let Some(trait_item_id) = cx.tcx.associated_item(owner_id).trait_item_def_id
                 {
                     (
                         trait_item_id,
@@ -253,7 +253,7 @@ impl<'tcx> LateLintPass<'tcx> for OnlyUsedInRecursion {
                         usize::from(sig.decl.implicit_self.has_implicit_self()),
                     )
                 } else {
-                    (def_id.to_def_id(), FnKind::Fn, 0)
+                    (owner_id.to_def_id(), FnKind::Fn, 0)
                 }
             },
             _ => return,
diff --git a/src/tools/clippy/clippy_lints/src/operators/op_ref.rs b/src/tools/clippy/clippy_lints/src/operators/op_ref.rs
index 1085e608944..71b31b5e4a5 100644
--- a/src/tools/clippy/clippy_lints/src/operators/op_ref.rs
+++ b/src/tools/clippy/clippy_lints/src/operators/op_ref.rs
@@ -204,7 +204,7 @@ fn are_equal<'tcx>(cx: &LateContext<'tcx>, middle_ty: Ty<'_>, hir_ty: &rustc_hir
         if let ty::Adt(adt_def, _) = middle_ty.kind();
         if let Some(local_did) = adt_def.did().as_local();
         let item = cx.tcx.hir().expect_item(local_did);
-        let middle_ty_id = item.def_id.to_def_id();
+        let middle_ty_id = item.owner_id.to_def_id();
         if let TyKind::Path(QPath::Resolved(_, path)) = hir_ty.kind;
         if let Res::Def(_, hir_ty_id) = path.res;
 
diff --git a/src/tools/clippy/clippy_lints/src/partialeq_ne_impl.rs b/src/tools/clippy/clippy_lints/src/partialeq_ne_impl.rs
index 09ac514d014..5aa3c6f2f93 100644
--- a/src/tools/clippy/clippy_lints/src/partialeq_ne_impl.rs
+++ b/src/tools/clippy/clippy_lints/src/partialeq_ne_impl.rs
@@ -36,7 +36,7 @@ impl<'tcx> LateLintPass<'tcx> for PartialEqNeImpl {
     fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'_>) {
         if_chain! {
             if let ItemKind::Impl(Impl { of_trait: Some(ref trait_ref), items: impl_items, .. }) = item.kind;
-            if !cx.tcx.has_attr(item.def_id.to_def_id(), sym::automatically_derived);
+            if !cx.tcx.has_attr(item.owner_id.to_def_id(), sym::automatically_derived);
             if let Some(eq_trait) = cx.tcx.lang_items().eq_trait();
             if trait_ref.path.res.def_id() == eq_trait;
             then {
diff --git a/src/tools/clippy/clippy_lints/src/pass_by_ref_or_value.rs b/src/tools/clippy/clippy_lints/src/pass_by_ref_or_value.rs
index 45e98de10ac..f9fd3645668 100644
--- a/src/tools/clippy/clippy_lints/src/pass_by_ref_or_value.rs
+++ b/src/tools/clippy/clippy_lints/src/pass_by_ref_or_value.rs
@@ -139,7 +139,7 @@ impl<'tcx> PassByRefOrValue {
     }
 
     fn check_poly_fn(&mut self, cx: &LateContext<'tcx>, def_id: LocalDefId, decl: &FnDecl<'_>, span: Option<Span>) {
-        if self.avoid_breaking_exported_api && cx.access_levels.is_exported(def_id) {
+        if self.avoid_breaking_exported_api && cx.effective_visibilities.is_exported(def_id) {
             return;
         }
 
@@ -261,7 +261,7 @@ impl<'tcx> LateLintPass<'tcx> for PassByRefOrValue {
         }
 
         if let hir::TraitItemKind::Fn(method_sig, _) = &item.kind {
-            self.check_poly_fn(cx, item.def_id.def_id, method_sig.decl, None);
+            self.check_poly_fn(cx, item.owner_id.def_id, method_sig.decl, None);
         }
     }
 
diff --git a/src/tools/clippy/clippy_lints/src/ptr.rs b/src/tools/clippy/clippy_lints/src/ptr.rs
index 40db315bf27..0d74c90a834 100644
--- a/src/tools/clippy/clippy_lints/src/ptr.rs
+++ b/src/tools/clippy/clippy_lints/src/ptr.rs
@@ -164,7 +164,7 @@ impl<'tcx> LateLintPass<'tcx> for Ptr {
             check_mut_from_ref(cx, sig, None);
             for arg in check_fn_args(
                 cx,
-                cx.tcx.fn_sig(item.def_id).skip_binder().inputs(),
+                cx.tcx.fn_sig(item.owner_id).skip_binder().inputs(),
                 sig.decl.inputs,
                 &[],
             )
@@ -188,7 +188,7 @@ impl<'tcx> LateLintPass<'tcx> for Ptr {
         let (item_id, sig, is_trait_item) = match parents.next() {
             Some((_, Node::Item(i))) => {
                 if let ItemKind::Fn(sig, ..) = &i.kind {
-                    (i.def_id, sig, false)
+                    (i.owner_id, sig, false)
                 } else {
                     return;
                 }
@@ -200,14 +200,14 @@ impl<'tcx> LateLintPass<'tcx> for Ptr {
                     return;
                 }
                 if let ImplItemKind::Fn(sig, _) = &i.kind {
-                    (i.def_id, sig, false)
+                    (i.owner_id, sig, false)
                 } else {
                     return;
                 }
             },
             Some((_, Node::TraitItem(i))) => {
                 if let TraitItemKind::Fn(sig, _) = &i.kind {
-                    (i.def_id, sig, true)
+                    (i.owner_id, sig, true)
                 } else {
                     return;
                 }
diff --git a/src/tools/clippy/clippy_lints/src/question_mark.rs b/src/tools/clippy/clippy_lints/src/question_mark.rs
index 328371fd602..bb86fb3b7d4 100644
--- a/src/tools/clippy/clippy_lints/src/question_mark.rs
+++ b/src/tools/clippy/clippy_lints/src/question_mark.rs
@@ -94,7 +94,7 @@ fn check_is_none_or_err_and_early_return<'tcx>(cx: &LateContext<'tcx>, expr: &Ex
         then {
             let mut applicability = Applicability::MachineApplicable;
             let receiver_str = snippet_with_applicability(cx, caller.span, "..", &mut applicability);
-            let by_ref = !caller_ty.is_copy_modulo_regions(cx.tcx.at(caller.span), cx.param_env) &&
+            let by_ref = !caller_ty.is_copy_modulo_regions(cx.tcx, cx.param_env) &&
                 !matches!(caller.kind, ExprKind::Call(..) | ExprKind::MethodCall(..));
             let sugg = if let Some(else_inner) = r#else {
                 if eq_expr_value(cx, caller, peel_blocks(else_inner)) {
diff --git a/src/tools/clippy/clippy_lints/src/redundant_pub_crate.rs b/src/tools/clippy/clippy_lints/src/redundant_pub_crate.rs
index 464f6827e1d..26075e9f70f 100644
--- a/src/tools/clippy/clippy_lints/src/redundant_pub_crate.rs
+++ b/src/tools/clippy/clippy_lints/src/redundant_pub_crate.rs
@@ -46,12 +46,12 @@ impl_lint_pass!(RedundantPubCrate => [REDUNDANT_PUB_CRATE]);
 impl<'tcx> LateLintPass<'tcx> for RedundantPubCrate {
     fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'tcx>) {
         if_chain! {
-            if cx.tcx.visibility(item.def_id.def_id) == ty::Visibility::Restricted(CRATE_DEF_ID.to_def_id());
-            if !cx.access_levels.is_exported(item.def_id.def_id) && self.is_exported.last() == Some(&false);
+            if cx.tcx.visibility(item.owner_id.def_id) == ty::Visibility::Restricted(CRATE_DEF_ID.to_def_id());
+            if !cx.effective_visibilities.is_exported(item.owner_id.def_id) && self.is_exported.last() == Some(&false);
             if is_not_macro_export(item);
             then {
                 let span = item.span.with_hi(item.ident.span.hi());
-                let descr = cx.tcx.def_kind(item.def_id).descr(item.def_id.to_def_id());
+                let descr = cx.tcx.def_kind(item.owner_id).descr(item.owner_id.to_def_id());
                 span_lint_and_then(
                     cx,
                     REDUNDANT_PUB_CRATE,
@@ -70,7 +70,7 @@ impl<'tcx> LateLintPass<'tcx> for RedundantPubCrate {
         }
 
         if let ItemKind::Mod { .. } = item.kind {
-            self.is_exported.push(cx.access_levels.is_exported(item.def_id.def_id));
+            self.is_exported.push(cx.effective_visibilities.is_exported(item.owner_id.def_id));
         }
     }
 
diff --git a/src/tools/clippy/clippy_lints/src/return_self_not_must_use.rs b/src/tools/clippy/clippy_lints/src/return_self_not_must_use.rs
index 16d702a3868..b77faf7322b 100644
--- a/src/tools/clippy/clippy_lints/src/return_self_not_must_use.rs
+++ b/src/tools/clippy/clippy_lints/src/return_self_not_must_use.rs
@@ -74,7 +74,7 @@ fn check_method(cx: &LateContext<'_>, decl: &FnDecl<'_>, fn_def: LocalDefId, spa
         if !in_external_macro(cx.sess(), span);
         if decl.implicit_self.has_implicit_self();
         // We only show this warning for public exported methods.
-        if cx.access_levels.is_exported(fn_def);
+        if cx.effective_visibilities.is_exported(fn_def);
         // We don't want to emit this lint if the `#[must_use]` attribute is already there.
         if !cx.tcx.hir().attrs(hir_id).iter().any(|attr| attr.has_name(sym::must_use));
         if cx.tcx.visibility(fn_def.to_def_id()).is_public();
@@ -128,7 +128,7 @@ impl<'tcx> LateLintPass<'tcx> for ReturnSelfNotMustUse {
 
     fn check_trait_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx TraitItem<'tcx>) {
         if let TraitItemKind::Fn(ref sig, _) = item.kind {
-            check_method(cx, sig.decl, item.def_id.def_id, item.span, item.hir_id());
+            check_method(cx, sig.decl, item.owner_id.def_id, item.span, item.hir_id());
         }
     }
 }
diff --git a/src/tools/clippy/clippy_lints/src/same_name_method.rs b/src/tools/clippy/clippy_lints/src/same_name_method.rs
index 4249063d2d4..caab5851baf 100644
--- a/src/tools/clippy/clippy_lints/src/same_name_method.rs
+++ b/src/tools/clippy/clippy_lints/src/same_name_method.rs
@@ -52,7 +52,7 @@ impl<'tcx> LateLintPass<'tcx> for SameNameMethod {
         let mut map = FxHashMap::<Res, ExistingName>::default();
 
         for id in cx.tcx.hir().items() {
-            if matches!(cx.tcx.def_kind(id.def_id), DefKind::Impl)
+            if matches!(cx.tcx.def_kind(id.owner_id), DefKind::Impl)
                 && let item = cx.tcx.hir().item(id)
                 && let ItemKind::Impl(Impl {
                   items,
diff --git a/src/tools/clippy/clippy_lints/src/self_named_constructors.rs b/src/tools/clippy/clippy_lints/src/self_named_constructors.rs
index 1ac538f4c7c..71b387c66a3 100644
--- a/src/tools/clippy/clippy_lints/src/self_named_constructors.rs
+++ b/src/tools/clippy/clippy_lints/src/self_named_constructors.rs
@@ -53,7 +53,7 @@ impl<'tcx> LateLintPass<'tcx> for SelfNamedConstructors {
 
         let parent = cx.tcx.hir().get_parent_item(impl_item.hir_id()).def_id;
         let item = cx.tcx.hir().expect_item(parent);
-        let self_ty = cx.tcx.type_of(item.def_id);
+        let self_ty = cx.tcx.type_of(item.owner_id);
         let ret_ty = return_ty(cx, impl_item.hir_id());
 
         // Do not check trait impls
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 58cc057a39e..8cf3efc8dc7 100644
--- a/src/tools/clippy/clippy_lints/src/trailing_empty_array.rs
+++ b/src/tools/clippy/clippy_lints/src/trailing_empty_array.rs
@@ -46,7 +46,7 @@ impl<'tcx> LateLintPass<'tcx> for TrailingEmptyArray {
                 None,
                 &format!(
                     "consider annotating `{}` with `#[repr(C)]` or another `repr` attribute",
-                    cx.tcx.def_path_str(item.def_id.to_def_id())
+                    cx.tcx.def_path_str(item.owner_id.to_def_id())
                 ),
             );
         }
diff --git a/src/tools/clippy/clippy_lints/src/transmute/transmute_undefined_repr.rs b/src/tools/clippy/clippy_lints/src/transmute/transmute_undefined_repr.rs
index 1c99a02e6c7..3d4bbbf648c 100644
--- a/src/tools/clippy/clippy_lints/src/transmute/transmute_undefined_repr.rs
+++ b/src/tools/clippy/clippy_lints/src/transmute/transmute_undefined_repr.rs
@@ -5,7 +5,6 @@ use rustc_hir::Expr;
 use rustc_lint::LateContext;
 use rustc_middle::ty::SubstsRef;
 use rustc_middle::ty::{self, IntTy, Ty, TypeAndMut, UintTy};
-use rustc_span::DUMMY_SP;
 
 #[expect(clippy::too_many_lines)]
 pub(super) fn check<'tcx>(
@@ -28,24 +27,32 @@ pub(super) fn check<'tcx>(
 
             // `Repr(C)` <-> unordered type.
             // If the first field of the `Repr(C)` type matches then the transmute is ok
-            (ReducedTy::OrderedFields(_, Some(from_sub_ty)), ReducedTy::UnorderedFields(to_sub_ty))
-            | (ReducedTy::UnorderedFields(from_sub_ty), ReducedTy::OrderedFields(_, Some(to_sub_ty))) => {
+            (
+                ReducedTy::OrderedFields(_, Some(from_sub_ty)),
+                ReducedTy::UnorderedFields(to_sub_ty),
+            )
+            | (
+                ReducedTy::UnorderedFields(from_sub_ty),
+                ReducedTy::OrderedFields(_, Some(to_sub_ty)),
+            ) => {
                 from_ty = from_sub_ty;
                 to_ty = to_sub_ty;
                 continue;
-            },
-            (ReducedTy::OrderedFields(_, Some(from_sub_ty)), ReducedTy::Other(to_sub_ty)) if reduced_tys.to_fat_ptr => {
+            }
+            (ReducedTy::OrderedFields(_, Some(from_sub_ty)), ReducedTy::Other(to_sub_ty))
+                if reduced_tys.to_fat_ptr =>
+            {
                 from_ty = from_sub_ty;
                 to_ty = to_sub_ty;
                 continue;
-            },
+            }
             (ReducedTy::Other(from_sub_ty), ReducedTy::OrderedFields(_, Some(to_sub_ty)))
                 if reduced_tys.from_fat_ptr =>
             {
                 from_ty = from_sub_ty;
                 to_ty = to_sub_ty;
                 continue;
-            },
+            }
 
             // ptr <-> ptr
             (ReducedTy::Other(from_sub_ty), ReducedTy::Other(to_sub_ty))
@@ -55,19 +62,19 @@ pub(super) fn check<'tcx>(
                 from_ty = from_sub_ty;
                 to_ty = to_sub_ty;
                 continue;
-            },
+            }
 
             // fat ptr <-> (*size, *size)
             (ReducedTy::Other(_), ReducedTy::UnorderedFields(to_ty))
                 if reduced_tys.from_fat_ptr && is_size_pair(to_ty) =>
             {
                 return false;
-            },
+            }
             (ReducedTy::UnorderedFields(from_ty), ReducedTy::Other(_))
                 if reduced_tys.to_fat_ptr && is_size_pair(from_ty) =>
             {
                 return false;
-            },
+            }
 
             // fat ptr -> some struct | some struct -> fat ptr
             (ReducedTy::Other(_), _) if reduced_tys.from_fat_ptr => {
@@ -78,12 +85,14 @@ pub(super) fn check<'tcx>(
                     &format!("transmute from `{from_ty_orig}` which has an undefined layout"),
                     |diag| {
                         if from_ty_orig.peel_refs() != from_ty.peel_refs() {
-                            diag.note(&format!("the contained type `{from_ty}` has an undefined layout"));
+                            diag.note(&format!(
+                                "the contained type `{from_ty}` has an undefined layout"
+                            ));
                         }
                     },
                 );
                 return true;
-            },
+            }
             (_, ReducedTy::Other(_)) if reduced_tys.to_fat_ptr => {
                 span_lint_and_then(
                     cx,
@@ -92,14 +101,18 @@ pub(super) fn check<'tcx>(
                     &format!("transmute to `{to_ty_orig}` which has an undefined layout"),
                     |diag| {
                         if to_ty_orig.peel_refs() != to_ty.peel_refs() {
-                            diag.note(&format!("the contained type `{to_ty}` has an undefined layout"));
+                            diag.note(&format!(
+                                "the contained type `{to_ty}` has an undefined layout"
+                            ));
                         }
                     },
                 );
                 return true;
-            },
+            }
 
-            (ReducedTy::UnorderedFields(from_ty), ReducedTy::UnorderedFields(to_ty)) if from_ty != to_ty => {
+            (ReducedTy::UnorderedFields(from_ty), ReducedTy::UnorderedFields(to_ty))
+                if from_ty != to_ty =>
+            {
                 let same_adt_did = if let (ty::Adt(from_def, from_subs), ty::Adt(to_def, to_subs))
                         = (from_ty.kind(), to_ty.kind())
                         && from_def == to_def
@@ -126,19 +139,25 @@ pub(super) fn check<'tcx>(
                             ));
                         } else {
                             if from_ty_orig.peel_refs() != from_ty {
-                                diag.note(&format!("the contained type `{from_ty}` has an undefined layout"));
+                                diag.note(&format!(
+                                    "the contained type `{from_ty}` has an undefined layout"
+                                ));
                             }
                             if to_ty_orig.peel_refs() != to_ty {
-                                diag.note(&format!("the contained type `{to_ty}` has an undefined layout"));
+                                diag.note(&format!(
+                                    "the contained type `{to_ty}` has an undefined layout"
+                                ));
                             }
                         }
                     },
                 );
                 return true;
-            },
+            }
             (
                 ReducedTy::UnorderedFields(from_ty),
-                ReducedTy::Other(_) | ReducedTy::OrderedFields(..) | ReducedTy::TypeErasure { raw_ptr_only: true },
+                ReducedTy::Other(_)
+                | ReducedTy::OrderedFields(..)
+                | ReducedTy::TypeErasure { raw_ptr_only: true },
             ) => {
                 span_lint_and_then(
                     cx,
@@ -147,14 +166,18 @@ pub(super) fn check<'tcx>(
                     &format!("transmute from `{from_ty_orig}` which has an undefined layout"),
                     |diag| {
                         if from_ty_orig.peel_refs() != from_ty {
-                            diag.note(&format!("the contained type `{from_ty}` has an undefined layout"));
+                            diag.note(&format!(
+                                "the contained type `{from_ty}` has an undefined layout"
+                            ));
                         }
                     },
                 );
                 return true;
-            },
+            }
             (
-                ReducedTy::Other(_) | ReducedTy::OrderedFields(..) | ReducedTy::TypeErasure { raw_ptr_only: true },
+                ReducedTy::Other(_)
+                | ReducedTy::OrderedFields(..)
+                | ReducedTy::TypeErasure { raw_ptr_only: true },
                 ReducedTy::UnorderedFields(to_ty),
             ) => {
                 span_lint_and_then(
@@ -164,19 +187,25 @@ pub(super) fn check<'tcx>(
                     &format!("transmute into `{to_ty_orig}` which has an undefined layout"),
                     |diag| {
                         if to_ty_orig.peel_refs() != to_ty {
-                            diag.note(&format!("the contained type `{to_ty}` has an undefined layout"));
+                            diag.note(&format!(
+                                "the contained type `{to_ty}` has an undefined layout"
+                            ));
                         }
                     },
                 );
                 return true;
-            },
+            }
             (
-                ReducedTy::OrderedFields(..) | ReducedTy::Other(_) | ReducedTy::TypeErasure { raw_ptr_only: true },
-                ReducedTy::OrderedFields(..) | ReducedTy::Other(_) | ReducedTy::TypeErasure { raw_ptr_only: true },
+                ReducedTy::OrderedFields(..)
+                | ReducedTy::Other(_)
+                | ReducedTy::TypeErasure { raw_ptr_only: true },
+                ReducedTy::OrderedFields(..)
+                | ReducedTy::Other(_)
+                | ReducedTy::TypeErasure { raw_ptr_only: true },
             )
             | (ReducedTy::UnorderedFields(_), ReducedTy::UnorderedFields(_)) => {
                 break;
-            },
+            }
         }
     }
 
@@ -194,42 +223,38 @@ struct ReducedTys<'tcx> {
 }
 
 /// Remove references so long as both types are references.
-fn reduce_refs<'tcx>(cx: &LateContext<'tcx>, mut from_ty: Ty<'tcx>, mut to_ty: Ty<'tcx>) -> ReducedTys<'tcx> {
+fn reduce_refs<'tcx>(
+    cx: &LateContext<'tcx>,
+    mut from_ty: Ty<'tcx>,
+    mut to_ty: Ty<'tcx>,
+) -> ReducedTys<'tcx> {
     let mut from_raw_ptr = false;
     let mut to_raw_ptr = false;
-    let (from_fat_ptr, to_fat_ptr) = loop {
-        break match (from_ty.kind(), to_ty.kind()) {
-            (
-                &(ty::Ref(_, from_sub_ty, _) | ty::RawPtr(TypeAndMut { ty: from_sub_ty, .. })),
-                &(ty::Ref(_, to_sub_ty, _) | ty::RawPtr(TypeAndMut { ty: to_sub_ty, .. })),
-            ) => {
-                from_raw_ptr = matches!(*from_ty.kind(), ty::RawPtr(_));
-                from_ty = from_sub_ty;
-                to_raw_ptr = matches!(*to_ty.kind(), ty::RawPtr(_));
-                to_ty = to_sub_ty;
-                continue;
-            },
-            (&(ty::Ref(_, unsized_ty, _) | ty::RawPtr(TypeAndMut { ty: unsized_ty, .. })), _)
-                if !unsized_ty.is_sized(cx.tcx.at(DUMMY_SP), cx.param_env) =>
-            {
-                (true, false)
-            },
-            (_, &(ty::Ref(_, unsized_ty, _) | ty::RawPtr(TypeAndMut { ty: unsized_ty, .. })))
-                if !unsized_ty.is_sized(cx.tcx.at(DUMMY_SP), cx.param_env) =>
-            {
-                (false, true)
-            },
-            _ => (false, false),
+    let (from_fat_ptr, to_fat_ptr) =
+        loop {
+            break match (from_ty.kind(), to_ty.kind()) {
+                (
+                    &(ty::Ref(_, from_sub_ty, _) | ty::RawPtr(TypeAndMut { ty: from_sub_ty, .. })),
+                    &(ty::Ref(_, to_sub_ty, _) | ty::RawPtr(TypeAndMut { ty: to_sub_ty, .. })),
+                ) => {
+                    from_raw_ptr = matches!(*from_ty.kind(), ty::RawPtr(_));
+                    from_ty = from_sub_ty;
+                    to_raw_ptr = matches!(*to_ty.kind(), ty::RawPtr(_));
+                    to_ty = to_sub_ty;
+                    continue;
+                }
+                (
+                    &(ty::Ref(_, unsized_ty, _) | ty::RawPtr(TypeAndMut { ty: unsized_ty, .. })),
+                    _,
+                ) if !unsized_ty.is_sized(cx.tcx, cx.param_env) => (true, false),
+                (
+                    _,
+                    &(ty::Ref(_, unsized_ty, _) | ty::RawPtr(TypeAndMut { ty: unsized_ty, .. })),
+                ) if !unsized_ty.is_sized(cx.tcx, cx.param_env) => (false, true),
+                _ => (false, false),
+            };
         };
-    };
-    ReducedTys {
-        from_ty,
-        to_ty,
-        from_raw_ptr,
-        to_raw_ptr,
-        from_fat_ptr,
-        to_fat_ptr,
-    }
+    ReducedTys { from_ty, to_ty, from_raw_ptr, to_raw_ptr, from_fat_ptr, to_fat_ptr }
 }
 
 enum ReducedTy<'tcx> {
@@ -252,11 +277,11 @@ fn reduce_ty<'tcx>(cx: &LateContext<'tcx>, mut ty: Ty<'tcx>) -> ReducedTy<'tcx>
         return match *ty.kind() {
             ty::Array(sub_ty, _) if matches!(sub_ty.kind(), ty::Int(_) | ty::Uint(_)) => {
                 ReducedTy::TypeErasure { raw_ptr_only: false }
-            },
+            }
             ty::Array(sub_ty, _) | ty::Slice(sub_ty) => {
                 ty = sub_ty;
                 continue;
-            },
+            }
             ty::Tuple(args) if args.is_empty() => ReducedTy::TypeErasure { raw_ptr_only: false },
             ty::Tuple(args) => {
                 let mut iter = args.iter();
@@ -268,7 +293,7 @@ fn reduce_ty<'tcx>(cx: &LateContext<'tcx>, mut ty: Ty<'tcx>) -> ReducedTy<'tcx>
                     continue;
                 }
                 ReducedTy::UnorderedFields(ty)
-            },
+            }
             ty::Adt(def, substs) if def.is_struct() => {
                 let mut iter = def
                     .non_enum_variant()
@@ -287,10 +312,12 @@ fn reduce_ty<'tcx>(cx: &LateContext<'tcx>, mut ty: Ty<'tcx>) -> ReducedTy<'tcx>
                 } else {
                     ReducedTy::UnorderedFields(ty)
                 }
-            },
-            ty::Adt(def, _) if def.is_enum() && (def.variants().is_empty() || is_c_void(cx, ty)) => {
+            }
+            ty::Adt(def, _)
+                if def.is_enum() && (def.variants().is_empty() || is_c_void(cx, ty)) =>
+            {
                 ReducedTy::TypeErasure { raw_ptr_only: false }
-            },
+            }
             // TODO: Check if the conversion to or from at least one of a union's fields is valid.
             ty::Adt(def, _) if def.is_union() => ReducedTy::TypeErasure { raw_ptr_only: false },
             ty::Foreign(_) | ty::Param(_) => ReducedTy::TypeErasure { raw_ptr_only: false },
@@ -329,7 +356,11 @@ fn same_except_params<'tcx>(subs1: SubstsRef<'tcx>, subs2: SubstsRef<'tcx>) -> b
     for (ty1, ty2) in subs1.types().zip(subs2.types()).filter(|(ty1, ty2)| ty1 != ty2) {
         match (ty1.kind(), ty2.kind()) {
             (ty::Param(_), _) | (_, ty::Param(_)) => (),
-            (ty::Adt(adt1, subs1), ty::Adt(adt2, subs2)) if adt1 == adt2 && same_except_params(subs1, subs2) => (),
+            (ty::Adt(adt1, subs1), ty::Adt(adt2, subs2))
+                if adt1 == adt2 && same_except_params(subs1, subs2) =>
+            {
+                ()
+            }
             _ => return false,
         }
     }
diff --git a/src/tools/clippy/clippy_lints/src/transmute/utils.rs b/src/tools/clippy/clippy_lints/src/transmute/utils.rs
index 2f190e594a8..641cdf5d330 100644
--- a/src/tools/clippy/clippy_lints/src/transmute/utils.rs
+++ b/src/tools/clippy/clippy_lints/src/transmute/utils.rs
@@ -3,6 +3,7 @@ use rustc_hir_typeck::{cast, FnCtxt, Inherited};
 use rustc_lint::LateContext;
 use rustc_middle::ty::{cast::CastKind, Ty};
 use rustc_span::DUMMY_SP;
+use rustc_hir as hir;
 
 // check if the component types of the transmuted collection and the result have different ABI,
 // size or alignment
@@ -56,7 +57,7 @@ fn check_cast<'tcx>(cx: &LateContext<'tcx>, e: &'tcx Expr<'_>, from_ty: Ty<'tcx>
         if let Ok(check) = cast::CastCheck::new(
             &fn_ctxt, e, from_ty, to_ty,
             // We won't show any error to the user, so we don't care what the span is here.
-            DUMMY_SP, DUMMY_SP,
+            DUMMY_SP, DUMMY_SP, hir::Constness::NotConst,
         ) {
             let res = check.do_check(&fn_ctxt);
 
diff --git a/src/tools/clippy/clippy_lints/src/types/mod.rs b/src/tools/clippy/clippy_lints/src/types/mod.rs
index a06d1fffd8b..f6de87b0526 100644
--- a/src/tools/clippy/clippy_lints/src/types/mod.rs
+++ b/src/tools/clippy/clippy_lints/src/types/mod.rs
@@ -319,7 +319,7 @@ impl<'tcx> LateLintPass<'tcx> for Types {
                 false
             };
 
-        let is_exported = cx.access_levels.is_exported(cx.tcx.hir().local_def_id(id));
+        let is_exported = cx.effective_visibilities.is_exported(cx.tcx.hir().local_def_id(id));
 
         self.check_fn_decl(
             cx,
@@ -333,7 +333,7 @@ impl<'tcx> LateLintPass<'tcx> for Types {
     }
 
     fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'_>) {
-        let is_exported = cx.access_levels.is_exported(item.def_id.def_id);
+        let is_exported = cx.effective_visibilities.is_exported(item.owner_id.def_id);
 
         match item.kind {
             ItemKind::Static(ty, _, _) | ItemKind::Const(ty, _) => self.check_ty(
@@ -379,7 +379,7 @@ impl<'tcx> LateLintPass<'tcx> for Types {
     }
 
     fn check_field_def(&mut self, cx: &LateContext<'_>, field: &hir::FieldDef<'_>) {
-        let is_exported = cx.access_levels.is_exported(cx.tcx.hir().local_def_id(field.hir_id));
+        let is_exported = cx.effective_visibilities.is_exported(cx.tcx.hir().local_def_id(field.hir_id));
 
         self.check_ty(
             cx,
@@ -392,7 +392,7 @@ impl<'tcx> LateLintPass<'tcx> for Types {
     }
 
     fn check_trait_item(&mut self, cx: &LateContext<'tcx>, item: &TraitItem<'_>) {
-        let is_exported = cx.access_levels.is_exported(item.def_id.def_id);
+        let is_exported = cx.effective_visibilities.is_exported(item.owner_id.def_id);
 
         let context = CheckTyContext {
             is_exported,
diff --git a/src/tools/clippy/clippy_lints/src/types/redundant_allocation.rs b/src/tools/clippy/clippy_lints/src/types/redundant_allocation.rs
index 7883353e3fe..2b964b64a33 100644
--- a/src/tools/clippy/clippy_lints/src/types/redundant_allocation.rs
+++ b/src/tools/clippy/clippy_lints/src/types/redundant_allocation.rs
@@ -9,7 +9,12 @@ use rustc_span::symbol::sym;
 
 use super::{utils, REDUNDANT_ALLOCATION};
 
-pub(super) fn check(cx: &LateContext<'_>, hir_ty: &hir::Ty<'_>, qpath: &QPath<'_>, def_id: DefId) -> bool {
+pub(super) fn check(
+    cx: &LateContext<'_>,
+    hir_ty: &hir::Ty<'_>,
+    qpath: &QPath<'_>,
+    def_id: DefId,
+) -> bool {
     let mut applicability = Applicability::MaybeIncorrect;
     let outer_sym = if Some(def_id) == cx.tcx.lang_items().owned_box() {
         "Box"
@@ -29,7 +34,12 @@ pub(super) fn check(cx: &LateContext<'_>, hir_ty: &hir::Ty<'_>, qpath: &QPath<'_
             hir_ty.span,
             &format!("usage of `{outer_sym}<{generic_snippet}>`"),
             |diag| {
-                diag.span_suggestion(hir_ty.span, "try", format!("{generic_snippet}"), applicability);
+                diag.span_suggestion(
+                    hir_ty.span,
+                    "try",
+                    format!("{generic_snippet}"),
+                    applicability,
+                );
                 diag.note(&format!(
                     "`{generic_snippet}` is already a pointer, `{outer_sym}<{generic_snippet}>` allocates a pointer on the heap"
                 ));
@@ -55,11 +65,11 @@ pub(super) fn check(cx: &LateContext<'_>, hir_ty: &hir::Ty<'_>, qpath: &QPath<'_
             // Reallocation of a fat pointer causes it to become thin. `hir_ty_to_ty` is safe to use
             // here because `mod.rs` guarantees this lint is only run on types outside of bodies and
             // is not run on locals.
-            if !hir_ty_to_ty(cx.tcx, ty).is_sized(cx.tcx.at(ty.span), cx.param_env) {
+            if !hir_ty_to_ty(cx.tcx, ty).is_sized(cx.tcx, cx.param_env) {
                 return false;
             }
             ty.span
-        },
+        }
         None => return false,
     };
     if inner_sym == outer_sym {
diff --git a/src/tools/clippy/clippy_lints/src/types/vec_box.rs b/src/tools/clippy/clippy_lints/src/types/vec_box.rs
index 6c329d8cdf1..9ad2cb853d3 100644
--- a/src/tools/clippy/clippy_lints/src/types/vec_box.rs
+++ b/src/tools/clippy/clippy_lints/src/types/vec_box.rs
@@ -40,7 +40,7 @@ pub(super) fn check(
             });
             let ty_ty = hir_ty_to_ty(cx.tcx, boxed_ty);
             if !ty_ty.has_escaping_bound_vars();
-            if ty_ty.is_sized(cx.tcx.at(ty.span), cx.param_env);
+            if ty_ty.is_sized(cx.tcx, cx.param_env);
             if let Ok(ty_ty_size) = cx.layout_of(ty_ty).map(|l| l.size.bytes());
             if ty_ty_size <= box_size_threshold;
             then {
diff --git a/src/tools/clippy/clippy_lints/src/unnecessary_wraps.rs b/src/tools/clippy/clippy_lints/src/unnecessary_wraps.rs
index 7211e6864f3..60b46854b4f 100644
--- a/src/tools/clippy/clippy_lints/src/unnecessary_wraps.rs
+++ b/src/tools/clippy/clippy_lints/src/unnecessary_wraps.rs
@@ -83,7 +83,7 @@ impl<'tcx> LateLintPass<'tcx> for UnnecessaryWraps {
         match fn_kind {
             FnKind::ItemFn(..) | FnKind::Method(..) => {
                 let def_id = cx.tcx.hir().local_def_id(hir_id);
-                if self.avoid_breaking_exported_api && cx.access_levels.is_exported(def_id) {
+                if self.avoid_breaking_exported_api && cx.effective_visibilities.is_exported(def_id) {
                     return;
                 }
             },
diff --git a/src/tools/clippy/clippy_lints/src/unused_self.rs b/src/tools/clippy/clippy_lints/src/unused_self.rs
index 713fe06bad4..42bccc7212b 100644
--- a/src/tools/clippy/clippy_lints/src/unused_self.rs
+++ b/src/tools/clippy/clippy_lints/src/unused_self.rs
@@ -56,12 +56,12 @@ impl<'tcx> LateLintPass<'tcx> for UnusedSelf {
         }
         let parent = cx.tcx.hir().get_parent_item(impl_item.hir_id()).def_id;
         let parent_item = cx.tcx.hir().expect_item(parent);
-        let assoc_item = cx.tcx.associated_item(impl_item.def_id);
+        let assoc_item = cx.tcx.associated_item(impl_item.owner_id);
         if_chain! {
             if let ItemKind::Impl(Impl { of_trait: None, .. }) = parent_item.kind;
             if assoc_item.fn_has_self_parameter;
             if let ImplItemKind::Fn(.., body_id) = &impl_item.kind;
-            if !cx.access_levels.is_exported(impl_item.def_id.def_id) || !self.avoid_breaking_exported_api;
+            if !cx.effective_visibilities.is_exported(impl_item.owner_id.def_id) || !self.avoid_breaking_exported_api;
             let body = cx.tcx.hir().body(*body_id);
             if let [self_param, ..] = body.params;
             if !is_local_used(cx, body, self_param.pat.hir_id);
diff --git a/src/tools/clippy/clippy_lints/src/unwrap_in_result.rs b/src/tools/clippy/clippy_lints/src/unwrap_in_result.rs
index a69719b127b..f3611d17434 100644
--- a/src/tools/clippy/clippy_lints/src/unwrap_in_result.rs
+++ b/src/tools/clippy/clippy_lints/src/unwrap_in_result.rs
@@ -76,7 +76,7 @@ impl<'tcx> LateLintPass<'tcx> for UnwrapInResult {
 fn lint_impl_body<'tcx>(cx: &LateContext<'tcx>, impl_span: Span, impl_item: &'tcx hir::ImplItem<'_>) {
     if let ImplItemKind::Fn(_, body_id) = impl_item.kind {
         let body = cx.tcx.hir().body(body_id);
-        let typeck = cx.tcx.typeck(impl_item.def_id.def_id);
+        let typeck = cx.tcx.typeck(impl_item.owner_id.def_id);
         let mut result = Vec::new();
         let _: Option<!> = for_each_expr(body.value, |e| {
             // check for `expect`
diff --git a/src/tools/clippy/clippy_lints/src/upper_case_acronyms.rs b/src/tools/clippy/clippy_lints/src/upper_case_acronyms.rs
index 654ea306793..1d2d3eb12e1 100644
--- a/src/tools/clippy/clippy_lints/src/upper_case_acronyms.rs
+++ b/src/tools/clippy/clippy_lints/src/upper_case_acronyms.rs
@@ -105,7 +105,7 @@ impl LateLintPass<'_> for UpperCaseAcronyms {
     fn check_item(&mut self, cx: &LateContext<'_>, it: &Item<'_>) {
         // do not lint public items or in macros
         if in_external_macro(cx.sess(), it.span)
-            || (self.avoid_breaking_exported_api && cx.access_levels.is_exported(it.def_id.def_id))
+            || (self.avoid_breaking_exported_api && cx.effective_visibilities.is_exported(it.owner_id.def_id))
         {
             return;
         }
diff --git a/src/tools/clippy/clippy_lints/src/use_self.rs b/src/tools/clippy/clippy_lints/src/use_self.rs
index 65f1b546208..c6cdf3f85fc 100644
--- a/src/tools/clippy/clippy_lints/src/use_self.rs
+++ b/src/tools/clippy/clippy_lints/src/use_self.rs
@@ -106,7 +106,7 @@ impl<'tcx> LateLintPass<'tcx> for UseSelf {
             if !is_from_proc_macro(cx, item); // expensive, should be last check
             then {
                 StackItem::Check {
-                    impl_id: item.def_id.def_id,
+                    impl_id: item.owner_id.def_id,
                     in_body: 0,
                     types_to_skip: std::iter::once(self_ty.hir_id).collect(),
                 }
@@ -143,7 +143,7 @@ impl<'tcx> LateLintPass<'tcx> for UseSelf {
                 // trait, not in the impl of the trait.
                 let trait_method = cx
                     .tcx
-                    .associated_item(impl_item.def_id)
+                    .associated_item(impl_item.owner_id)
                     .trait_item_def_id
                     .expect("impl method matches a trait method");
                 let trait_method_sig = cx.tcx.fn_sig(trait_method);
diff --git a/src/tools/clippy/clippy_lints/src/wildcard_imports.rs b/src/tools/clippy/clippy_lints/src/wildcard_imports.rs
index 301eed9a1fb..be98344470b 100644
--- a/src/tools/clippy/clippy_lints/src/wildcard_imports.rs
+++ b/src/tools/clippy/clippy_lints/src/wildcard_imports.rs
@@ -120,14 +120,14 @@ impl LateLintPass<'_> for WildcardImports {
         if is_test_module_or_function(cx.tcx, item) {
             self.test_modules_deep = self.test_modules_deep.saturating_add(1);
         }
-        let module = cx.tcx.parent_module_from_def_id(item.def_id.def_id);
-        if cx.tcx.visibility(item.def_id.def_id) != ty::Visibility::Restricted(module.to_def_id()) {
+        let module = cx.tcx.parent_module_from_def_id(item.owner_id.def_id);
+        if cx.tcx.visibility(item.owner_id.def_id) != ty::Visibility::Restricted(module.to_def_id()) {
             return;
         }
         if_chain! {
             if let ItemKind::Use(use_path, UseKind::Glob) = &item.kind;
             if self.warn_on_all || !self.check_exceptions(item, use_path.segments);
-            let used_imports = cx.tcx.names_imported_by_glob_use(item.def_id.def_id);
+            let used_imports = cx.tcx.names_imported_by_glob_use(item.owner_id.def_id);
             if !used_imports.is_empty(); // Already handled by `unused_imports`
             then {
                 let mut applicability = Applicability::MachineApplicable;
diff --git a/src/tools/clippy/clippy_utils/src/lib.rs b/src/tools/clippy/clippy_utils/src/lib.rs
index 052db3f3a03..3ebfc5e00e1 100644
--- a/src/tools/clippy/clippy_utils/src/lib.rs
+++ b/src/tools/clippy/clippy_utils/src/lib.rs
@@ -2281,7 +2281,7 @@ fn with_test_item_names(tcx: TyCtxt<'_>, module: LocalDefId, f: impl Fn(&[Symbol
         Entry::Vacant(entry) => {
             let mut names = Vec::new();
             for id in tcx.hir().module_items(module) {
-                if matches!(tcx.def_kind(id.def_id), DefKind::Const)
+                if matches!(tcx.def_kind(id.owner_id), DefKind::Const)
                     && let item = tcx.hir().item(id)
                     && let ItemKind::Const(ty, _body) = item.kind {
                     if let TyKind::Path(QPath::Resolved(_, path)) = ty.kind {
diff --git a/src/tools/clippy/clippy_utils/src/ty.rs b/src/tools/clippy/clippy_utils/src/ty.rs
index 3b5a9ba8356..4e024ce4017 100644
--- a/src/tools/clippy/clippy_utils/src/ty.rs
+++ b/src/tools/clippy/clippy_utils/src/ty.rs
@@ -18,7 +18,7 @@ use rustc_middle::ty::{
 };
 use rustc_middle::ty::{GenericArg, GenericArgKind};
 use rustc_span::symbol::Ident;
-use rustc_span::{sym, Span, Symbol, DUMMY_SP};
+use rustc_span::{sym, Span, Symbol};
 use rustc_target::abi::{Size, VariantIdx};
 use rustc_trait_selection::infer::InferCtxtExt;
 use rustc_trait_selection::traits::query::normalize::AtExt;
@@ -28,7 +28,7 @@ use crate::{match_def_path, path_res, paths};
 
 // Checks if the given type implements copy.
 pub fn is_copy<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> bool {
-    ty.is_copy_modulo_regions(cx.tcx.at(DUMMY_SP), cx.param_env)
+    ty.is_copy_modulo_regions(cx.tcx, cx.param_env)
 }
 
 /// This checks whether a given type is known to implement Debug.
diff --git a/src/tools/compiletest/src/common.rs b/src/tools/compiletest/src/common.rs
index b9ac6c9f364..0260f684838 100644
--- a/src/tools/compiletest/src/common.rs
+++ b/src/tools/compiletest/src/common.rs
@@ -269,10 +269,10 @@ pub struct Config {
     pub runtool: Option<String>,
 
     /// Flags to pass to the compiler when building for the host
-    pub host_rustcflags: Option<String>,
+    pub host_rustcflags: Vec<String>,
 
     /// Flags to pass to the compiler when building for the target
-    pub target_rustcflags: Option<String>,
+    pub target_rustcflags: Vec<String>,
 
     /// Whether tests should be optimized by default. Individual test-suites and test files may
     /// override this setting.
@@ -457,12 +457,12 @@ pub enum Endian {
 }
 
 impl TargetCfg {
-    fn new(rustc_path: &Path, target: &str, target_rustcflags: &Option<String>) -> TargetCfg {
+    fn new(rustc_path: &Path, target: &str, target_rustcflags: &Vec<String>) -> TargetCfg {
         let output = match Command::new(rustc_path)
             .arg("--print=cfg")
             .arg("--target")
             .arg(target)
-            .args(target_rustcflags.into_iter().map(|s| s.split_whitespace()).flatten())
+            .args(target_rustcflags)
             .output()
         {
             Ok(output) => output,
diff --git a/src/tools/compiletest/src/main.rs b/src/tools/compiletest/src/main.rs
index a8cf6623f35..19cf54780c1 100644
--- a/src/tools/compiletest/src/main.rs
+++ b/src/tools/compiletest/src/main.rs
@@ -254,8 +254,8 @@ pub fn parse_config(args: Vec<String>) -> Config {
         }),
         logfile: matches.opt_str("logfile").map(|s| PathBuf::from(&s)),
         runtool: matches.opt_str("runtool"),
-        host_rustcflags: Some(matches.opt_strs("host-rustcflags").join(" ")),
-        target_rustcflags: Some(matches.opt_strs("target-rustcflags").join(" ")),
+        host_rustcflags: matches.opt_strs("host-rustcflags"),
+        target_rustcflags: matches.opt_strs("target-rustcflags"),
         optimize_tests: matches.opt_present("optimize-tests"),
         target,
         host: opt_str2(matches.opt_str("host")),
@@ -322,8 +322,8 @@ pub fn log_config(config: &Config) {
         format!("force_pass_mode: {}", opt_str(&config.force_pass_mode.map(|m| format!("{}", m))),),
     );
     logv(c, format!("runtool: {}", opt_str(&config.runtool)));
-    logv(c, format!("host-rustcflags: {}", opt_str(&config.host_rustcflags)));
-    logv(c, format!("target-rustcflags: {}", opt_str(&config.target_rustcflags)));
+    logv(c, format!("host-rustcflags: {:?}", config.host_rustcflags));
+    logv(c, format!("target-rustcflags: {:?}", config.target_rustcflags));
     logv(c, format!("target: {}", config.target));
     logv(c, format!("host: {}", config.host));
     logv(c, format!("android-cross-path: {:?}", config.android_cross_path.display()));
diff --git a/src/tools/compiletest/src/runtest.rs b/src/tools/compiletest/src/runtest.rs
index 8f289876f73..8af5f1da694 100644
--- a/src/tools/compiletest/src/runtest.rs
+++ b/src/tools/compiletest/src/runtest.rs
@@ -558,10 +558,7 @@ impl<'test> TestCx<'test> {
             .arg(&aux_dir)
             .args(&self.props.compile_flags)
             .envs(self.props.rustc_env.clone());
-        self.maybe_add_external_args(
-            &mut rustc,
-            self.split_maybe_args(&self.config.target_rustcflags),
-        );
+        self.maybe_add_external_args(&mut rustc, &self.config.target_rustcflags);
 
         let src = match read_from {
             ReadFrom::Stdin(src) => Some(src),
@@ -629,10 +626,7 @@ impl<'test> TestCx<'test> {
             .arg("-L")
             .arg(aux_dir);
         self.set_revision_flags(&mut rustc);
-        self.maybe_add_external_args(
-            &mut rustc,
-            self.split_maybe_args(&self.config.target_rustcflags),
-        );
+        self.maybe_add_external_args(&mut rustc, &self.config.target_rustcflags);
         rustc.args(&self.props.compile_flags);
 
         self.compose_and_run_compiler(rustc, Some(src))
@@ -1186,23 +1180,14 @@ impl<'test> TestCx<'test> {
         ProcRes { status, stdout: out, stderr: err, cmdline: format!("{:?}", cmd) }
     }
 
-    fn cleanup_debug_info_options(&self, options: &Option<String>) -> Option<String> {
-        if options.is_none() {
-            return None;
-        }
-
+    fn cleanup_debug_info_options(&self, options: &Vec<String>) -> Vec<String> {
         // Remove options that are either unwanted (-O) or may lead to duplicates due to RUSTFLAGS.
         let options_to_remove = ["-O".to_owned(), "-g".to_owned(), "--debuginfo".to_owned()];
-        let new_options = self
-            .split_maybe_args(options)
-            .into_iter()
-            .filter(|x| !options_to_remove.contains(x))
-            .collect::<Vec<String>>();
 
-        Some(new_options.join(" "))
+        options.iter().filter(|x| !options_to_remove.contains(x)).map(|x| x.clone()).collect()
     }
 
-    fn maybe_add_external_args(&self, cmd: &mut Command, args: Vec<String>) {
+    fn maybe_add_external_args(&self, cmd: &mut Command, args: &Vec<String>) {
         // Filter out the arguments that should not be added by runtest here.
         //
         // Notable use-cases are: do not add our optimisation flag if
@@ -2035,15 +2020,9 @@ impl<'test> TestCx<'test> {
         }
 
         if self.props.force_host {
-            self.maybe_add_external_args(
-                &mut rustc,
-                self.split_maybe_args(&self.config.host_rustcflags),
-            );
+            self.maybe_add_external_args(&mut rustc, &self.config.host_rustcflags);
         } else {
-            self.maybe_add_external_args(
-                &mut rustc,
-                self.split_maybe_args(&self.config.target_rustcflags),
-            );
+            self.maybe_add_external_args(&mut rustc, &self.config.target_rustcflags);
             if !is_rustdoc {
                 if let Some(ref linker) = self.config.linker {
                     rustc.arg(format!("-Clinker={}", linker));
diff --git a/src/tools/miri/miri b/src/tools/miri/miri
index 52902410a6b..a0593deb08a 100755
--- a/src/tools/miri/miri
+++ b/src/tools/miri/miri
@@ -121,7 +121,7 @@ toolchain)
 rustc-pull)
     cd "$MIRIDIR"
     git fetch http://localhost:8000/rust-lang/rust.git$JOSH_FILTER.git master
-    git merge FETCH_HEAD
+    git merge FETCH_HEAD --no-ff -m "Merge from rustc"
     exit 0
     ;;
 rustc-push)
diff --git a/src/tools/miri/rust-version b/src/tools/miri/rust-version
index e582bf35356..13492d183c9 100644
--- a/src/tools/miri/rust-version
+++ b/src/tools/miri/rust-version
@@ -1 +1 @@
-607878d069267e1402ad792c9331b426e4c6d0f9
+b03502b35d111bef0399a66ab3cc765f0802e8ba
diff --git a/src/tools/miri/src/stacked_borrows/mod.rs b/src/tools/miri/src/stacked_borrows/mod.rs
index cc27b71eb56..5ec787dd441 100644
--- a/src/tools/miri/src/stacked_borrows/mod.rs
+++ b/src/tools/miri/src/stacked_borrows/mod.rs
@@ -16,7 +16,6 @@ use rustc_middle::ty::{
     layout::{HasParamEnv, LayoutOf},
     Ty,
 };
-use rustc_span::DUMMY_SP;
 use rustc_target::abi::Abi;
 use rustc_target::abi::Size;
 use smallvec::SmallVec;
@@ -714,12 +713,12 @@ trait EvalContextPrivExt<'mir: 'ecx, 'tcx: 'mir, 'ecx>: crate::MiriInterpCxExt<'
                 let mut kind_str = format!("{kind}");
                 match kind {
                     RefKind::Unique { two_phase: false }
-                        if !ty.is_unpin(this.tcx.at(DUMMY_SP), this.param_env()) =>
+                        if !ty.is_unpin(*this.tcx, this.param_env()) =>
                     {
                         write!(kind_str, " (!Unpin pointee type {ty})").unwrap()
                     },
                     RefKind::Shared
-                        if !ty.is_freeze(this.tcx.at(DUMMY_SP), this.param_env()) =>
+                        if !ty.is_freeze(*this.tcx, this.param_env()) =>
                     {
                         write!(kind_str, " (!Freeze pointee type {ty})").unwrap()
                     },
@@ -834,7 +833,7 @@ trait EvalContextPrivExt<'mir: 'ecx, 'tcx: 'mir, 'ecx>: crate::MiriInterpCxExt<'
         // There could be existing unique pointers reborrowed from them that should remain valid!
         let perm = match kind {
             RefKind::Unique { two_phase: false }
-                if place.layout.ty.is_unpin(this.tcx.at(DUMMY_SP), this.param_env()) =>
+                if place.layout.ty.is_unpin(*this.tcx, this.param_env()) =>
             {
                 // Only if the type is unpin do we actually enforce uniqueness
                 Permission::Unique
diff --git a/src/tools/rust-analyzer/.github/workflows/publish.yml b/src/tools/rust-analyzer/.github/workflows/publish.yml
index a4497f49e3c..73e62ab32c6 100644
--- a/src/tools/rust-analyzer/.github/workflows/publish.yml
+++ b/src/tools/rust-analyzer/.github/workflows/publish.yml
@@ -2,8 +2,8 @@ name: publish
 on:
   workflow_dispatch: # We can add version input when 1.0 is released and scheduled releases are removed
 
-#   schedule:
-#     - cron: "0 0 * * *" # midnight UTC
+  #   schedule:
+  #     - cron: "0 0 * * *" # midnight UTC
 
   push:
     branches:
@@ -50,5 +50,7 @@ jobs:
           cargo workspaces rename --from test-utils test_utils
           cargo workspaces rename --from text-edit text_edit
           cargo workspaces rename ra_ap_%n
+          # Remove library crates from the workspaces so we don't auto-publish them as well
+          sed -i 's/ "lib\/\*",//' ./Cargo.toml
           find crates/rust-analyzer -type f -name '*.rs' -exec sed -i 's/rust_analyzer/ra_ap_rust_analyzer/g' {} +
           cargo workspaces publish --yes --force '*' --exact --no-git-commit --allow-dirty --skip-published custom 0.0.$PATCH
diff --git a/src/tools/rust-analyzer/crates/flycheck/src/lib.rs b/src/tools/rust-analyzer/crates/flycheck/src/lib.rs
index e8c63d410aa..73c3a48b4c5 100644
--- a/src/tools/rust-analyzer/crates/flycheck/src/lib.rs
+++ b/src/tools/rust-analyzer/crates/flycheck/src/lib.rs
@@ -21,6 +21,20 @@ pub use cargo_metadata::diagnostic::{
     DiagnosticSpanMacroExpansion,
 };
 
+#[derive(Copy, Clone, Debug, Default, PartialEq, Eq)]
+pub enum InvocationStrategy {
+    Once,
+    #[default]
+    PerWorkspace,
+}
+
+#[derive(Clone, Debug, Default, PartialEq, Eq)]
+pub enum InvocationLocation {
+    Root(AbsPathBuf),
+    #[default]
+    Workspace,
+}
+
 #[derive(Clone, Debug, PartialEq, Eq)]
 pub enum FlycheckConfig {
     CargoCommand {
@@ -37,6 +51,8 @@ pub enum FlycheckConfig {
         command: String,
         args: Vec<String>,
         extra_env: FxHashMap<String, String>,
+        invocation_strategy: InvocationStrategy,
+        invocation_location: InvocationLocation,
     },
 }
 
@@ -136,11 +152,15 @@ enum Restart {
     No,
 }
 
+/// A [`FlycheckActor`] is a single check instance of a workspace.
 struct FlycheckActor {
+    /// The workspace id of this flycheck instance.
     id: usize,
     sender: Box<dyn Fn(Message) + Send>,
     config: FlycheckConfig,
-    workspace_root: AbsPathBuf,
+    /// Either the workspace root of the workspace we are flychecking,
+    /// or the project root of the project.
+    root: AbsPathBuf,
     /// CargoHandle exists to wrap around the communication needed to be able to
     /// run `cargo check` without blocking. Currently the Rust standard library
     /// doesn't provide a way to read sub-process output without blocking, so we
@@ -162,11 +182,13 @@ impl FlycheckActor {
         workspace_root: AbsPathBuf,
     ) -> FlycheckActor {
         tracing::info!(%id, ?workspace_root, "Spawning flycheck");
-        FlycheckActor { id, sender, config, workspace_root, cargo_handle: None }
+        FlycheckActor { id, sender, config, root: workspace_root, cargo_handle: None }
     }
-    fn progress(&self, progress: Progress) {
+
+    fn report_progress(&self, progress: Progress) {
         self.send(Message::Progress { id: self.id, progress });
     }
+
     fn next_event(&self, inbox: &Receiver<Restart>) -> Option<Event> {
         let check_chan = self.cargo_handle.as_ref().map(|cargo| &cargo.receiver);
         if let Ok(msg) = inbox.try_recv() {
@@ -178,6 +200,7 @@ impl FlycheckActor {
             recv(check_chan.unwrap_or(&never())) -> msg => Some(Event::CheckEvent(msg.ok())),
         }
     }
+
     fn run(mut self, inbox: Receiver<Restart>) {
         'event: while let Some(event) = self.next_event(&inbox) {
             match event {
@@ -203,10 +226,10 @@ impl FlycheckActor {
                                 "did  restart flycheck"
                             );
                             self.cargo_handle = Some(cargo_handle);
-                            self.progress(Progress::DidStart);
+                            self.report_progress(Progress::DidStart);
                         }
                         Err(error) => {
-                            self.progress(Progress::DidFailToRestart(format!(
+                            self.report_progress(Progress::DidFailToRestart(format!(
                                 "Failed to run the following command: {:?} error={}",
                                 self.check_command(),
                                 error
@@ -226,17 +249,17 @@ impl FlycheckActor {
                             self.check_command()
                         );
                     }
-                    self.progress(Progress::DidFinish(res));
+                    self.report_progress(Progress::DidFinish(res));
                 }
                 Event::CheckEvent(Some(message)) => match message {
                     CargoMessage::CompilerArtifact(msg) => {
-                        self.progress(Progress::DidCheckCrate(msg.target.name));
+                        self.report_progress(Progress::DidCheckCrate(msg.target.name));
                     }
 
                     CargoMessage::Diagnostic(msg) => {
                         self.send(Message::AddDiagnostic {
                             id: self.id,
-                            workspace_root: self.workspace_root.clone(),
+                            workspace_root: self.root.clone(),
                             diagnostic: msg,
                         });
                     }
@@ -254,12 +277,12 @@ impl FlycheckActor {
                 "did  cancel flycheck"
             );
             cargo_handle.cancel();
-            self.progress(Progress::DidCancel);
+            self.report_progress(Progress::DidCancel);
         }
     }
 
     fn check_command(&self) -> Command {
-        let mut cmd = match &self.config {
+        let (mut cmd, args) = match &self.config {
             FlycheckConfig::CargoCommand {
                 command,
                 target_triple,
@@ -272,9 +295,7 @@ impl FlycheckActor {
             } => {
                 let mut cmd = Command::new(toolchain::cargo());
                 cmd.arg(command);
-                cmd.current_dir(&self.workspace_root);
-                cmd.args(&["--workspace", "--message-format=json", "--manifest-path"])
-                    .arg(self.workspace_root.join("Cargo.toml").as_os_str());
+                cmd.args(&["--workspace", "--message-format=json"]);
 
                 if let Some(target) = target_triple {
                     cmd.args(&["--target", target.as_str()]);
@@ -293,18 +314,41 @@ impl FlycheckActor {
                         cmd.arg(features.join(" "));
                     }
                 }
-                cmd.args(extra_args);
                 cmd.envs(extra_env);
-                cmd
+                (cmd, extra_args)
             }
-            FlycheckConfig::CustomCommand { command, args, extra_env } => {
+            FlycheckConfig::CustomCommand {
+                command,
+                args,
+                extra_env,
+                invocation_strategy,
+                invocation_location,
+            } => {
                 let mut cmd = Command::new(command);
-                cmd.args(args);
                 cmd.envs(extra_env);
-                cmd
+
+                match invocation_location {
+                    InvocationLocation::Workspace => {
+                        match invocation_strategy {
+                            InvocationStrategy::Once => {
+                                cmd.current_dir(&self.root);
+                            }
+                            InvocationStrategy::PerWorkspace => {
+                                // FIXME: cmd.current_dir(&affected_workspace);
+                                cmd.current_dir(&self.root);
+                            }
+                        }
+                    }
+                    InvocationLocation::Root(root) => {
+                        cmd.current_dir(root);
+                    }
+                }
+
+                (cmd, args)
             }
         };
-        cmd.current_dir(&self.workspace_root);
+
+        cmd.args(args);
         cmd
     }
 
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/macro_expansion_tests/builtin_derive_macro.rs b/src/tools/rust-analyzer/crates/hir-def/src/macro_expansion_tests/builtin_derive_macro.rs
index 6819e9114a0..fafcde25ae7 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/macro_expansion_tests/builtin_derive_macro.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/macro_expansion_tests/builtin_derive_macro.rs
@@ -12,11 +12,11 @@ fn test_copy_expand_simple() {
 #[derive(Copy)]
 struct Foo;
 "#,
-        expect![[r##"
+        expect![[r#"
 #[derive(Copy)]
 struct Foo;
 
-impl < > core::marker::Copy for Foo< > {}"##]],
+impl < > core::marker::Copy for Foo< > {}"#]],
     );
 }
 
@@ -33,7 +33,7 @@ macro Copy {}
 #[derive(Copy)]
 struct Foo;
 "#,
-        expect![[r##"
+        expect![[r#"
 #[rustc_builtin_macro]
 macro derive {}
 #[rustc_builtin_macro]
@@ -41,7 +41,7 @@ macro Copy {}
 #[derive(Copy)]
 struct Foo;
 
-impl < > crate ::marker::Copy for Foo< > {}"##]],
+impl < > crate ::marker::Copy for Foo< > {}"#]],
     );
 }
 
@@ -53,11 +53,11 @@ fn test_copy_expand_with_type_params() {
 #[derive(Copy)]
 struct Foo<A, B>;
 "#,
-        expect![[r##"
+        expect![[r#"
 #[derive(Copy)]
 struct Foo<A, B>;
 
-impl <T0: core::marker::Copy, T1: core::marker::Copy> core::marker::Copy for Foo<T0, T1> {}"##]],
+impl <T0: core::marker::Copy, T1: core::marker::Copy, > core::marker::Copy for Foo<T0, T1, > {}"#]],
     );
 }
 
@@ -70,11 +70,11 @@ fn test_copy_expand_with_lifetimes() {
 #[derive(Copy)]
 struct Foo<A, B, 'a, 'b>;
 "#,
-        expect![[r##"
+        expect![[r#"
 #[derive(Copy)]
 struct Foo<A, B, 'a, 'b>;
 
-impl <T0: core::marker::Copy, T1: core::marker::Copy> core::marker::Copy for Foo<T0, T1> {}"##]],
+impl <T0: core::marker::Copy, T1: core::marker::Copy, > core::marker::Copy for Foo<T0, T1, > {}"#]],
     );
 }
 
@@ -86,10 +86,26 @@ fn test_clone_expand() {
 #[derive(Clone)]
 struct Foo<A, B>;
 "#,
-        expect![[r##"
+        expect![[r#"
 #[derive(Clone)]
 struct Foo<A, B>;
 
-impl <T0: core::clone::Clone, T1: core::clone::Clone> core::clone::Clone for Foo<T0, T1> {}"##]],
+impl <T0: core::clone::Clone, T1: core::clone::Clone, > core::clone::Clone for Foo<T0, T1, > {}"#]],
+    );
+}
+
+#[test]
+fn test_clone_expand_with_const_generics() {
+    check(
+        r#"
+//- minicore: derive, clone
+#[derive(Clone)]
+struct Foo<const X: usize, T>(u32);
+"#,
+        expect![[r#"
+#[derive(Clone)]
+struct Foo<const X: usize, T>(u32);
+
+impl <const T0: usize, T1: core::clone::Clone, > core::clone::Clone for Foo<T0, T1, > {}"#]],
     );
 }
diff --git a/src/tools/rust-analyzer/crates/hir-expand/src/builtin_derive_macro.rs b/src/tools/rust-analyzer/crates/hir-expand/src/builtin_derive_macro.rs
index 79989bc2e38..8966047c9b2 100644
--- a/src/tools/rust-analyzer/crates/hir-expand/src/builtin_derive_macro.rs
+++ b/src/tools/rust-analyzer/crates/hir-expand/src/builtin_derive_macro.rs
@@ -60,7 +60,8 @@ pub fn find_builtin_derive(ident: &name::Name) -> Option<BuiltinDeriveExpander>
 
 struct BasicAdtInfo {
     name: tt::Ident,
-    type_or_const_params: usize,
+    /// `Some(ty)` if it's a const param of type `ty`, `None` if it's a type param.
+    param_types: Vec<Option<tt::Subtree>>,
 }
 
 fn parse_adt(tt: &tt::Subtree) -> Result<BasicAdtInfo, ExpandError> {
@@ -92,50 +93,22 @@ fn parse_adt(tt: &tt::Subtree) -> Result<BasicAdtInfo, ExpandError> {
     let name_token_id =
         token_map.token_by_range(name.syntax().text_range()).unwrap_or_else(TokenId::unspecified);
     let name_token = tt::Ident { id: name_token_id, text: name.text().into() };
-    let type_or_const_params =
-        params.map_or(0, |type_param_list| type_param_list.type_or_const_params().count());
-    Ok(BasicAdtInfo { name: name_token, type_or_const_params })
-}
-
-fn make_type_args(n: usize, bound: Vec<tt::TokenTree>) -> Vec<tt::TokenTree> {
-    let mut result = Vec::<tt::TokenTree>::with_capacity(n * 2);
-    result.push(
-        tt::Leaf::Punct(tt::Punct {
-            char: '<',
-            spacing: tt::Spacing::Alone,
-            id: tt::TokenId::unspecified(),
-        })
-        .into(),
-    );
-    for i in 0..n {
-        if i > 0 {
-            result.push(
-                tt::Leaf::Punct(tt::Punct {
-                    char: ',',
-                    spacing: tt::Spacing::Alone,
-                    id: tt::TokenId::unspecified(),
-                })
-                .into(),
-            );
-        }
-        result.push(
-            tt::Leaf::Ident(tt::Ident {
-                id: tt::TokenId::unspecified(),
-                text: format!("T{}", i).into(),
-            })
-            .into(),
-        );
-        result.extend(bound.iter().cloned());
-    }
-    result.push(
-        tt::Leaf::Punct(tt::Punct {
-            char: '>',
-            spacing: tt::Spacing::Alone,
-            id: tt::TokenId::unspecified(),
+    let param_types = params
+        .into_iter()
+        .flat_map(|param_list| param_list.type_or_const_params())
+        .map(|param| {
+            if let ast::TypeOrConstParam::Const(param) = param {
+                let ty = param
+                    .ty()
+                    .map(|ty| mbe::syntax_node_to_token_tree(ty.syntax()).0)
+                    .unwrap_or_default();
+                Some(ty)
+            } else {
+                None
+            }
         })
-        .into(),
-    );
-    result
+        .collect();
+    Ok(BasicAdtInfo { name: name_token, param_types })
 }
 
 fn expand_simple_derive(tt: &tt::Subtree, trait_path: tt::Subtree) -> ExpandResult<tt::Subtree> {
@@ -143,14 +116,27 @@ fn expand_simple_derive(tt: &tt::Subtree, trait_path: tt::Subtree) -> ExpandResu
         Ok(info) => info,
         Err(e) => return ExpandResult::only_err(e),
     };
+    let (params, args): (Vec<_>, Vec<_>) = info
+        .param_types
+        .into_iter()
+        .enumerate()
+        .map(|(idx, param_ty)| {
+            let ident = tt::Leaf::Ident(tt::Ident {
+                id: tt::TokenId::unspecified(),
+                text: format!("T{idx}").into(),
+            });
+            let ident_ = ident.clone();
+            if let Some(ty) = param_ty {
+                (quote! { const #ident : #ty , }, quote! { #ident_ , })
+            } else {
+                let bound = trait_path.clone();
+                (quote! { #ident : #bound , }, quote! { #ident_ , })
+            }
+        })
+        .unzip();
     let name = info.name;
-    let trait_path_clone = trait_path.token_trees.clone();
-    let bound = (quote! { : ##trait_path_clone }).token_trees;
-    let type_params = make_type_args(info.type_or_const_params, bound);
-    let type_args = make_type_args(info.type_or_const_params, Vec::new());
-    let trait_path = trait_path.token_trees;
     let expanded = quote! {
-        impl ##type_params ##trait_path for #name ##type_args {}
+        impl < ##params > #trait_path for #name < ##args > {}
     };
     ExpandResult::ok(expanded)
 }
diff --git a/src/tools/rust-analyzer/crates/hir-expand/src/mod_path.rs b/src/tools/rust-analyzer/crates/hir-expand/src/mod_path.rs
index 68413df420c..d7586d129b7 100644
--- a/src/tools/rust-analyzer/crates/hir-expand/src/mod_path.rs
+++ b/src/tools/rust-analyzer/crates/hir-expand/src/mod_path.rs
@@ -259,7 +259,6 @@ macro_rules! __known_path {
     (core::future::Future) => {};
     (core::future::IntoFuture) => {};
     (core::ops::Try) => {};
-    (core::ops::FromResidual) => {};
     ($path:path) => {
         compile_error!("Please register your known path in the path module")
     };
diff --git a/src/tools/rust-analyzer/crates/hir-expand/src/name.rs b/src/tools/rust-analyzer/crates/hir-expand/src/name.rs
index 8a735b965ab..2679a1c3602 100644
--- a/src/tools/rust-analyzer/crates/hir-expand/src/name.rs
+++ b/src/tools/rust-analyzer/crates/hir-expand/src/name.rs
@@ -279,8 +279,6 @@ pub mod known {
         RangeToInclusive,
         RangeTo,
         Range,
-        Residual,
-        FromResidual,
         Neg,
         Not,
         None,
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/infer.rs b/src/tools/rust-analyzer/crates/hir-ty/src/infer.rs
index 6a5c4966f7b..0efff651cc1 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/infer.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/infer.rs
@@ -190,9 +190,7 @@ pub(crate) type InferResult<T> = Result<InferOk<T>, TypeError>;
 pub enum InferenceDiagnostic {
     NoSuchField { expr: ExprId },
     BreakOutsideOfLoop { expr: ExprId, is_break: bool },
-    IncorrectTryTarget { expr: ExprId },
     MismatchedArgCount { call_expr: ExprId, expected: usize, found: usize },
-    DoesNotImplement { expr: ExprId, trait_: TraitId, ty: Ty },
 }
 
 /// A mismatch between an expected and an inferred type.
@@ -907,6 +905,17 @@ impl<'a> InferenceContext<'a> {
         self.db.trait_data(trait_).associated_type_by_name(&name![Item])
     }
 
+    fn resolve_ops_try_ok(&self) -> Option<TypeAliasId> {
+        // FIXME resolve via lang_item once try v2 is stable
+        let path = path![core::ops::Try];
+        let trait_ = self.resolver.resolve_known_trait(self.db.upcast(), &path)?;
+        let trait_data = self.db.trait_data(trait_);
+        trait_data
+            // FIXME remove once try v2 is stable
+            .associated_type_by_name(&name![Ok])
+            .or_else(|| trait_data.associated_type_by_name(&name![Output]))
+    }
+
     fn resolve_ops_neg_output(&self) -> Option<TypeAliasId> {
         let trait_ = self.resolve_lang_item(name![neg])?.as_trait()?;
         self.db.trait_data(trait_).associated_type_by_name(&name![Output])
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/infer/expr.rs b/src/tools/rust-analyzer/crates/hir-ty/src/infer/expr.rs
index 59ab50d0717..f56108b26c4 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/infer/expr.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/infer/expr.rs
@@ -19,24 +19,24 @@ use hir_def::{
     resolver::resolver_for_expr,
     ConstParamId, FieldId, ItemContainerId, Lookup,
 };
-use hir_expand::{name, name::Name};
+use hir_expand::name::Name;
 use stdx::always;
 use syntax::ast::RangeOp;
 
 use crate::{
     autoderef::{self, Autoderef},
     consteval,
-    infer::{coerce::CoerceMany, find_continuable, path, BreakableKind},
+    infer::{coerce::CoerceMany, find_continuable, BreakableKind},
     lower::{
         const_or_path_to_chalk, generic_arg_to_chalk, lower_to_chalk_mutability, ParamLoweringMode,
     },
     mapping::{from_chalk, ToChalk},
     method_resolution::{self, lang_names_for_bin_op, VisibleFromModule},
     primitive::{self, UintTy},
-    static_lifetime, to_assoc_type_id, to_chalk_trait_id,
+    static_lifetime, to_chalk_trait_id,
     utils::{generics, Generics},
-    AdtId, AliasEq, AliasTy, Binders, CallableDefId, FnPointer, FnSig, FnSubst, Interner,
-    ProjectionTy, Rawness, Scalar, Substitution, TraitRef, Ty, TyBuilder, TyExt, TyKind,
+    AdtId, Binders, CallableDefId, FnPointer, FnSig, FnSubst, Interner, Rawness, Scalar,
+    Substitution, TraitRef, Ty, TyBuilder, TyExt, TyKind,
 };
 
 use super::{
@@ -564,29 +564,9 @@ impl<'a> InferenceContext<'a> {
                 let inner_ty = self.infer_expr_inner(*expr, &Expectation::none());
                 self.resolve_associated_type(inner_ty, self.resolve_future_future_output())
             }
-            &Expr::Try { expr } => {
-                let inner_ty = self.infer_expr_inner(expr, &Expectation::none());
-                match self.resolve_try_impl_for(inner_ty.clone()) {
-                    Some((_, Some((output, residual)))) => {
-                        if let Some((_trait, false)) =
-                            self.implements_from_residual(self.return_ty.clone(), residual)
-                        {
-                            self.push_diagnostic(InferenceDiagnostic::IncorrectTryTarget {
-                                expr: tgt_expr,
-                            });
-                        }
-                        output
-                    }
-                    Some((trait_, None)) => {
-                        self.push_diagnostic(InferenceDiagnostic::DoesNotImplement {
-                            expr,
-                            trait_,
-                            ty: inner_ty,
-                        });
-                        self.err_ty()
-                    }
-                    None => self.err_ty(),
-                }
+            Expr::Try { expr } => {
+                let inner_ty = self.infer_expr_inner(*expr, &Expectation::none());
+                self.resolve_associated_type(inner_ty, self.resolve_ops_try_ok())
             }
             Expr::Cast { expr, type_ref } => {
                 // FIXME: propagate the "castable to" expectation (and find a test case that shows this is necessary)
@@ -1550,67 +1530,4 @@ impl<'a> InferenceContext<'a> {
         let ctx = self.breakables.pop().expect("breakable stack broken");
         (ctx.may_break.then(|| ctx.coerce.complete()), res)
     }
-
-    /// Check whether `ty` implements `FromResidual<r>`
-    fn implements_from_residual(&mut self, ty: Ty, r: Ty) -> Option<(hir_def::TraitId, bool)> {
-        let from_residual_trait = self
-            .resolver
-            .resolve_known_trait(self.db.upcast(), &(super::path![core::ops::FromResidual]))?;
-        let r = GenericArgData::Ty(r).intern(Interner);
-        let b = TyBuilder::trait_ref(self.db, from_residual_trait);
-        if b.remaining() != 2 {
-            return Some((from_residual_trait, false));
-        }
-        let trait_ref = b.push(ty).push(r).build();
-        Some((from_residual_trait, self.table.try_obligation(trait_ref.cast(Interner)).is_some()))
-    }
-
-    fn resolve_try_impl_for(&mut self, ty: Ty) -> Option<(hir_def::TraitId, Option<(Ty, Ty)>)> {
-        let path = path![core::ops::Try];
-        let trait_ = self.resolver.resolve_known_trait(self.db.upcast(), &path)?;
-
-        let trait_ref = TyBuilder::trait_ref(self.db, trait_).push(ty).build();
-        let substitution = trait_ref.substitution.clone();
-        self.push_obligation(trait_ref.clone().cast(Interner));
-
-        let trait_data = self.db.trait_data(trait_);
-        let output = trait_data.associated_type_by_name(&name![Output]);
-        let residual = trait_data.associated_type_by_name(&name![Residual]);
-
-        let output_ty = match output {
-            Some(output) => {
-                let output_ty = self.table.new_type_var();
-                let alias_eq = AliasEq {
-                    alias: AliasTy::Projection(ProjectionTy {
-                        associated_ty_id: to_assoc_type_id(output),
-                        substitution: substitution.clone(),
-                    }),
-                    ty: output_ty.clone(),
-                };
-                self.push_obligation(alias_eq.cast(Interner));
-                output_ty
-            }
-            None => self.err_ty(),
-        };
-        let residual_ty = match residual {
-            Some(residual) => {
-                let residual_ty = self.table.new_type_var();
-                let alias_eq = AliasEq {
-                    alias: AliasTy::Projection(ProjectionTy {
-                        associated_ty_id: to_assoc_type_id(residual),
-                        substitution,
-                    }),
-                    ty: residual_ty.clone(),
-                };
-                self.push_obligation(alias_eq.cast(Interner));
-                residual_ty
-            }
-            None => self.err_ty(),
-        };
-        // FIXME: We are doing the work twice here I think?
-        Some((
-            trait_,
-            self.table.try_obligation(trait_ref.cast(Interner)).map(|_| (output_ty, residual_ty)),
-        ))
-    }
 }
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/method_resolution.rs b/src/tools/rust-analyzer/crates/hir-ty/src/method_resolution.rs
index a79efeb6daa..3a1a3f4fdeb 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/method_resolution.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/method_resolution.rs
@@ -1111,24 +1111,6 @@ pub fn resolve_indexing_op(
     }
     None
 }
-/// Returns the receiver type for the try branch trait call.
-pub fn resolve_branch_op(
-    db: &dyn HirDatabase,
-    env: Arc<TraitEnvironment>,
-    ty: Canonical<Ty>,
-    try_trait: TraitId,
-) -> Option<ReceiverAdjustments> {
-    let mut table = InferenceTable::new(db, env.clone());
-    let ty = table.instantiate_canonical(ty);
-    let (deref_chain, adj) = autoderef_method_receiver(&mut table, ty);
-    for (ty, adj) in deref_chain.into_iter().zip(adj) {
-        let goal = generic_implements_goal(db, env.clone(), try_trait, &ty);
-        if db.trait_solve(env.krate, goal.cast(Interner)).is_some() {
-            return Some(adj);
-        }
-    }
-    None
-}
 
 macro_rules! check_that {
     ($cond:expr) => {
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/tests/traits.rs b/src/tools/rust-analyzer/crates/hir-ty/src/tests/traits.rs
index b91172e3342..555b6972fb7 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/tests/traits.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/tests/traits.rs
@@ -163,15 +163,97 @@ fn test() {
 }
 
 #[test]
+fn infer_try() {
+    check_types(
+        r#"
+//- /main.rs crate:main deps:core
+fn test() {
+    let r: Result<i32, u64> = Result::Ok(1);
+    let v = r?;
+    v;
+} //^ i32
+
+//- /core.rs crate:core
+pub mod ops {
+    pub trait Try {
+        type Ok;
+        type Error;
+    }
+}
+
+pub mod result {
+    pub enum Result<O, E> {
+        Ok(O),
+        Err(E)
+    }
+
+    impl<O, E> crate::ops::Try for Result<O, E> {
+        type Ok = O;
+        type Error = E;
+    }
+}
+
+pub mod prelude {
+    pub mod rust_2018 {
+        pub use crate::{result::*, ops::*};
+    }
+}
+"#,
+    );
+}
+
+#[test]
 fn infer_try_trait_v2() {
     check_types(
         r#"
-//- minicore: try
-fn test() -> core::ops::ControlFlow<u32, f32> {
-    let r: core::ops::ControlFlow<u32, f32> = core::ops::ControlFlow::Continue(1.0);
+//- /main.rs crate:main deps:core
+fn test() {
+    let r: Result<i32, u64> = Result::Ok(1);
     let v = r?;
-      //^ f32
-    r
+    v;
+} //^ i32
+
+//- /core.rs crate:core
+mod ops {
+    mod try_trait {
+        pub trait Try: FromResidual {
+            type Output;
+            type Residual;
+        }
+        pub trait FromResidual<R = <Self as Try>::Residual> {}
+    }
+
+    pub use self::try_trait::FromResidual;
+    pub use self::try_trait::Try;
+}
+
+mod convert {
+    pub trait From<T> {}
+    impl<T> From<T> for T {}
+}
+
+pub mod result {
+    use crate::convert::From;
+    use crate::ops::{Try, FromResidual};
+
+    pub enum Infallible {}
+    pub enum Result<O, E> {
+        Ok(O),
+        Err(E)
+    }
+
+    impl<O, E> Try for Result<O, E> {
+        type Output = O;
+        type Error = Result<Infallible, E>;
+    }
+
+    impl<T, E, F: From<E>> FromResidual<Result<Infallible, E>> for Result<T, F> {}
+}
+
+pub mod prelude {
+    pub mod rust_2018 {
+        pub use crate::result::*;
+    }
 }
 "#,
     );
diff --git a/src/tools/rust-analyzer/crates/hir/src/diagnostics.rs b/src/tools/rust-analyzer/crates/hir/src/diagnostics.rs
index 6c8b3088adc..c5dc60f1ec5 100644
--- a/src/tools/rust-analyzer/crates/hir/src/diagnostics.rs
+++ b/src/tools/rust-analyzer/crates/hir/src/diagnostics.rs
@@ -6,7 +6,7 @@
 use base_db::CrateId;
 use cfg::{CfgExpr, CfgOptions};
 use either::Either;
-use hir_def::{path::ModPath, TraitId};
+use hir_def::path::ModPath;
 use hir_expand::{name::Name, HirFileId, InFile};
 use syntax::{ast, AstPtr, SyntaxNodePtr, TextRange};
 
@@ -33,7 +33,6 @@ diagnostics![
     BreakOutsideOfLoop,
     InactiveCode,
     IncorrectCase,
-    IncorrectTryExpr,
     InvalidDeriveTarget,
     MacroError,
     MalformedDerive,
@@ -41,7 +40,6 @@ diagnostics![
     MissingFields,
     MissingMatchArms,
     MissingUnsafe,
-    NotImplemented,
     NoSuchField,
     ReplaceFilterMapNextWithFindMap,
     TypeMismatch,
@@ -155,16 +153,6 @@ pub struct MismatchedArgCount {
     pub expected: usize,
     pub found: usize,
 }
-#[derive(Debug)]
-pub struct IncorrectTryExpr {
-    pub expr: InFile<AstPtr<ast::Expr>>,
-}
-#[derive(Debug)]
-pub struct NotImplemented {
-    pub expr: InFile<AstPtr<ast::Expr>>,
-    pub trait_: TraitId,
-    pub ty: Type,
-}
 
 #[derive(Debug)]
 pub struct MissingMatchArms {
diff --git a/src/tools/rust-analyzer/crates/hir/src/lib.rs b/src/tools/rust-analyzer/crates/hir/src/lib.rs
index e6c5c6b5833..f5324208c9a 100644
--- a/src/tools/rust-analyzer/crates/hir/src/lib.rs
+++ b/src/tools/rust-analyzer/crates/hir/src/lib.rs
@@ -81,12 +81,11 @@ use crate::db::{DefDatabase, HirDatabase};
 pub use crate::{
     attrs::{HasAttrs, Namespace},
     diagnostics::{
-        AnyDiagnostic, BreakOutsideOfLoop, InactiveCode, IncorrectCase, IncorrectTryExpr,
-        InvalidDeriveTarget, MacroError, MalformedDerive, MismatchedArgCount, MissingFields,
-        MissingMatchArms, MissingUnsafe, NoSuchField, NotImplemented,
-        ReplaceFilterMapNextWithFindMap, TypeMismatch, UnimplementedBuiltinMacro,
-        UnresolvedExternCrate, UnresolvedImport, UnresolvedMacroCall, UnresolvedModule,
-        UnresolvedProcMacro,
+        AnyDiagnostic, BreakOutsideOfLoop, InactiveCode, IncorrectCase, InvalidDeriveTarget,
+        MacroError, MalformedDerive, MismatchedArgCount, MissingFields, MissingMatchArms,
+        MissingUnsafe, NoSuchField, ReplaceFilterMapNextWithFindMap, TypeMismatch,
+        UnimplementedBuiltinMacro, UnresolvedExternCrate, UnresolvedImport, UnresolvedMacroCall,
+        UnresolvedModule, UnresolvedProcMacro,
     },
     has_source::HasSource,
     semantics::{PathResolution, Semantics, SemanticsScope, TypeInfo, VisibleTraits},
@@ -1283,45 +1282,30 @@ impl DefWithBody {
         let infer = db.infer(self.into());
         let source_map = Lazy::new(|| db.body_with_source_map(self.into()).1);
         for d in &infer.diagnostics {
-            match *d {
+            match d {
                 hir_ty::InferenceDiagnostic::NoSuchField { expr } => {
-                    let field = source_map.field_syntax(expr);
+                    let field = source_map.field_syntax(*expr);
                     acc.push(NoSuchField { field }.into())
                 }
-                hir_ty::InferenceDiagnostic::BreakOutsideOfLoop { expr, is_break } => {
+                &hir_ty::InferenceDiagnostic::BreakOutsideOfLoop { expr, is_break } => {
                     let expr = source_map
                         .expr_syntax(expr)
                         .expect("break outside of loop in synthetic syntax");
                     acc.push(BreakOutsideOfLoop { expr, is_break }.into())
                 }
                 hir_ty::InferenceDiagnostic::MismatchedArgCount { call_expr, expected, found } => {
-                    match source_map.expr_syntax(call_expr) {
+                    match source_map.expr_syntax(*call_expr) {
                         Ok(source_ptr) => acc.push(
                             MismatchedArgCount {
                                 call_expr: source_ptr,
-                                expected: expected,
-                                found: found,
+                                expected: *expected,
+                                found: *found,
                             }
                             .into(),
                         ),
                         Err(SyntheticSyntax) => (),
                     }
                 }
-                hir_ty::InferenceDiagnostic::IncorrectTryTarget { expr } => {
-                    let expr = source_map.expr_syntax(expr).expect("try in synthetic syntax");
-                    acc.push(IncorrectTryExpr { expr }.into())
-                }
-                hir_ty::InferenceDiagnostic::DoesNotImplement { expr, trait_, ref ty } => {
-                    let expr = source_map.expr_syntax(expr).expect("try in synthetic syntax");
-                    acc.push(
-                        NotImplemented {
-                            expr,
-                            trait_,
-                            ty: Type::new(db, DefWithBodyId::from(self), ty.clone()),
-                        }
-                        .into(),
-                    )
-                }
             }
         }
         for (expr, mismatch) in infer.expr_type_mismatches() {
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_constant.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_constant.rs
index eaa6de73eb3..ccdfcb0d9e4 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_constant.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_constant.rs
@@ -77,7 +77,7 @@ pub(crate) fn generate_constant(acc: &mut Assists, ctx: &AssistContext<'_>) -> O
         target_data_for_generate_constant(ctx, current_module, constant_module).unwrap_or_else(
             || {
                 let indent = IndentLevel::from_node(statement.syntax());
-                (statement.syntax().text_range().start(), indent, None, format!("\n{}", indent))
+                (statement.syntax().text_range().start(), indent, None, format!("\n{indent}"))
             },
         );
 
@@ -90,7 +90,7 @@ pub(crate) fn generate_constant(acc: &mut Assists, ctx: &AssistContext<'_>) -> O
             if let Some(file_id) = file_id {
                 builder.edit_file(file_id);
             }
-            builder.insert(offset, format!("{}{}", text, post_string));
+            builder.insert(offset, format!("{text}{post_string}"));
         },
     )
 }
@@ -103,13 +103,13 @@ fn get_text_for_generate_constant(
 ) -> Option<String> {
     let constant_token = not_exist_name_ref.pop()?;
     let vis = if not_exist_name_ref.len() == 0 && !outer_exists { "" } else { "\npub " };
-    let mut text = format!("{}const {}: {} = $0;", vis, constant_token, type_name);
+    let mut text = format!("{vis}const {constant_token}: {type_name} = $0;");
     while let Some(name_ref) = not_exist_name_ref.pop() {
         let vis = if not_exist_name_ref.len() == 0 && !outer_exists { "" } else { "\npub " };
         text = text.replace("\n", "\n    ");
-        text = format!("{}mod {} {{{}\n}}", vis, name_ref.to_string(), text);
+        text = format!("{vis}mod {name_ref} {{{text}\n}}");
     }
-    Some(text.replace("\n", &format!("\n{}", indent)))
+    Some(text.replace("\n", &format!("\n{indent}")))
 }
 
 fn target_data_for_generate_constant(
@@ -134,7 +134,7 @@ fn target_data_for_generate_constant(
                 .find(|it| it.kind() == SyntaxKind::WHITESPACE && it.to_string().contains("\n"))
                 .is_some();
             let post_string =
-                if siblings_has_newline { format!("{}", indent) } else { format!("\n{}", indent) };
+                if siblings_has_newline { format!("{indent}") } else { format!("\n{indent}") };
             Some((offset, indent + 1, Some(file_id), post_string))
         }
         _ => Some((TextSize::from(0), 0.into(), Some(file_id), "\n".into())),
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_default_from_enum_variant.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_default_from_enum_variant.rs
index 5e9995a9866..a6e3d49e0d1 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_default_from_enum_variant.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_default_from_enum_variant.rs
@@ -55,12 +55,11 @@ pub(crate) fn generate_default_from_enum_variant(
             let buf = format!(
                 r#"
 
-impl Default for {0} {{
+impl Default for {enum_name} {{
     fn default() -> Self {{
-        Self::{1}
+        Self::{variant_name}
     }}
 }}"#,
-                enum_name, variant_name
             );
             edit.insert(start_offset, buf);
         },
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_default_from_new.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_default_from_new.rs
index cbd33de19ed..49d9fd707ff 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_default_from_new.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_default_from_new.rs
@@ -1,8 +1,7 @@
 use ide_db::famous_defs::FamousDefs;
-use itertools::Itertools;
 use stdx::format_to;
 use syntax::{
-    ast::{self, HasGenericParams, HasName, HasTypeBounds, Impl},
+    ast::{self, make, HasGenericParams, HasName, Impl},
     AstNode,
 };
 
@@ -77,45 +76,47 @@ pub(crate) fn generate_default_from_new(acc: &mut Assists, ctx: &AssistContext<'
     )
 }
 
+// FIXME: based on from utils::generate_impl_text_inner
 fn generate_trait_impl_text_from_impl(impl_: &ast::Impl, trait_text: &str, code: &str) -> String {
-    let generic_params = impl_.generic_param_list();
-    let mut buf = String::with_capacity(code.len());
-    buf.push_str("\n\n");
-    buf.push_str("impl");
-
-    if let Some(generic_params) = &generic_params {
-        let lifetimes = generic_params.lifetime_params().map(|lt| format!("{}", lt.syntax()));
-        let toc_params = generic_params.type_or_const_params().map(|toc_param| match toc_param {
-            ast::TypeOrConstParam::Type(type_param) => {
-                let mut buf = String::new();
-                if let Some(it) = type_param.name() {
-                    format_to!(buf, "{}", it.syntax());
-                }
-                if let Some(it) = type_param.colon_token() {
-                    format_to!(buf, "{} ", it);
+    let impl_ty = impl_.self_ty().unwrap();
+    let generic_params = impl_.generic_param_list().map(|generic_params| {
+        let lifetime_params =
+            generic_params.lifetime_params().map(ast::GenericParam::LifetimeParam);
+        let ty_or_const_params = generic_params.type_or_const_params().filter_map(|param| {
+            // remove defaults since they can't be specified in impls
+            match param {
+                ast::TypeOrConstParam::Type(param) => {
+                    let param = param.clone_for_update();
+                    param.remove_default();
+                    Some(ast::GenericParam::TypeParam(param))
                 }
-                if let Some(it) = type_param.type_bound_list() {
-                    format_to!(buf, "{}", it.syntax());
+                ast::TypeOrConstParam::Const(param) => {
+                    let param = param.clone_for_update();
+                    param.remove_default();
+                    Some(ast::GenericParam::ConstParam(param))
                 }
-                buf
             }
-            ast::TypeOrConstParam::Const(const_param) => const_param.syntax().to_string(),
         });
-        let generics = lifetimes.chain(toc_params).format(", ");
-        format_to!(buf, "<{}>", generics);
-    }
 
-    buf.push(' ');
-    buf.push_str(trait_text);
-    buf.push_str(" for ");
-    buf.push_str(&impl_.self_ty().unwrap().syntax().text().to_string());
+        make::generic_param_list(itertools::chain(lifetime_params, ty_or_const_params))
+    });
+
+    let mut buf = String::with_capacity(code.len());
+    buf.push_str("\n\n");
+
+    // `impl{generic_params} {trait_text} for {impl_.self_ty()}`
+    buf.push_str("impl");
+    if let Some(generic_params) = &generic_params {
+        format_to!(buf, "{generic_params}")
+    }
+    format_to!(buf, " {trait_text} for {impl_ty}");
 
     match impl_.where_clause() {
         Some(where_clause) => {
-            format_to!(buf, "\n{}\n{{\n{}\n}}", where_clause, code);
+            format_to!(buf, "\n{where_clause}\n{{\n{code}\n}}");
         }
         None => {
-            format_to!(buf, " {{\n{}\n}}", code);
+            format_to!(buf, " {{\n{code}\n}}");
         }
     }
 
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_delegate_methods.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_delegate_methods.rs
index 85b193663a0..ceae8075503 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_delegate_methods.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_delegate_methods.rs
@@ -51,14 +51,14 @@ pub(crate) fn generate_delegate_methods(acc: &mut Assists, ctx: &AssistContext<'
         Some(field) => {
             let field_name = field.name()?;
             let field_ty = field.ty()?;
-            (format!("{}", field_name), field_ty, field.syntax().text_range())
+            (field_name.to_string(), field_ty, field.syntax().text_range())
         }
         None => {
             let field = ctx.find_node_at_offset::<ast::TupleField>()?;
             let field_list = ctx.find_node_at_offset::<ast::TupleFieldList>()?;
             let field_list_index = field_list.fields().position(|it| it == field)?;
             let field_ty = field.ty()?;
-            (format!("{}", field_list_index), field_ty, field.syntax().text_range())
+            (field_list_index.to_string(), field_ty, field.syntax().text_range())
         }
     };
 
@@ -77,7 +77,7 @@ pub(crate) fn generate_delegate_methods(acc: &mut Assists, ctx: &AssistContext<'
     for method in methods {
         let adt = ast::Adt::Struct(strukt.clone());
         let name = method.name(ctx.db()).to_string();
-        let impl_def = find_struct_impl(ctx, &adt, &name).flatten();
+        let impl_def = find_struct_impl(ctx, &adt, &[name]).flatten();
         acc.add_group(
             &GroupLabel("Generate delegate methods…".to_owned()),
             AssistId("generate_delegate_methods", AssistKind::Generate),
@@ -151,7 +151,7 @@ pub(crate) fn generate_delegate_methods(acc: &mut Assists, ctx: &AssistContext<'
                             Some(cap) => {
                                 let offset = strukt.syntax().text_range().end();
                                 let snippet = render_snippet(cap, impl_def.syntax(), cursor);
-                                let snippet = format!("\n\n{}", snippet);
+                                let snippet = format!("\n\n{snippet}");
                                 builder.insert_snippet(cap, offset, snippet);
                             }
                             None => {
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_deref.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_deref.rs
index 8f4405a8c86..55b7afb3d3b 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_deref.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_deref.rs
@@ -66,7 +66,7 @@ fn generate_record_deref(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option<(
     let target = field.syntax().text_range();
     acc.add(
         AssistId("generate_deref", AssistKind::Generate),
-        format!("Generate `{:?}` impl using `{}`", deref_type_to_generate, field_name),
+        format!("Generate `{deref_type_to_generate:?}` impl using `{field_name}`"),
         target,
         |edit| {
             generate_edit(
@@ -106,7 +106,7 @@ fn generate_tuple_deref(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option<()
     let target = field.syntax().text_range();
     acc.add(
         AssistId("generate_deref", AssistKind::Generate),
-        format!("Generate `{:?}` impl using `{}`", deref_type_to_generate, field.syntax()),
+        format!("Generate `{deref_type_to_generate:?}` impl using `{field}`"),
         target,
         |edit| {
             generate_edit(
@@ -132,18 +132,16 @@ fn generate_edit(
     let start_offset = strukt.syntax().text_range().end();
     let impl_code = match deref_type {
         DerefType::Deref => format!(
-            r#"    type Target = {0};
+            r#"    type Target = {field_type_syntax};
 
     fn deref(&self) -> &Self::Target {{
-        &self.{1}
+        &self.{field_name}
     }}"#,
-            field_type_syntax, field_name
         ),
         DerefType::DerefMut => format!(
             r#"    fn deref_mut(&mut self) -> &mut Self::Target {{
-        &mut self.{}
+        &mut self.{field_name}
     }}"#,
-            field_name
         ),
     };
     let strukt_adt = ast::Adt::Struct(strukt);
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_documentation_template.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_documentation_template.rs
index c91141f8eb5..b8415c72a2a 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_documentation_template.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_documentation_template.rs
@@ -139,40 +139,44 @@ fn make_example_for_fn(ast_func: &ast::Fn, ctx: &AssistContext<'_>) -> Option<St
 
     let mut example = String::new();
 
+    let use_path = build_path(ast_func, ctx)?;
     let is_unsafe = ast_func.unsafe_token().is_some();
     let param_list = ast_func.param_list()?;
     let ref_mut_params = ref_mut_params(&param_list);
     let self_name = self_name(ast_func);
 
-    format_to!(example, "use {};\n\n", build_path(ast_func, ctx)?);
+    format_to!(example, "use {use_path};\n\n");
     if let Some(self_name) = &self_name {
-        if let Some(mtbl) = is_ref_mut_self(ast_func) {
-            let mtbl = if mtbl == true { " mut" } else { "" };
-            format_to!(example, "let{} {} = ;\n", mtbl, self_name);
+        if let Some(mut_) = is_ref_mut_self(ast_func) {
+            let mut_ = if mut_ == true { "mut " } else { "" };
+            format_to!(example, "let {mut_}{self_name} = ;\n");
         }
     }
     for param_name in &ref_mut_params {
-        format_to!(example, "let mut {} = ;\n", param_name);
+        format_to!(example, "let mut {param_name} = ;\n");
     }
     // Call the function, check result
     let function_call = function_call(ast_func, &param_list, self_name.as_deref(), is_unsafe)?;
     if returns_a_value(ast_func, ctx) {
         if count_parameters(&param_list) < 3 {
-            format_to!(example, "assert_eq!({}, );\n", function_call);
+            format_to!(example, "assert_eq!({function_call}, );\n");
         } else {
-            format_to!(example, "let result = {};\n", function_call);
+            format_to!(example, "let result = {function_call};\n");
             example.push_str("assert_eq!(result, );\n");
         }
     } else {
-        format_to!(example, "{};\n", function_call);
+        format_to!(example, "{function_call};\n");
     }
     // Check the mutated values
-    if is_ref_mut_self(ast_func) == Some(true) {
-        format_to!(example, "assert_eq!({}, );", self_name?);
+    if let Some(self_name) = &self_name {
+        if is_ref_mut_self(ast_func) == Some(true) {
+            format_to!(example, "assert_eq!({self_name}, );");
+        }
     }
     for param_name in &ref_mut_params {
-        format_to!(example, "assert_eq!({}, );", param_name);
+        format_to!(example, "assert_eq!({param_name}, );");
     }
+
     Some(example)
 }
 
@@ -189,7 +193,8 @@ fn introduction_builder(ast_func: &ast::Fn, ctx: &AssistContext<'_>) -> Option<S
         let intro_for_new = || {
             let is_new = name == "new";
             if is_new && ret_ty == self_ty {
-                Some(format!("Creates a new [`{}`].", linkable_self_ty?))
+                let self_ty = linkable_self_ty?;
+                Some(format!("Creates a new [`{self_ty}`]."))
             } else {
                 None
             }
@@ -214,7 +219,9 @@ fn introduction_builder(ast_func: &ast::Fn, ctx: &AssistContext<'_>) -> Option<S
                 } else {
                     ""
                 };
-                Some(format!("Returns{reference} the {what} of this [`{}`].", linkable_self_ty?))
+
+                let self_ty = linkable_self_ty?;
+                Some(format!("Returns{reference} the {what} of this [`{self_ty}`]."))
             }
             _ => None,
         };
@@ -228,7 +235,9 @@ fn introduction_builder(ast_func: &ast::Fn, ctx: &AssistContext<'_>) -> Option<S
             if what == "len" {
                 what = "length".into()
             };
-            Some(format!("Sets the {what} of this [`{}`].", linkable_self_ty?))
+
+            let self_ty = linkable_self_ty?;
+            Some(format!("Sets the {what} of this [`{self_ty}`]."))
         };
 
         if let Some(intro) = intro_for_new() {
@@ -404,7 +413,7 @@ fn arguments_from_params(param_list: &ast::ParamList) -> String {
         // instance `TuplePat`) could be managed later.
         Some(ast::Pat::IdentPat(ident_pat)) => match ident_pat.name() {
             Some(name) => match is_a_ref_mut_param(&param) {
-                true => format!("&mut {}", name),
+                true => format!("&mut {name}"),
                 false => name.to_string(),
             },
             None => "_".to_string(),
@@ -424,14 +433,15 @@ fn function_call(
     let name = ast_func.name()?;
     let arguments = arguments_from_params(param_list);
     let function_call = if param_list.self_param().is_some() {
-        format!("{}.{}({})", self_name?, name, arguments)
+        let self_ = self_name?;
+        format!("{self_}.{name}({arguments})")
     } else if let Some(implementation) = self_partial_type(ast_func) {
-        format!("{}::{}({})", implementation, name, arguments)
+        format!("{implementation}::{name}({arguments})")
     } else {
-        format!("{}({})", name, arguments)
+        format!("{name}({arguments})")
     };
     match is_unsafe {
-        true => Some(format!("unsafe {{ {} }}", function_call)),
+        true => Some(format!("unsafe {{ {function_call} }}")),
         false => Some(function_call),
     }
 }
@@ -469,8 +479,8 @@ fn build_path(ast_func: &ast::Fn, ctx: &AssistContext<'_>) -> Option<String> {
         .unwrap_or_else(|| "*".into());
     let module_def: ModuleDef = ctx.sema.to_def(ast_func)?.module(ctx.db()).into();
     match module_def.canonical_path(ctx.db()) {
-        Some(path) => Some(format!("{}::{}::{}", crate_name, path, leaf)),
-        None => Some(format!("{}::{}", crate_name, leaf)),
+        Some(path) => Some(format!("{crate_name}::{path}::{leaf}")),
+        None => Some(format!("{crate_name}::{leaf}")),
     }
 }
 
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_enum_is_method.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_enum_is_method.rs
index 52d27d8a7d6..63e91b835f1 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_enum_is_method.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_enum_is_method.rs
@@ -52,7 +52,7 @@ pub(crate) fn generate_enum_is_method(acc: &mut Assists, ctx: &AssistContext<'_>
     let fn_name = format!("is_{}", &to_lower_snake_case(&variant_name.text()));
 
     // Return early if we've found an existing new fn
-    let impl_def = find_struct_impl(ctx, &parent_enum, &fn_name)?;
+    let impl_def = find_struct_impl(ctx, &parent_enum, &[fn_name.clone()])?;
 
     let target = variant.syntax().text_range();
     acc.add_group(
@@ -61,21 +61,15 @@ pub(crate) fn generate_enum_is_method(acc: &mut Assists, ctx: &AssistContext<'_>
         "Generate an `is_` method for this enum variant",
         target,
         |builder| {
-            let vis = parent_enum.visibility().map_or(String::new(), |v| format!("{} ", v));
+            let vis = parent_enum.visibility().map_or(String::new(), |v| format!("{v} "));
             let method = format!(
-                "    /// Returns `true` if the {} is [`{variant}`].
+                "    /// Returns `true` if the {enum_lowercase_name} is [`{variant_name}`].
     ///
-    /// [`{variant}`]: {}::{variant}
+    /// [`{variant_name}`]: {enum_name}::{variant_name}
     #[must_use]
-    {}fn {}(&self) -> bool {{
-        matches!(self, Self::{variant}{})
+    {vis}fn {fn_name}(&self) -> bool {{
+        matches!(self, Self::{variant_name}{pattern_suffix})
     }}",
-                enum_lowercase_name,
-                enum_name,
-                vis,
-                fn_name,
-                pattern_suffix,
-                variant = variant_name
             );
 
             add_method_to_adt(builder, &parent_enum, impl_def, &method);
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_enum_projection_method.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_enum_projection_method.rs
index b19aa0f652a..bdd3cf4f06c 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_enum_projection_method.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_enum_projection_method.rs
@@ -116,6 +116,14 @@ fn generate_enum_projection_method(
     assist_description: &str,
     props: ProjectionProps,
 ) -> Option<()> {
+    let ProjectionProps {
+        fn_name_prefix,
+        self_param,
+        return_prefix,
+        return_suffix,
+        happy_case,
+        sad_case,
+    } = props;
     let variant = ctx.find_node_at_offset::<ast::Variant>()?;
     let variant_name = variant.name()?;
     let parent_enum = ast::Adt::Enum(variant.parent_enum());
@@ -125,7 +133,7 @@ fn generate_enum_projection_method(
             let (field,) = record.fields().collect_tuple()?;
             let name = field.name()?.to_string();
             let ty = field.ty()?;
-            let pattern_suffix = format!(" {{ {} }}", name);
+            let pattern_suffix = format!(" {{ {name} }}");
             (pattern_suffix, ty, name)
         }
         ast::StructKind::Tuple(tuple) => {
@@ -136,11 +144,10 @@ fn generate_enum_projection_method(
         ast::StructKind::Unit => return None,
     };
 
-    let fn_name =
-        format!("{}_{}", props.fn_name_prefix, &to_lower_snake_case(&variant_name.text()));
+    let fn_name = format!("{}_{}", fn_name_prefix, &to_lower_snake_case(&variant_name.text()));
 
     // Return early if we've found an existing new fn
-    let impl_def = find_struct_impl(ctx, &parent_enum, &fn_name)?;
+    let impl_def = find_struct_impl(ctx, &parent_enum, &[fn_name.clone()])?;
 
     let target = variant.syntax().text_range();
     acc.add_group(
@@ -149,27 +156,15 @@ fn generate_enum_projection_method(
         assist_description,
         target,
         |builder| {
-            let vis = parent_enum.visibility().map_or(String::new(), |v| format!("{} ", v));
+            let vis = parent_enum.visibility().map_or(String::new(), |v| format!("{v} "));
             let method = format!(
-                "    {0}fn {1}({2}) -> {3}{4}{5} {{
-        if let Self::{6}{7} = self {{
-            {8}({9})
+                "    {vis}fn {fn_name}({self_param}) -> {return_prefix}{field_type}{return_suffix} {{
+        if let Self::{variant_name}{pattern_suffix} = self {{
+            {happy_case}({bound_name})
         }} else {{
-            {10}
+            {sad_case}
         }}
-    }}",
-                vis,
-                fn_name,
-                props.self_param,
-                props.return_prefix,
-                field_type.syntax(),
-                props.return_suffix,
-                variant_name,
-                pattern_suffix,
-                props.happy_case,
-                bound_name,
-                props.sad_case,
-            );
+    }}");
 
             add_method_to_adt(builder, &parent_enum, impl_def, &method);
         },
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_from_impl_for_enum.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_from_impl_for_enum.rs
index 507ea012bab..7c81d2c6a6c 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_from_impl_for_enum.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_from_impl_for_enum.rs
@@ -56,23 +56,18 @@ pub(crate) fn generate_from_impl_for_enum(
         target,
         |edit| {
             let start_offset = variant.parent_enum().syntax().text_range().end();
-            let from_trait = format!("From<{}>", field_type.syntax());
+            let from_trait = format!("From<{field_type}>");
             let impl_code = if let Some(name) = field_name {
                 format!(
-                    r#"    fn from({0}: {1}) -> Self {{
-        Self::{2} {{ {0} }}
-    }}"#,
-                    name.text(),
-                    field_type.syntax(),
-                    variant_name,
+                    r#"    fn from({name}: {field_type}) -> Self {{
+        Self::{variant_name} {{ {name} }}
+    }}"#
                 )
             } else {
                 format!(
-                    r#"    fn from(v: {}) -> Self {{
-        Self::{}(v)
-    }}"#,
-                    field_type.syntax(),
-                    variant_name,
+                    r#"    fn from(v: {field_type}) -> Self {{
+        Self::{variant_name}(v)
+    }}"#
                 )
             };
             let from_impl = generate_trait_impl_text(&enum_, &from_trait, &impl_code);
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_function.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_function.rs
index 8b67982f915..c229127e48f 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_function.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_function.rs
@@ -179,7 +179,7 @@ fn add_func_to_accumulator(
         let function_template = function_builder.render(adt_name.is_some());
         let mut func = function_template.to_string(ctx.config.snippet_cap);
         if let Some(name) = adt_name {
-            func = format!("\n{}impl {} {{\n{}\n{}}}", indent, name, func, indent);
+            func = format!("\n{indent}impl {name} {{\n{func}\n{indent}}}");
         }
         builder.edit_file(file);
         match ctx.config.snippet_cap {
@@ -198,7 +198,7 @@ fn get_adt_source(
     let file = ctx.sema.parse(range.file_id);
     let adt_source =
         ctx.sema.find_node_at_offset_with_macros(file.syntax(), range.range.start())?;
-    find_struct_impl(ctx, &adt_source, fn_name).map(|impl_| (impl_, range.file_id))
+    find_struct_impl(ctx, &adt_source, &[fn_name.to_string()]).map(|impl_| (impl_, range.file_id))
 }
 
 struct FunctionTemplate {
@@ -212,23 +212,26 @@ struct FunctionTemplate {
 
 impl FunctionTemplate {
     fn to_string(&self, cap: Option<SnippetCap>) -> String {
+        let Self { leading_ws, fn_def, ret_type, should_focus_return_type, trailing_ws, tail_expr } =
+            self;
+
         let f = match cap {
             Some(cap) => {
-                let cursor = if self.should_focus_return_type {
+                let cursor = if *should_focus_return_type {
                     // Focus the return type if there is one
-                    match self.ret_type {
-                        Some(ref ret_type) => ret_type.syntax(),
-                        None => self.tail_expr.syntax(),
+                    match ret_type {
+                        Some(ret_type) => ret_type.syntax(),
+                        None => tail_expr.syntax(),
                     }
                 } else {
-                    self.tail_expr.syntax()
+                    tail_expr.syntax()
                 };
-                render_snippet(cap, self.fn_def.syntax(), Cursor::Replace(cursor))
+                render_snippet(cap, fn_def.syntax(), Cursor::Replace(cursor))
             }
-            None => self.fn_def.to_string(),
+            None => fn_def.to_string(),
         };
 
-        format!("{}{}{}", self.leading_ws, f, self.trailing_ws)
+        format!("{leading_ws}{f}{trailing_ws}")
     }
 }
 
@@ -330,9 +333,9 @@ impl FunctionBuilder {
                 let mut indent = IndentLevel::from_node(&it);
                 if is_method {
                     indent = indent + 1;
-                    leading_ws = format!("{}", indent);
+                    leading_ws = format!("{indent}");
                 } else {
-                    leading_ws = format!("\n\n{}", indent);
+                    leading_ws = format!("\n\n{indent}");
                 }
 
                 fn_def = fn_def.indent(indent);
@@ -340,9 +343,10 @@ impl FunctionBuilder {
             }
             GeneratedFunctionTarget::InEmptyItemList(it) => {
                 let indent = IndentLevel::from_node(&it);
-                leading_ws = format!("\n{}", indent + 1);
-                fn_def = fn_def.indent(indent + 1);
-                trailing_ws = format!("\n{}", indent);
+                let leading_indent = indent + 1;
+                leading_ws = format!("\n{leading_indent}");
+                fn_def = fn_def.indent(leading_indent);
+                trailing_ws = format!("\n{indent}");
             }
         };
 
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_getter.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_getter.rs
index 76fcef0cad9..5e719142834 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_getter.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_getter.rs
@@ -1,6 +1,9 @@
 use ide_db::famous_defs::FamousDefs;
 use stdx::{format_to, to_lower_snake_case};
-use syntax::ast::{self, AstNode, HasName, HasVisibility};
+use syntax::{
+    ast::{self, AstNode, HasName, HasVisibility},
+    TextRange,
+};
 
 use crate::{
     utils::{convert_reference_type, find_impl_block_end, find_struct_impl, generate_impl_text},
@@ -72,92 +75,259 @@ pub(crate) fn generate_getter_mut(acc: &mut Assists, ctx: &AssistContext<'_>) ->
     generate_getter_impl(acc, ctx, true)
 }
 
+#[derive(Clone, Debug)]
+struct RecordFieldInfo {
+    field_name: syntax::ast::Name,
+    field_ty: syntax::ast::Type,
+    fn_name: String,
+    target: TextRange,
+}
+
+struct GetterInfo {
+    impl_def: Option<ast::Impl>,
+    strukt: ast::Struct,
+    mutable: bool,
+}
+
 pub(crate) fn generate_getter_impl(
     acc: &mut Assists,
     ctx: &AssistContext<'_>,
     mutable: bool,
 ) -> Option<()> {
-    let strukt = ctx.find_node_at_offset::<ast::Struct>()?;
-    let field = ctx.find_node_at_offset::<ast::RecordField>()?;
+    // This if condition denotes two modes this assist can work in:
+    // - First is acting upon selection of record fields
+    // - Next is acting upon a single record field
+    //
+    // This is the only part where implementation diverges a bit,
+    // subsequent code is generic for both of these modes
 
-    let field_name = field.name()?;
-    let field_ty = field.ty()?;
+    let (strukt, info_of_record_fields, fn_names) = if !ctx.has_empty_selection() {
+        // Selection Mode
+        let node = ctx.covering_element();
 
-    // Return early if we've found an existing fn
-    let mut fn_name = to_lower_snake_case(&field_name.to_string());
-    if mutable {
-        format_to!(fn_name, "_mut");
+        let node = match node {
+            syntax::NodeOrToken::Node(n) => n,
+            syntax::NodeOrToken::Token(t) => t.parent()?,
+        };
+
+        let parent_struct = node.ancestors().find_map(ast::Struct::cast)?;
+
+        let (info_of_record_fields, field_names) =
+            extract_and_parse_record_fields(&parent_struct, ctx.selection_trimmed(), mutable)?;
+
+        (parent_struct, info_of_record_fields, field_names)
+    } else {
+        // Single Record Field mode
+        let strukt = ctx.find_node_at_offset::<ast::Struct>()?;
+        let field = ctx.find_node_at_offset::<ast::RecordField>()?;
+
+        let record_field_info = parse_record_field(field, mutable)?;
+
+        let fn_name = record_field_info.fn_name.clone();
+
+        (strukt, vec![record_field_info], vec![fn_name])
+    };
+
+    // No record fields to do work on :(
+    if info_of_record_fields.len() == 0 {
+        return None;
     }
-    let impl_def = find_struct_impl(ctx, &ast::Adt::Struct(strukt.clone()), fn_name.as_str())?;
+
+    let impl_def = find_struct_impl(ctx, &ast::Adt::Struct(strukt.clone()), &fn_names)?;
 
     let (id, label) = if mutable {
         ("generate_getter_mut", "Generate a mut getter method")
     } else {
         ("generate_getter", "Generate a getter method")
     };
-    let target = field.syntax().text_range();
+
+    // Computing collective text range of all record fields in selected region
+    let target: TextRange = info_of_record_fields
+        .iter()
+        .map(|record_field_info| record_field_info.target)
+        .reduce(|acc, target| acc.cover(target))?;
+
+    let getter_info = GetterInfo { impl_def, strukt, mutable };
+
     acc.add_group(
         &GroupLabel("Generate getter/setter".to_owned()),
         AssistId(id, AssistKind::Generate),
         label,
         target,
         |builder| {
+            let record_fields_count = info_of_record_fields.len();
+
             let mut buf = String::with_capacity(512);
 
-            if impl_def.is_some() {
-                buf.push('\n');
+            // Check if an impl exists
+            if let Some(impl_def) = &getter_info.impl_def {
+                // Check if impl is empty
+                if let Some(assoc_item_list) = impl_def.assoc_item_list() {
+                    if assoc_item_list.assoc_items().next().is_some() {
+                        // If not empty then only insert a new line
+                        buf.push('\n');
+                    }
+                }
             }
 
-            let vis = strukt.visibility().map_or(String::new(), |v| format!("{} ", v));
-            let (ty, body) = if mutable {
-                (format!("&mut {}", field_ty), format!("&mut self.{}", field_name))
-            } else {
-                (|| {
-                    let krate = ctx.sema.scope(field_ty.syntax())?.krate();
-                    let famous_defs = &FamousDefs(&ctx.sema, krate);
-                    ctx.sema
-                        .resolve_type(&field_ty)
-                        .and_then(|ty| convert_reference_type(ty, ctx.db(), famous_defs))
-                        .map(|conversion| {
-                            cov_mark::hit!(convert_reference_type);
-                            (
-                                conversion.convert_type(ctx.db()),
-                                conversion.getter(field_name.to_string()),
-                            )
-                        })
-                })()
-                .unwrap_or_else(|| (format!("&{}", field_ty), format!("&self.{}", field_name)))
-            };
-
-            format_to!(
-                buf,
-                "    {}fn {}(&{}self) -> {} {{
-        {}
-    }}",
-                vis,
-                fn_name,
-                mutable.then(|| "mut ").unwrap_or_default(),
-                ty,
-                body,
-            );
-
-            let start_offset = impl_def
-                .and_then(|impl_def| find_impl_block_end(impl_def, &mut buf))
+            for (i, record_field_info) in info_of_record_fields.iter().enumerate() {
+                // this buf inserts a newline at the end of a getter
+                // automatically, if one wants to add one more newline
+                // for separating it from other assoc items, that needs
+                // to be handled spearately
+                let mut getter_buf =
+                    generate_getter_from_info(ctx, &getter_info, &record_field_info);
+
+                // Insert `$0` only for last getter we generate
+                if i == record_fields_count - 1 {
+                    getter_buf = getter_buf.replacen("fn ", "fn $0", 1);
+                }
+
+                // For first element we do not merge with '\n', as
+                // that can be inserted by impl_def check defined
+                // above, for other cases which are:
+                //
+                // - impl exists but it empty, here we would ideally
+                // not want to keep newline between impl <struct> {
+                // and fn <fn-name>() { line
+                //
+                // - next if impl itself does not exist, in this
+                // case we ourselves generate a new impl and that
+                // again ends up with the same reasoning as above
+                // for not keeping newline
+                if i == 0 {
+                    buf = buf + &getter_buf;
+                } else {
+                    buf = buf + "\n" + &getter_buf;
+                }
+
+                // We don't insert a new line at the end of
+                // last getter as it will end up in the end
+                // of an impl where we would not like to keep
+                // getter and end of impl ( i.e. `}` ) with an
+                // extra line for no reason
+                if i < record_fields_count - 1 {
+                    buf = buf + "\n";
+                }
+            }
+
+            let start_offset = getter_info
+                .impl_def
+                .as_ref()
+                .and_then(|impl_def| find_impl_block_end(impl_def.to_owned(), &mut buf))
                 .unwrap_or_else(|| {
-                    buf = generate_impl_text(&ast::Adt::Struct(strukt.clone()), &buf);
-                    strukt.syntax().text_range().end()
+                    buf = generate_impl_text(&ast::Adt::Struct(getter_info.strukt.clone()), &buf);
+                    getter_info.strukt.syntax().text_range().end()
                 });
 
             match ctx.config.snippet_cap {
-                Some(cap) => {
-                    builder.insert_snippet(cap, start_offset, buf.replacen("fn ", "fn $0", 1))
-                }
+                Some(cap) => builder.insert_snippet(cap, start_offset, buf),
                 None => builder.insert(start_offset, buf),
             }
         },
     )
 }
 
+fn generate_getter_from_info(
+    ctx: &AssistContext<'_>,
+    info: &GetterInfo,
+    record_field_info: &RecordFieldInfo,
+) -> String {
+    let mut buf = String::with_capacity(512);
+
+    let vis = info.strukt.visibility().map_or(String::new(), |v| format!("{} ", v));
+    let (ty, body) = if info.mutable {
+        (
+            format!("&mut {}", record_field_info.field_ty),
+            format!("&mut self.{}", record_field_info.field_name),
+        )
+    } else {
+        (|| {
+            let krate = ctx.sema.scope(record_field_info.field_ty.syntax())?.krate();
+            let famous_defs = &FamousDefs(&ctx.sema, krate);
+            ctx.sema
+                .resolve_type(&record_field_info.field_ty)
+                .and_then(|ty| convert_reference_type(ty, ctx.db(), famous_defs))
+                .map(|conversion| {
+                    cov_mark::hit!(convert_reference_type);
+                    (
+                        conversion.convert_type(ctx.db()),
+                        conversion.getter(record_field_info.field_name.to_string()),
+                    )
+                })
+        })()
+        .unwrap_or_else(|| {
+            (
+                format!("&{}", record_field_info.field_ty),
+                format!("&self.{}", record_field_info.field_name),
+            )
+        })
+    };
+
+    format_to!(
+        buf,
+        "    {}fn {}(&{}self) -> {} {{
+        {}
+    }}",
+        vis,
+        record_field_info.fn_name,
+        info.mutable.then(|| "mut ").unwrap_or_default(),
+        ty,
+        body,
+    );
+
+    buf
+}
+
+fn extract_and_parse_record_fields(
+    node: &ast::Struct,
+    selection_range: TextRange,
+    mutable: bool,
+) -> Option<(Vec<RecordFieldInfo>, Vec<String>)> {
+    let mut field_names: Vec<String> = vec![];
+    let field_list = node.field_list()?;
+
+    match field_list {
+        ast::FieldList::RecordFieldList(ele) => {
+            let info_of_record_fields_in_selection = ele
+                .fields()
+                .filter_map(|record_field| {
+                    if selection_range.contains_range(record_field.syntax().text_range()) {
+                        let record_field_info = parse_record_field(record_field, mutable)?;
+                        field_names.push(record_field_info.fn_name.clone());
+                        return Some(record_field_info);
+                    }
+
+                    None
+                })
+                .collect::<Vec<RecordFieldInfo>>();
+
+            if info_of_record_fields_in_selection.len() == 0 {
+                return None;
+            }
+
+            Some((info_of_record_fields_in_selection, field_names))
+        }
+        ast::FieldList::TupleFieldList(_) => {
+            return None;
+        }
+    }
+}
+
+fn parse_record_field(record_field: ast::RecordField, mutable: bool) -> Option<RecordFieldInfo> {
+    let field_name = record_field.name()?;
+    let field_ty = record_field.ty()?;
+
+    let mut fn_name = to_lower_snake_case(&field_name.to_string());
+    if mutable {
+        format_to!(fn_name, "_mut");
+    }
+
+    let target = record_field.syntax().text_range();
+
+    Some(RecordFieldInfo { field_name, field_ty, fn_name, target })
+}
+
 #[cfg(test)]
 mod tests {
     use crate::tests::{check_assist, check_assist_not_applicable};
@@ -489,4 +659,53 @@ impl Context {
 "#,
         );
     }
+
+    #[test]
+    fn test_generate_multiple_getters_from_selection() {
+        check_assist(
+            generate_getter,
+            r#"
+struct Context {
+    $0data: Data,
+    count: usize,$0
+}
+    "#,
+            r#"
+struct Context {
+    data: Data,
+    count: usize,
+}
+
+impl Context {
+    fn data(&self) -> &Data {
+        &self.data
+    }
+
+    fn $0count(&self) -> &usize {
+        &self.count
+    }
+}
+    "#,
+        );
+    }
+
+    #[test]
+    fn test_generate_multiple_getters_from_selection_one_already_exists() {
+        // As impl for one of the fields already exist, skip it
+        check_assist_not_applicable(
+            generate_getter,
+            r#"
+struct Context {
+    $0data: Data,
+    count: usize,$0
+}
+
+impl Context {
+    fn data(&self) -> &Data {
+        &self.data
+    }
+}
+    "#,
+        );
+    }
 }
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_impl.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_impl.rs
index 307cea3d0a4..9af26c04eb4 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_impl.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_impl.rs
@@ -28,7 +28,7 @@ pub(crate) fn generate_impl(acc: &mut Assists, ctx: &AssistContext<'_>) -> Optio
 
     acc.add(
         AssistId("generate_impl", AssistKind::Generate),
-        format!("Generate impl for `{}`", name),
+        format!("Generate impl for `{name}`"),
         target,
         |edit| {
             let start_offset = nominal.syntax().text_range().end();
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_new.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_new.rs
index 9cda74d9e0d..17fadea0eaf 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_new.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_new.rs
@@ -39,7 +39,8 @@ pub(crate) fn generate_new(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option
     };
 
     // Return early if we've found an existing new fn
-    let impl_def = find_struct_impl(ctx, &ast::Adt::Struct(strukt.clone()), "new")?;
+    let impl_def =
+        find_struct_impl(ctx, &ast::Adt::Struct(strukt.clone()), &[String::from("new")])?;
 
     let current_module = ctx.sema.scope(strukt.syntax())?.module();
 
@@ -51,11 +52,13 @@ pub(crate) fn generate_new(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option
             buf.push('\n');
         }
 
-        let vis = strukt.visibility().map_or(String::new(), |v| format!("{} ", v));
+        let vis = strukt.visibility().map_or(String::new(), |v| format!("{v} "));
 
         let trivial_constructors = field_list
             .fields()
             .map(|f| {
+                let name = f.name()?;
+
                 let ty = ctx.sema.resolve_type(&f.ty()?)?;
 
                 let item_in_ns = hir::ItemInNs::from(hir::ModuleDef::from(ty.as_adt()?));
@@ -72,7 +75,7 @@ pub(crate) fn generate_new(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option
                     &ty,
                 )?;
 
-                Some(format!("{}: {}", f.name()?.syntax(), expr))
+                Some(format!("{name}: {expr}"))
             })
             .collect::<Vec<_>>();
 
@@ -81,7 +84,10 @@ pub(crate) fn generate_new(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option
             .enumerate()
             .filter_map(|(i, f)| {
                 if trivial_constructors[i].is_none() {
-                    Some(format!("{}: {}", f.name()?.syntax(), f.ty()?.syntax()))
+                    let name = f.name()?;
+                    let ty = f.ty()?;
+
+                    Some(format!("{name}: {ty}"))
                 } else {
                     None
                 }
@@ -101,7 +107,7 @@ pub(crate) fn generate_new(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option
             })
             .format(", ");
 
-        format_to!(buf, "    {}fn new({}) -> Self {{ Self {{ {} }} }}", vis, params, fields);
+        format_to!(buf, "    {vis}fn new({params}) -> Self {{ Self {{ {fields} }} }}");
 
         let start_offset = impl_def
             .and_then(|impl_def| find_impl_block_start(impl_def, &mut buf))
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_setter.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_setter.rs
index 2a7ad6ce368..62f72df1c9d 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_setter.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_setter.rs
@@ -36,11 +36,8 @@ pub(crate) fn generate_setter(acc: &mut Assists, ctx: &AssistContext<'_>) -> Opt
 
     // Return early if we've found an existing fn
     let fn_name = to_lower_snake_case(&field_name.to_string());
-    let impl_def = find_struct_impl(
-        ctx,
-        &ast::Adt::Struct(strukt.clone()),
-        format!("set_{}", fn_name).as_str(),
-    )?;
+    let impl_def =
+        find_struct_impl(ctx, &ast::Adt::Struct(strukt.clone()), &[format!("set_{fn_name}")])?;
 
     let target = field.syntax().text_range();
     acc.add_group(
@@ -55,18 +52,12 @@ pub(crate) fn generate_setter(acc: &mut Assists, ctx: &AssistContext<'_>) -> Opt
                 buf.push('\n');
             }
 
-            let vis = strukt.visibility().map_or(String::new(), |v| format!("{} ", v));
+            let vis = strukt.visibility().map_or(String::new(), |v| format!("{v} "));
             format_to!(
                 buf,
-                "    {}fn set_{}(&mut self, {}: {}) {{
-        self.{} = {};
-    }}",
-                vis,
-                fn_name,
-                fn_name,
-                field_ty,
-                fn_name,
-                fn_name,
+                "    {vis}fn set_{fn_name}(&mut self, {fn_name}: {field_ty}) {{
+        self.{fn_name} = {fn_name};
+    }}"
             );
 
             let start_offset = impl_def
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/utils.rs b/src/tools/rust-analyzer/crates/ide-assists/src/utils.rs
index 38396cd7d7b..db32e7182c4 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/utils.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/utils.rs
@@ -331,10 +331,14 @@ fn calc_depth(pat: &ast::Pat, depth: usize) -> usize {
 // FIXME: change the new fn checking to a more semantic approach when that's more
 // viable (e.g. we process proc macros, etc)
 // FIXME: this partially overlaps with `find_impl_block_*`
+
+/// `find_struct_impl` looks for impl of a struct, but this also has additional feature
+/// where it takes a list of function names and check if they exist inside impl_, if
+/// even one match is found, it returns None
 pub(crate) fn find_struct_impl(
     ctx: &AssistContext<'_>,
     adt: &ast::Adt,
-    name: &str,
+    names: &[String],
 ) -> Option<Option<ast::Impl>> {
     let db = ctx.db();
     let module = adt.syntax().parent()?;
@@ -362,7 +366,7 @@ pub(crate) fn find_struct_impl(
     });
 
     if let Some(ref impl_blk) = block {
-        if has_fn(impl_blk, name) {
+        if has_any_fn(impl_blk, names) {
             return None;
         }
     }
@@ -370,12 +374,12 @@ pub(crate) fn find_struct_impl(
     Some(block)
 }
 
-fn has_fn(imp: &ast::Impl, rhs_name: &str) -> bool {
+fn has_any_fn(imp: &ast::Impl, names: &[String]) -> bool {
     if let Some(il) = imp.assoc_item_list() {
         for item in il.assoc_items() {
             if let ast::AssocItem::Fn(f) = item {
                 if let Some(name) = f.name() {
-                    if name.text().eq_ignore_ascii_case(rhs_name) {
+                    if names.iter().any(|n| n.eq_ignore_ascii_case(&name.text())) {
                         return true;
                     }
                 }
diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/incorrect_try_expr.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/incorrect_try_expr.rs
deleted file mode 100644
index 085d8d32598..00000000000
--- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/incorrect_try_expr.rs
+++ /dev/null
@@ -1,37 +0,0 @@
-use hir::InFile;
-
-use crate::{Diagnostic, DiagnosticsContext};
-
-// Diagnostic: incorrect-try-target
-//
-// This diagnostic is triggered if a question mark operator was used in a context where it is not applicable.
-pub(crate) fn incorrect_try_expr(
-    ctx: &DiagnosticsContext<'_>,
-    d: &hir::IncorrectTryExpr,
-) -> Diagnostic {
-    Diagnostic::new(
-        "incorrect-try-target",
-        format!("the return type of the containing function does not implement `FromResidual`"),
-        ctx.sema
-            .diagnostics_display_range(InFile::new(d.expr.file_id, d.expr.value.clone().into()))
-            .range,
-    )
-}
-
-#[cfg(test)]
-mod tests {
-    use crate::tests::check_diagnostics;
-
-    #[test]
-    fn try_ops_diag() {
-        check_diagnostics(
-            r#"
-//- minicore: try
-fn test() {
-    core::ops::ControlFlow::<u32, f32>::Continue(1.0)?;
- // ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: the return type of the containing function does not implement `FromResidual`
-}
-"#,
-        );
-    }
-}
diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/not_implemented.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/not_implemented.rs
deleted file mode 100644
index 3bf6a423229..00000000000
--- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/not_implemented.rs
+++ /dev/null
@@ -1,35 +0,0 @@
-use hir::{db::DefDatabase, HirDisplay};
-
-use crate::{Diagnostic, DiagnosticsContext};
-
-// Diagnostic: not-implemented
-//
-// This diagnostic is triggered if a type doesn't implement a necessary trait.
-pub(crate) fn not_implemented(ctx: &DiagnosticsContext<'_>, d: &hir::NotImplemented) -> Diagnostic {
-    Diagnostic::new(
-        "not-implemented",
-        format!(
-            "the trait `{}` is not implemented for `{}`",
-            ctx.sema.db.trait_data(d.trait_).name,
-            d.ty.display(ctx.sema.db)
-        ),
-        ctx.sema.diagnostics_display_range(d.expr.clone().map(|it| it.into())).range,
-    )
-}
-
-#[cfg(test)]
-mod tests {
-    use crate::tests::check_diagnostics;
-
-    #[test]
-    fn missing_try_impl() {
-        check_diagnostics(
-            r#"
-//- minicore: try
-fn main() {
-    ()?;
-} //^^ error: the trait `Try` is not implemented for `()`
-"#,
-        )
-    }
-}
diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/lib.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/lib.rs
index 4577072149a..ae299f05841 100644
--- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/lib.rs
+++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/lib.rs
@@ -29,7 +29,6 @@ mod handlers {
     pub(crate) mod break_outside_of_loop;
     pub(crate) mod inactive_code;
     pub(crate) mod incorrect_case;
-    pub(crate) mod incorrect_try_expr;
     pub(crate) mod invalid_derive_target;
     pub(crate) mod macro_error;
     pub(crate) mod malformed_derive;
@@ -37,7 +36,6 @@ mod handlers {
     pub(crate) mod missing_fields;
     pub(crate) mod missing_match_arms;
     pub(crate) mod missing_unsafe;
-    pub(crate) mod not_implemented;
     pub(crate) mod no_such_field;
     pub(crate) mod replace_filter_map_next_with_find_map;
     pub(crate) mod type_mismatch;
@@ -227,14 +225,12 @@ pub fn diagnostics(
         let d = match diag {
             AnyDiagnostic::BreakOutsideOfLoop(d) => handlers::break_outside_of_loop::break_outside_of_loop(&ctx, &d),
             AnyDiagnostic::IncorrectCase(d) => handlers::incorrect_case::incorrect_case(&ctx, &d),
-            AnyDiagnostic::IncorrectTryExpr(d) => handlers::incorrect_try_expr::incorrect_try_expr(&ctx, &d),
             AnyDiagnostic::MacroError(d) => handlers::macro_error::macro_error(&ctx, &d),
             AnyDiagnostic::MalformedDerive(d) => handlers::malformed_derive::malformed_derive(&ctx, &d),
             AnyDiagnostic::MismatchedArgCount(d) => handlers::mismatched_arg_count::mismatched_arg_count(&ctx, &d),
             AnyDiagnostic::MissingFields(d) => handlers::missing_fields::missing_fields(&ctx, &d),
             AnyDiagnostic::MissingMatchArms(d) => handlers::missing_match_arms::missing_match_arms(&ctx, &d),
             AnyDiagnostic::MissingUnsafe(d) => handlers::missing_unsafe::missing_unsafe(&ctx, &d),
-            AnyDiagnostic::NotImplemented(d) => handlers::not_implemented::not_implemented(&ctx, &d),
             AnyDiagnostic::NoSuchField(d) => handlers::no_such_field::no_such_field(&ctx, &d),
             AnyDiagnostic::ReplaceFilterMapNextWithFindMap(d) => handlers::replace_filter_map_next_with_find_map::replace_filter_map_next_with_find_map(&ctx, &d),
             AnyDiagnostic::TypeMismatch(d) => handlers::type_mismatch::type_mismatch(&ctx, &d),
diff --git a/src/tools/rust-analyzer/crates/ide/src/hover/tests.rs b/src/tools/rust-analyzer/crates/ide/src/hover/tests.rs
index 5cab017a58d..eb997e6fef8 100644
--- a/src/tools/rust-analyzer/crates/ide/src/hover/tests.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/hover/tests.rs
@@ -4913,22 +4913,6 @@ fn foo() -> NotResult<(), Short> {
                 ```
             "#]],
     );
-    check_hover_range(
-        r#"
-//- minicore: try
-use core::ops::ControlFlow;
-fn foo() -> ControlFlow<()> {
-    $0ControlFlow::Break(())?$0;
-    ControlFlow::Continue(())
-}
-"#,
-        expect![[r#"
-            ```text
-            Try Target Type: ControlFlow<(), {unknown}>
-            Propagated as:          ControlFlow<(), ()>
-            ```
-        "#]],
-    );
 }
 
 #[test]
@@ -4944,9 +4928,9 @@ fn foo() -> Option<()> {
 }
 "#,
         expect![[r#"
-            ```rust
-            i32
-            ```"#]],
+                ```rust
+                <Option<i32> as Try>::Output
+                ```"#]],
     );
 }
 
diff --git a/src/tools/rust-analyzer/crates/ide/src/lib.rs b/src/tools/rust-analyzer/crates/ide/src/lib.rs
index 77fe0dbf556..416817ca0b4 100644
--- a/src/tools/rust-analyzer/crates/ide/src/lib.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/lib.rs
@@ -482,8 +482,18 @@ impl Analysis {
     }
 
     /// Returns crates this file belongs too.
-    pub fn crate_for(&self, file_id: FileId) -> Cancellable<Vec<CrateId>> {
-        self.with_db(|db| parent_module::crate_for(db, file_id))
+    pub fn crates_for(&self, file_id: FileId) -> Cancellable<Vec<CrateId>> {
+        self.with_db(|db| parent_module::crates_for(db, file_id))
+    }
+
+    /// Returns crates this file belongs too.
+    pub fn transitive_rev_deps(&self, crate_id: CrateId) -> Cancellable<Vec<CrateId>> {
+        self.with_db(|db| db.crate_graph().transitive_rev_deps(crate_id).collect())
+    }
+
+    /// Returns crates this file *might* belong too.
+    pub fn relevant_crates_for(&self, file_id: FileId) -> Cancellable<Vec<CrateId>> {
+        self.with_db(|db| db.relevant_crates(file_id).iter().copied().collect())
     }
 
     /// Returns the edition of the given crate.
diff --git a/src/tools/rust-analyzer/crates/ide/src/parent_module.rs b/src/tools/rust-analyzer/crates/ide/src/parent_module.rs
index 8f3cc86873f..506f9452cf1 100644
--- a/src/tools/rust-analyzer/crates/ide/src/parent_module.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/parent_module.rs
@@ -1,6 +1,6 @@
-use hir::Semantics;
+use hir::{db::DefDatabase, Semantics};
 use ide_db::{
-    base_db::{CrateId, FileId, FilePosition},
+    base_db::{CrateId, FileId, FileLoader, FilePosition},
     RootDatabase,
 };
 use itertools::Itertools;
@@ -55,9 +55,13 @@ pub(crate) fn parent_module(db: &RootDatabase, position: FilePosition) -> Vec<Na
 }
 
 /// Returns `Vec` for the same reason as `parent_module`
-pub(crate) fn crate_for(db: &RootDatabase, file_id: FileId) -> Vec<CrateId> {
-    let sema = Semantics::new(db);
-    sema.to_module_defs(file_id).map(|module| module.krate().into()).unique().collect()
+pub(crate) fn crates_for(db: &RootDatabase, file_id: FileId) -> Vec<CrateId> {
+    db.relevant_crates(file_id)
+        .iter()
+        .copied()
+        .filter(|&crate_id| db.crate_def_map(crate_id).modules_for_file(file_id).next().is_some())
+        .sorted()
+        .collect()
 }
 
 #[cfg(test)]
@@ -147,7 +151,7 @@ $0
 mod foo;
 "#,
         );
-        assert_eq!(analysis.crate_for(file_id).unwrap().len(), 1);
+        assert_eq!(analysis.crates_for(file_id).unwrap().len(), 1);
     }
 
     #[test]
@@ -162,6 +166,6 @@ mod baz;
 mod baz;
 "#,
         );
-        assert_eq!(analysis.crate_for(file_id).unwrap().len(), 2);
+        assert_eq!(analysis.crates_for(file_id).unwrap().len(), 2);
     }
 }
diff --git a/src/tools/rust-analyzer/crates/ide/src/static_index.rs b/src/tools/rust-analyzer/crates/ide/src/static_index.rs
index 9e5eb909508..27ad1a948d1 100644
--- a/src/tools/rust-analyzer/crates/ide/src/static_index.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/static_index.rs
@@ -210,9 +210,7 @@ fn get_definition(sema: &Semantics<'_, RootDatabase>, token: SyntaxToken) -> Opt
         let def = IdentClass::classify_token(sema, &token).map(IdentClass::definitions_no_ops);
         if let Some(&[x]) = def.as_deref() {
             return Some(x);
-        } else {
-            continue;
-        };
+        }
     }
     None
 }
diff --git a/src/tools/rust-analyzer/crates/ide/src/status.rs b/src/tools/rust-analyzer/crates/ide/src/status.rs
index f4d0387440d..20810c25b3e 100644
--- a/src/tools/rust-analyzer/crates/ide/src/status.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/status.rs
@@ -45,7 +45,7 @@ pub(crate) fn status(db: &RootDatabase, file_id: Option<FileId>) -> String {
 
     if let Some(file_id) = file_id {
         format_to!(buf, "\nFile info:\n");
-        let crates = crate::parent_module::crate_for(db, file_id);
+        let crates = crate::parent_module::crates_for(db, file_id);
         if crates.is_empty() {
             format_to!(buf, "Does not belong to any crate");
         }
diff --git a/src/tools/rust-analyzer/crates/project-model/Cargo.toml b/src/tools/rust-analyzer/crates/project-model/Cargo.toml
index 6fd7c3166f8..cf9868740cb 100644
--- a/src/tools/rust-analyzer/crates/project-model/Cargo.toml
+++ b/src/tools/rust-analyzer/crates/project-model/Cargo.toml
@@ -17,7 +17,6 @@ semver = "1.0.14"
 serde = { version = "1.0.137", features = ["derive"] }
 serde_json = "1.0.86"
 anyhow = "1.0.62"
-expect-test = "1.4.0"
 la-arena = { version = "0.3.0", path = "../../lib/la-arena" }
 
 cfg = { path = "../cfg", version = "0.0.0" }
@@ -26,3 +25,6 @@ toolchain = { path = "../toolchain", version = "0.0.0" }
 paths = { path = "../paths", version = "0.0.0" }
 stdx = { path = "../stdx", version = "0.0.0" }
 profile = { path = "../profile", version = "0.0.0" }
+
+[dev-dependencies]
+expect-test = "1.4.0"
diff --git a/src/tools/rust-analyzer/crates/project-model/src/build_scripts.rs b/src/tools/rust-analyzer/crates/project-model/src/build_scripts.rs
index d9f09c03495..a26a7c57acf 100644
--- a/src/tools/rust-analyzer/crates/project-model/src/build_scripts.rs
+++ b/src/tools/rust-analyzer/crates/project-model/src/build_scripts.rs
@@ -6,7 +6,12 @@
 //! This module implements this second part. We use "build script" terminology
 //! here, but it covers procedural macros as well.
 
-use std::{cell::RefCell, io, path::PathBuf, process::Command};
+use std::{
+    cell::RefCell,
+    io, mem,
+    path::{self, PathBuf},
+    process::Command,
+};
 
 use cargo_metadata::{camino::Utf8Path, Message};
 use la_arena::ArenaMap;
@@ -15,11 +20,14 @@ use rustc_hash::FxHashMap;
 use semver::Version;
 use serde::Deserialize;
 
-use crate::{cfg_flag::CfgFlag, CargoConfig, CargoFeatures, CargoWorkspace, Package};
+use crate::{
+    cfg_flag::CfgFlag, CargoConfig, CargoFeatures, CargoWorkspace, InvocationLocation,
+    InvocationStrategy, Package,
+};
 
 #[derive(Debug, Default, Clone, PartialEq, Eq)]
 pub struct WorkspaceBuildScripts {
-    outputs: ArenaMap<Package, Option<BuildScriptOutput>>,
+    outputs: ArenaMap<Package, BuildScriptOutput>,
     error: Option<String>,
 }
 
@@ -38,47 +46,71 @@ pub(crate) struct BuildScriptOutput {
     pub(crate) proc_macro_dylib_path: Option<AbsPathBuf>,
 }
 
-impl WorkspaceBuildScripts {
-    fn build_command(config: &CargoConfig) -> Command {
-        if let Some([program, args @ ..]) = config.run_build_script_command.as_deref() {
-            let mut cmd = Command::new(program);
-            cmd.args(args);
-            cmd.envs(&config.extra_env);
-            return cmd;
-        }
+impl BuildScriptOutput {
+    fn is_unchanged(&self) -> bool {
+        self.cfgs.is_empty()
+            && self.envs.is_empty()
+            && self.out_dir.is_none()
+            && self.proc_macro_dylib_path.is_none()
+    }
+}
 
-        let mut cmd = Command::new(toolchain::cargo());
-        cmd.envs(&config.extra_env);
-        cmd.args(&["check", "--quiet", "--workspace", "--message-format=json"]);
+impl WorkspaceBuildScripts {
+    fn build_command(config: &CargoConfig) -> io::Result<Command> {
+        let mut cmd = match config.run_build_script_command.as_deref() {
+            Some([program, args @ ..]) => {
+                let mut cmd = Command::new(program);
+                cmd.args(args);
+                cmd
+            }
+            _ => {
+                let mut cmd = Command::new(toolchain::cargo());
 
-        // --all-targets includes tests, benches and examples in addition to the
-        // default lib and bins. This is an independent concept from the --targets
-        // flag below.
-        cmd.arg("--all-targets");
+                cmd.args(&["check", "--quiet", "--workspace", "--message-format=json"]);
 
-        if let Some(target) = &config.target {
-            cmd.args(&["--target", target]);
-        }
+                // --all-targets includes tests, benches and examples in addition to the
+                // default lib and bins. This is an independent concept from the --targets
+                // flag below.
+                cmd.arg("--all-targets");
 
-        match &config.features {
-            CargoFeatures::All => {
-                cmd.arg("--all-features");
-            }
-            CargoFeatures::Selected { features, no_default_features } => {
-                if *no_default_features {
-                    cmd.arg("--no-default-features");
+                if let Some(target) = &config.target {
+                    cmd.args(&["--target", target]);
                 }
-                if !features.is_empty() {
-                    cmd.arg("--features");
-                    cmd.arg(features.join(" "));
+
+                match &config.features {
+                    CargoFeatures::All => {
+                        cmd.arg("--all-features");
+                    }
+                    CargoFeatures::Selected { features, no_default_features } => {
+                        if *no_default_features {
+                            cmd.arg("--no-default-features");
+                        }
+                        if !features.is_empty() {
+                            cmd.arg("--features");
+                            cmd.arg(features.join(" "));
+                        }
+                    }
                 }
+
+                cmd
             }
+        };
+
+        cmd.envs(&config.extra_env);
+        if config.wrap_rustc_in_build_scripts {
+            // Setup RUSTC_WRAPPER to point to `rust-analyzer` binary itself. We use
+            // that to compile only proc macros and build scripts during the initial
+            // `cargo check`.
+            let myself = std::env::current_exe()?;
+            cmd.env("RUSTC_WRAPPER", myself);
+            cmd.env("RA_RUSTC_WRAPPER", "1");
         }
 
-        cmd
+        Ok(cmd)
     }
 
-    pub(crate) fn run(
+    /// Runs the build scripts for the given workspace
+    pub(crate) fn run_for_workspace(
         config: &CargoConfig,
         workspace: &CargoWorkspace,
         progress: &dyn Fn(String),
@@ -86,15 +118,23 @@ impl WorkspaceBuildScripts {
     ) -> io::Result<WorkspaceBuildScripts> {
         const RUST_1_62: Version = Version::new(1, 62, 0);
 
-        match Self::run_(Self::build_command(config), config, workspace, progress) {
+        let current_dir = match &config.invocation_location {
+            InvocationLocation::Root(root) if config.run_build_script_command.is_some() => {
+                root.as_path()
+            }
+            _ => &workspace.workspace_root(),
+        }
+        .as_ref();
+
+        match Self::run_per_ws(Self::build_command(config)?, workspace, current_dir, progress) {
             Ok(WorkspaceBuildScripts { error: Some(error), .. })
                 if toolchain.as_ref().map_or(false, |it| *it >= RUST_1_62) =>
             {
                 // building build scripts failed, attempt to build with --keep-going so
                 // that we potentially get more build data
-                let mut cmd = Self::build_command(config);
+                let mut cmd = Self::build_command(config)?;
                 cmd.args(&["-Z", "unstable-options", "--keep-going"]).env("RUSTC_BOOTSTRAP", "1");
-                let mut res = Self::run_(cmd, config, workspace, progress)?;
+                let mut res = Self::run_per_ws(cmd, workspace, current_dir, progress)?;
                 res.error = Some(error);
                 Ok(res)
             }
@@ -102,23 +142,90 @@ impl WorkspaceBuildScripts {
         }
     }
 
-    fn run_(
-        mut cmd: Command,
+    /// Runs the build scripts by invoking the configured command *once*.
+    /// This populates the outputs for all passed in workspaces.
+    pub(crate) fn run_once(
         config: &CargoConfig,
-        workspace: &CargoWorkspace,
+        workspaces: &[&CargoWorkspace],
         progress: &dyn Fn(String),
-    ) -> io::Result<WorkspaceBuildScripts> {
-        if config.wrap_rustc_in_build_scripts {
-            // Setup RUSTC_WRAPPER to point to `rust-analyzer` binary itself. We use
-            // that to compile only proc macros and build scripts during the initial
-            // `cargo check`.
-            let myself = std::env::current_exe()?;
-            cmd.env("RUSTC_WRAPPER", myself);
-            cmd.env("RA_RUSTC_WRAPPER", "1");
+    ) -> io::Result<Vec<WorkspaceBuildScripts>> {
+        assert_eq!(config.invocation_strategy, InvocationStrategy::Once);
+
+        let current_dir = match &config.invocation_location {
+            InvocationLocation::Root(root) => root,
+            InvocationLocation::Workspace => {
+                return Err(io::Error::new(
+                    io::ErrorKind::Other,
+                    "Cannot run build scripts from workspace with invocation strategy `once`",
+                ))
+            }
+        };
+        let cmd = Self::build_command(config)?;
+        // NB: Cargo.toml could have been modified between `cargo metadata` and
+        // `cargo check`. We shouldn't assume that package ids we see here are
+        // exactly those from `config`.
+        let mut by_id = FxHashMap::default();
+        // some workspaces might depend on the same crates, so we need to duplicate the outputs
+        // to those collisions
+        let mut collisions = Vec::new();
+        let mut res: Vec<_> = workspaces
+            .iter()
+            .enumerate()
+            .map(|(idx, workspace)| {
+                let mut res = WorkspaceBuildScripts::default();
+                for package in workspace.packages() {
+                    res.outputs.insert(package, BuildScriptOutput::default());
+                    if by_id.contains_key(&workspace[package].id) {
+                        collisions.push((&workspace[package].id, idx, package));
+                    } else {
+                        by_id.insert(workspace[package].id.clone(), (package, idx));
+                    }
+                }
+                res
+            })
+            .collect();
+
+        let errors = Self::run_command(
+            cmd,
+            current_dir.as_path().as_ref(),
+            |package, cb| {
+                if let Some(&(package, workspace)) = by_id.get(package) {
+                    cb(&workspaces[workspace][package].name, &mut res[workspace].outputs[package]);
+                }
+            },
+            progress,
+        )?;
+        res.iter_mut().for_each(|it| it.error = errors.clone());
+        collisions.into_iter().for_each(|(id, workspace, package)| {
+            if let Some(&(p, w)) = by_id.get(id) {
+                res[workspace].outputs[package] = res[w].outputs[p].clone();
+            }
+        });
+
+        if tracing::enabled!(tracing::Level::INFO) {
+            for (idx, workspace) in workspaces.iter().enumerate() {
+                for package in workspace.packages() {
+                    let package_build_data = &mut res[idx].outputs[package];
+                    if !package_build_data.is_unchanged() {
+                        tracing::info!(
+                            "{}: {:?}",
+                            workspace[package].manifest.parent().display(),
+                            package_build_data,
+                        );
+                    }
+                }
+            }
         }
 
-        cmd.current_dir(workspace.workspace_root());
+        Ok(res)
+    }
 
+    fn run_per_ws(
+        cmd: Command,
+        workspace: &CargoWorkspace,
+        current_dir: &path::Path,
+        progress: &dyn Fn(String),
+    ) -> io::Result<WorkspaceBuildScripts> {
         let mut res = WorkspaceBuildScripts::default();
         let outputs = &mut res.outputs;
         // NB: Cargo.toml could have been modified between `cargo metadata` and
@@ -126,10 +233,46 @@ impl WorkspaceBuildScripts {
         // exactly those from `config`.
         let mut by_id: FxHashMap<String, Package> = FxHashMap::default();
         for package in workspace.packages() {
-            outputs.insert(package, None);
+            outputs.insert(package, BuildScriptOutput::default());
             by_id.insert(workspace[package].id.clone(), package);
         }
 
+        res.error = Self::run_command(
+            cmd,
+            current_dir,
+            |package, cb| {
+                if let Some(&package) = by_id.get(package) {
+                    cb(&workspace[package].name, &mut outputs[package]);
+                }
+            },
+            progress,
+        )?;
+
+        if tracing::enabled!(tracing::Level::INFO) {
+            for package in workspace.packages() {
+                let package_build_data = &mut outputs[package];
+                if !package_build_data.is_unchanged() {
+                    tracing::info!(
+                        "{}: {:?}",
+                        workspace[package].manifest.parent().display(),
+                        package_build_data,
+                    );
+                }
+            }
+        }
+
+        Ok(res)
+    }
+
+    fn run_command(
+        mut cmd: Command,
+        current_dir: &path::Path,
+        // ideally this would be something like:
+        // with_output_for: impl FnMut(&str, dyn FnOnce(&mut BuildScriptOutput)),
+        // but owned trait objects aren't a thing
+        mut with_output_for: impl FnMut(&str, &mut dyn FnMut(&str, &mut BuildScriptOutput)),
+        progress: &dyn Fn(String),
+    ) -> io::Result<Option<String>> {
         let errors = RefCell::new(String::new());
         let push_err = |err: &str| {
             let mut e = errors.borrow_mut();
@@ -137,7 +280,8 @@ impl WorkspaceBuildScripts {
             e.push('\n');
         };
 
-        tracing::info!("Running build scripts: {:?}", cmd);
+        tracing::info!("Running build scripts in {}: {:?}", current_dir.display(), cmd);
+        cmd.current_dir(current_dir);
         let output = stdx::process::spawn_with_streaming_output(
             cmd,
             &mut |line| {
@@ -149,61 +293,58 @@ impl WorkspaceBuildScripts {
                     .unwrap_or_else(|_| Message::TextLine(line.to_string()));
 
                 match message {
-                    Message::BuildScriptExecuted(message) => {
-                        let package = match by_id.get(&message.package_id.repr) {
-                            Some(&it) => it,
-                            None => return,
-                        };
-                        progress(format!("running build-script: {}", workspace[package].name));
-
-                        let cfgs = {
-                            let mut acc = Vec::new();
-                            for cfg in message.cfgs {
-                                match cfg.parse::<CfgFlag>() {
-                                    Ok(it) => acc.push(it),
-                                    Err(err) => {
-                                        push_err(&format!(
-                                            "invalid cfg from cargo-metadata: {}",
-                                            err
-                                        ));
-                                        return;
-                                    }
-                                };
+                    Message::BuildScriptExecuted(mut message) => {
+                        with_output_for(&message.package_id.repr, &mut |name, data| {
+                            progress(format!("running build-script: {}", name));
+                            let cfgs = {
+                                let mut acc = Vec::new();
+                                for cfg in &message.cfgs {
+                                    match cfg.parse::<CfgFlag>() {
+                                        Ok(it) => acc.push(it),
+                                        Err(err) => {
+                                            push_err(&format!(
+                                                "invalid cfg from cargo-metadata: {}",
+                                                err
+                                            ));
+                                            return;
+                                        }
+                                    };
+                                }
+                                acc
+                            };
+                            if !message.env.is_empty() {
+                                data.envs = mem::take(&mut message.env);
                             }
-                            acc
-                        };
-                        // cargo_metadata crate returns default (empty) path for
-                        // older cargos, which is not absolute, so work around that.
-                        let out_dir = message.out_dir.into_os_string();
-                        if !out_dir.is_empty() {
-                            let data = outputs[package].get_or_insert_with(Default::default);
-                            data.out_dir = Some(AbsPathBuf::assert(PathBuf::from(out_dir)));
-                            data.cfgs = cfgs;
-                        }
-                        if !message.env.is_empty() {
-                            outputs[package].get_or_insert_with(Default::default).envs =
-                                message.env;
-                        }
+                            // cargo_metadata crate returns default (empty) path for
+                            // older cargos, which is not absolute, so work around that.
+                            let out_dir = mem::take(&mut message.out_dir).into_os_string();
+                            if !out_dir.is_empty() {
+                                let out_dir = AbsPathBuf::assert(PathBuf::from(out_dir));
+                                // inject_cargo_env(package, package_build_data);
+                                // NOTE: cargo and rustc seem to hide non-UTF-8 strings from env! and option_env!()
+                                if let Some(out_dir) =
+                                    out_dir.as_os_str().to_str().map(|s| s.to_owned())
+                                {
+                                    data.envs.push(("OUT_DIR".to_string(), out_dir));
+                                }
+                                data.out_dir = Some(out_dir);
+                                data.cfgs = cfgs;
+                            }
+                        });
                     }
                     Message::CompilerArtifact(message) => {
-                        let package = match by_id.get(&message.package_id.repr) {
-                            Some(it) => *it,
-                            None => return,
-                        };
-
-                        progress(format!("building proc-macros: {}", message.target.name));
-
-                        if message.target.kind.iter().any(|k| k == "proc-macro") {
-                            // Skip rmeta file
-                            if let Some(filename) =
-                                message.filenames.iter().find(|name| is_dylib(name))
-                            {
-                                let filename = AbsPathBuf::assert(PathBuf::from(&filename));
-                                outputs[package]
-                                    .get_or_insert_with(Default::default)
-                                    .proc_macro_dylib_path = Some(filename);
+                        with_output_for(&message.package_id.repr, &mut |name, data| {
+                            progress(format!("building proc-macros: {}", name));
+                            if message.target.kind.iter().any(|k| k == "proc-macro") {
+                                // Skip rmeta file
+                                if let Some(filename) =
+                                    message.filenames.iter().find(|name| is_dylib(name))
+                                {
+                                    let filename = AbsPathBuf::assert(PathBuf::from(&filename));
+                                    data.proc_macro_dylib_path = Some(filename);
+                                }
                             }
-                        }
+                        });
                     }
                     Message::CompilerMessage(message) => {
                         progress(message.target.name);
@@ -222,32 +363,13 @@ impl WorkspaceBuildScripts {
             },
         )?;
 
-        for package in workspace.packages() {
-            if let Some(package_build_data) = &mut outputs[package] {
-                tracing::info!(
-                    "{}: {:?}",
-                    workspace[package].manifest.parent().display(),
-                    package_build_data,
-                );
-                // inject_cargo_env(package, package_build_data);
-                if let Some(out_dir) = &package_build_data.out_dir {
-                    // NOTE: cargo and rustc seem to hide non-UTF-8 strings from env! and option_env!()
-                    if let Some(out_dir) = out_dir.as_os_str().to_str().map(|s| s.to_owned()) {
-                        package_build_data.envs.push(("OUT_DIR".to_string(), out_dir));
-                    }
-                }
-            }
-        }
-
-        let mut errors = errors.into_inner();
-        if !output.status.success() {
-            if errors.is_empty() {
-                errors = "cargo check failed".to_string();
-            }
-            res.error = Some(errors);
-        }
-
-        Ok(res)
+        let errors = if !output.status.success() {
+            let errors = errors.into_inner();
+            Some(if errors.is_empty() { "cargo check failed".to_string() } else { errors })
+        } else {
+            None
+        };
+        Ok(errors)
     }
 
     pub fn error(&self) -> Option<&str> {
@@ -255,11 +377,11 @@ impl WorkspaceBuildScripts {
     }
 
     pub(crate) fn get_output(&self, idx: Package) -> Option<&BuildScriptOutput> {
-        self.outputs.get(idx)?.as_ref()
+        self.outputs.get(idx)
     }
 }
 
-// FIXME: File a better way to know if it is a dylib.
+// FIXME: Find a better way to know if it is a dylib.
 fn is_dylib(path: &Utf8Path) -> bool {
     match path.extension().map(|e| e.to_string().to_lowercase()) {
         None => false,
diff --git a/src/tools/rust-analyzer/crates/project-model/src/cargo_workspace.rs b/src/tools/rust-analyzer/crates/project-model/src/cargo_workspace.rs
index 8e690f1125a..b4c2ba43677 100644
--- a/src/tools/rust-analyzer/crates/project-model/src/cargo_workspace.rs
+++ b/src/tools/rust-analyzer/crates/project-model/src/cargo_workspace.rs
@@ -14,8 +14,8 @@ use rustc_hash::FxHashMap;
 use serde::Deserialize;
 use serde_json::from_value;
 
-use crate::CfgOverrides;
-use crate::{utf8_stdout, ManifestPath};
+use crate::{utf8_stdout, InvocationLocation, ManifestPath};
+use crate::{CfgOverrides, InvocationStrategy};
 
 /// [`CargoWorkspace`] represents the logical structure of, well, a Cargo
 /// workspace. It pretty closely mirrors `cargo metadata` output.
@@ -106,6 +106,8 @@ pub struct CargoConfig {
     pub run_build_script_command: Option<Vec<String>>,
     /// Extra env vars to set when invoking the cargo command
     pub extra_env: FxHashMap<String, String>,
+    pub invocation_strategy: InvocationStrategy,
+    pub invocation_location: InvocationLocation,
 }
 
 impl CargoConfig {
@@ -283,8 +285,6 @@ impl CargoWorkspace {
             }
             CargoFeatures::Selected { features, no_default_features } => {
                 if *no_default_features {
-                    // FIXME: `NoDefaultFeatures` is mutual exclusive with `SomeFeatures`
-                    // https://github.com/oli-obk/cargo_metadata/issues/79
                     meta.features(CargoOpt::NoDefaultFeatures);
                 }
                 if !features.is_empty() {
@@ -329,18 +329,21 @@ impl CargoWorkspace {
         let ws_members = &meta.workspace_members;
 
         meta.packages.sort_by(|a, b| a.id.cmp(&b.id));
-        for meta_pkg in &meta.packages {
+        for meta_pkg in meta.packages {
             let cargo_metadata::Package {
-                id,
-                edition,
                 name,
-                manifest_path,
                 version,
-                metadata,
+                id,
+                source,
+                targets: meta_targets,
+                features,
+                manifest_path,
                 repository,
+                edition,
+                metadata,
                 ..
             } = meta_pkg;
-            let meta = from_value::<PackageMetadata>(metadata.clone()).unwrap_or_default();
+            let meta = from_value::<PackageMetadata>(metadata).unwrap_or_default();
             let edition = match edition {
                 cargo_metadata::Edition::E2015 => Edition::Edition2015,
                 cargo_metadata::Edition::E2018 => Edition::Edition2018,
@@ -352,35 +355,36 @@ impl CargoWorkspace {
             };
             // We treat packages without source as "local" packages. That includes all members of
             // the current workspace, as well as any path dependency outside the workspace.
-            let is_local = meta_pkg.source.is_none();
-            let is_member = ws_members.contains(id);
+            let is_local = source.is_none();
+            let is_member = ws_members.contains(&id);
 
             let pkg = packages.alloc(PackageData {
                 id: id.repr.clone(),
-                name: name.clone(),
-                version: version.clone(),
-                manifest: AbsPathBuf::assert(PathBuf::from(&manifest_path)).try_into().unwrap(),
+                name,
+                version,
+                manifest: AbsPathBuf::assert(manifest_path.into()).try_into().unwrap(),
                 targets: Vec::new(),
                 is_local,
                 is_member,
                 edition,
-                repository: repository.clone(),
+                repository,
                 dependencies: Vec::new(),
-                features: meta_pkg.features.clone().into_iter().collect(),
+                features: features.into_iter().collect(),
                 active_features: Vec::new(),
                 metadata: meta.rust_analyzer.unwrap_or_default(),
             });
             let pkg_data = &mut packages[pkg];
             pkg_by_id.insert(id, pkg);
-            for meta_tgt in &meta_pkg.targets {
-                let is_proc_macro = meta_tgt.kind.as_slice() == ["proc-macro"];
+            for meta_tgt in meta_targets {
+                let cargo_metadata::Target { name, kind, required_features, src_path, .. } =
+                    meta_tgt;
                 let tgt = targets.alloc(TargetData {
                     package: pkg,
-                    name: meta_tgt.name.clone(),
-                    root: AbsPathBuf::assert(PathBuf::from(&meta_tgt.src_path)),
-                    kind: TargetKind::new(meta_tgt.kind.as_slice()),
-                    is_proc_macro,
-                    required_features: meta_tgt.required_features.clone(),
+                    name,
+                    root: AbsPathBuf::assert(src_path.into()),
+                    kind: TargetKind::new(&kind),
+                    is_proc_macro: &*kind == ["proc-macro"],
+                    required_features,
                 });
                 pkg_data.targets.push(tgt);
             }
diff --git a/src/tools/rust-analyzer/crates/project-model/src/lib.rs b/src/tools/rust-analyzer/crates/project-model/src/lib.rs
index ce78ce85697..575581fa543 100644
--- a/src/tools/rust-analyzer/crates/project-model/src/lib.rs
+++ b/src/tools/rust-analyzer/crates/project-model/src/lib.rs
@@ -67,7 +67,7 @@ impl ProjectManifest {
         if path.file_name().unwrap_or_default() == "Cargo.toml" {
             return Ok(ProjectManifest::CargoToml(path));
         }
-        bail!("project root must point to Cargo.toml or rust-project.json: {}", path.display())
+        bail!("project root must point to Cargo.toml or rust-project.json: {}", path.display());
     }
 
     pub fn discover_single(path: &AbsPath) -> Result<ProjectManifest> {
@@ -78,7 +78,7 @@ impl ProjectManifest {
         };
 
         if !candidates.is_empty() {
-            bail!("more than one project")
+            bail!("more than one project");
         }
         Ok(res)
     }
@@ -157,3 +157,17 @@ fn utf8_stdout(mut cmd: Command) -> Result<String> {
     let stdout = String::from_utf8(output.stdout)?;
     Ok(stdout.trim().to_string())
 }
+
+#[derive(Copy, Clone, Debug, Default, PartialEq, Eq)]
+pub enum InvocationStrategy {
+    Once,
+    #[default]
+    PerWorkspace,
+}
+
+#[derive(Clone, Debug, Default, PartialEq, Eq)]
+pub enum InvocationLocation {
+    Root(AbsPathBuf),
+    #[default]
+    Workspace,
+}
diff --git a/src/tools/rust-analyzer/crates/project-model/src/sysroot.rs b/src/tools/rust-analyzer/crates/project-model/src/sysroot.rs
index bc37e3d132a..fa8d76f3f45 100644
--- a/src/tools/rust-analyzer/crates/project-model/src/sysroot.rs
+++ b/src/tools/rust-analyzer/crates/project-model/src/sysroot.rs
@@ -64,14 +64,15 @@ impl Sysroot {
         self.by_name("proc_macro")
     }
 
-    pub fn crates<'a>(&'a self) -> impl Iterator<Item = SysrootCrate> + ExactSizeIterator + 'a {
+    pub fn crates(&self) -> impl Iterator<Item = SysrootCrate> + ExactSizeIterator + '_ {
         self.crates.iter().map(|(id, _data)| id)
     }
 }
 
 impl Sysroot {
+    /// Attempts to discover the toolchain's sysroot from the given `dir`.
     pub fn discover(dir: &AbsPath, extra_env: &FxHashMap<String, String>) -> Result<Sysroot> {
-        tracing::debug!("Discovering sysroot for {}", dir.display());
+        tracing::debug!("discovering sysroot for {}", dir.display());
         let sysroot_dir = discover_sysroot_dir(dir, extra_env)?;
         let sysroot_src_dir =
             discover_sysroot_src_dir_or_add_component(&sysroot_dir, dir, extra_env)?;
@@ -83,11 +84,10 @@ impl Sysroot {
         cargo_toml: &ManifestPath,
         extra_env: &FxHashMap<String, String>,
     ) -> Option<ManifestPath> {
-        tracing::debug!("Discovering rustc source for {}", cargo_toml.display());
+        tracing::debug!("discovering rustc source for {}", cargo_toml.display());
         let current_dir = cargo_toml.parent();
-        discover_sysroot_dir(current_dir, extra_env)
-            .ok()
-            .and_then(|sysroot_dir| get_rustc_src(&sysroot_dir))
+        let sysroot_dir = discover_sysroot_dir(current_dir, extra_env).ok()?;
+        get_rustc_src(&sysroot_dir)
     }
 
     pub fn with_sysroot_dir(sysroot_dir: AbsPathBuf) -> Result<Sysroot> {
@@ -189,6 +189,7 @@ fn discover_sysroot_src_dir(sysroot_path: &AbsPathBuf) -> Option<AbsPathBuf> {
 
     get_rust_src(sysroot_path)
 }
+
 fn discover_sysroot_src_dir_or_add_component(
     sysroot_path: &AbsPathBuf,
     current_dir: &AbsPath,
@@ -199,6 +200,7 @@ fn discover_sysroot_src_dir_or_add_component(
             let mut rustup = Command::new(toolchain::rustup());
             rustup.envs(extra_env);
             rustup.current_dir(current_dir).args(&["component", "add", "rust-src"]);
+            tracing::info!("adding rust-src component by {:?}", rustup);
             utf8_stdout(rustup).ok()?;
             get_rust_src(sysroot_path)
         })
@@ -217,7 +219,7 @@ try installing the Rust source the same way you installed rustc",
 fn get_rustc_src(sysroot_path: &AbsPath) -> Option<ManifestPath> {
     let rustc_src = sysroot_path.join("lib/rustlib/rustc-src/rust/compiler/rustc/Cargo.toml");
     let rustc_src = ManifestPath::try_from(rustc_src).ok()?;
-    tracing::debug!("Checking for rustc source code: {}", rustc_src.display());
+    tracing::debug!("checking for rustc source code: {}", rustc_src.display());
     if fs::metadata(&rustc_src).is_ok() {
         Some(rustc_src)
     } else {
@@ -227,7 +229,7 @@ fn get_rustc_src(sysroot_path: &AbsPath) -> Option<ManifestPath> {
 
 fn get_rust_src(sysroot_path: &AbsPath) -> Option<AbsPathBuf> {
     let rust_src = sysroot_path.join("lib/rustlib/src/rust/library");
-    tracing::debug!("Checking sysroot: {}", rust_src.display());
+    tracing::debug!("checking sysroot library: {}", rust_src.display());
     if fs::metadata(&rust_src).is_ok() {
         Some(rust_src)
     } else {
diff --git a/src/tools/rust-analyzer/crates/project-model/src/workspace.rs b/src/tools/rust-analyzer/crates/project-model/src/workspace.rs
index 72ddf809288..2780c62ed11 100644
--- a/src/tools/rust-analyzer/crates/project-model/src/workspace.rs
+++ b/src/tools/rust-analyzer/crates/project-model/src/workspace.rs
@@ -2,7 +2,7 @@
 //! metadata` or `rust-project.json`) into representation stored in the salsa
 //! database -- `CrateGraph`.
 
-use std::{collections::VecDeque, fmt, fs, process::Command};
+use std::{collections::VecDeque, fmt, fs, process::Command, sync::Arc};
 
 use anyhow::{format_err, Context, Result};
 use base_db::{
@@ -21,8 +21,8 @@ use crate::{
     cfg_flag::CfgFlag,
     rustc_cfg,
     sysroot::SysrootCrate,
-    utf8_stdout, CargoConfig, CargoWorkspace, ManifestPath, Package, ProjectJson, ProjectManifest,
-    Sysroot, TargetKind, WorkspaceBuildScripts,
+    utf8_stdout, CargoConfig, CargoWorkspace, InvocationStrategy, ManifestPath, Package,
+    ProjectJson, ProjectManifest, Sysroot, TargetKind, WorkspaceBuildScripts,
 };
 
 /// A set of cfg-overrides per crate.
@@ -209,6 +209,9 @@ impl ProjectWorkspace {
                     ),
                     None => None,
                 };
+                if let Some(sysroot) = &sysroot {
+                    tracing::info!(src_root = %sysroot.src_root().display(), root = %sysroot.root().display(), "Using sysroot");
+                }
 
                 let rustc_dir = match &config.rustc_source {
                     Some(RustcSource::Path(path)) => ManifestPath::try_from(path.clone()).ok(),
@@ -217,6 +220,9 @@ impl ProjectWorkspace {
                     }
                     None => None,
                 };
+                if let Some(rustc_dir) = &rustc_dir {
+                    tracing::info!(rustc_dir = %rustc_dir.display(), "Using rustc source");
+                }
 
                 let rustc = match rustc_dir {
                     Some(rustc_dir) => Some({
@@ -277,6 +283,9 @@ impl ProjectWorkspace {
             }
             (None, None) => None,
         };
+        if let Some(sysroot) = &sysroot {
+            tracing::info!(src_root = %sysroot.src_root().display(), root = %sysroot.root().display(), "Using sysroot");
+        }
 
         let rustc_cfg = rustc_cfg::get(None, target, extra_env);
         Ok(ProjectWorkspace::Json { project: project_json, sysroot, rustc_cfg })
@@ -294,6 +303,7 @@ impl ProjectWorkspace {
         Ok(ProjectWorkspace::DetachedFiles { files: detached_files, sysroot, rustc_cfg })
     }
 
+    /// Runs the build scripts for this [`ProjectWorkspace`].
     pub fn run_build_scripts(
         &self,
         config: &CargoConfig,
@@ -301,9 +311,13 @@ impl ProjectWorkspace {
     ) -> Result<WorkspaceBuildScripts> {
         match self {
             ProjectWorkspace::Cargo { cargo, toolchain, .. } => {
-                WorkspaceBuildScripts::run(config, cargo, progress, toolchain).with_context(|| {
-                    format!("Failed to run build scripts for {}", &cargo.workspace_root().display())
-                })
+                WorkspaceBuildScripts::run_for_workspace(config, cargo, progress, toolchain)
+                    .with_context(|| {
+                        format!(
+                            "Failed to run build scripts for {}",
+                            &cargo.workspace_root().display()
+                        )
+                    })
             }
             ProjectWorkspace::Json { .. } | ProjectWorkspace::DetachedFiles { .. } => {
                 Ok(WorkspaceBuildScripts::default())
@@ -311,6 +325,49 @@ impl ProjectWorkspace {
         }
     }
 
+    /// Runs the build scripts for the given [`ProjectWorkspace`]s. Depending on the invocation
+    /// strategy this may run a single build process for all project workspaces.
+    pub fn run_all_build_scripts(
+        workspaces: &[ProjectWorkspace],
+        config: &CargoConfig,
+        progress: &dyn Fn(String),
+    ) -> Vec<Result<WorkspaceBuildScripts>> {
+        if matches!(config.invocation_strategy, InvocationStrategy::PerWorkspace)
+            || config.run_build_script_command.is_none()
+        {
+            return workspaces.iter().map(|it| it.run_build_scripts(config, progress)).collect();
+        }
+
+        let cargo_ws: Vec<_> = workspaces
+            .iter()
+            .filter_map(|it| match it {
+                ProjectWorkspace::Cargo { cargo, .. } => Some(cargo),
+                _ => None,
+            })
+            .collect();
+        let ref mut outputs = match WorkspaceBuildScripts::run_once(config, &cargo_ws, progress) {
+            Ok(it) => Ok(it.into_iter()),
+            // io::Error is not Clone?
+            Err(e) => Err(Arc::new(e)),
+        };
+
+        workspaces
+            .iter()
+            .map(|it| match it {
+                ProjectWorkspace::Cargo { cargo, .. } => match outputs {
+                    Ok(outputs) => Ok(outputs.next().unwrap()),
+                    Err(e) => Err(e.clone()).with_context(|| {
+                        format!(
+                            "Failed to run build scripts for {}",
+                            &cargo.workspace_root().display()
+                        )
+                    }),
+                },
+                _ => Ok(WorkspaceBuildScripts::default()),
+            })
+            .collect()
+    }
+
     pub fn set_build_scripts(&mut self, bs: WorkspaceBuildScripts) {
         match self {
             ProjectWorkspace::Cargo { build_scripts, .. } => *build_scripts = bs,
diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/cargo_target_spec.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/cargo_target_spec.rs
index e1675a030c0..6ede194babc 100644
--- a/src/tools/rust-analyzer/crates/rust-analyzer/src/cargo_target_spec.rs
+++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/cargo_target_spec.rs
@@ -118,7 +118,7 @@ impl CargoTargetSpec {
         global_state_snapshot: &GlobalStateSnapshot,
         file_id: FileId,
     ) -> Result<Option<CargoTargetSpec>> {
-        let crate_id = match &*global_state_snapshot.analysis.crate_for(file_id)? {
+        let crate_id = match &*global_state_snapshot.analysis.crates_for(file_id)? {
             &[crate_id, ..] => crate_id,
             _ => return Ok(None),
         };
diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/scip.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/scip.rs
index 2c29b3ee3a6..8b77ccde0ee 100644
--- a/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/scip.rs
+++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/scip.rs
@@ -8,8 +8,8 @@ use std::{
 use crate::line_index::{LineEndings, LineIndex, OffsetEncoding};
 use hir::Name;
 use ide::{
-    LineCol, MonikerDescriptorKind, MonikerResult, StaticIndex, StaticIndexedFile, TextRange,
-    TokenId,
+    LineCol, MonikerDescriptorKind, StaticIndex, StaticIndexedFile, TextRange, TokenId,
+    TokenStaticData,
 };
 use ide_db::LineIndexDatabase;
 use project_model::{CargoConfig, ProjectManifest, ProjectWorkspace};
@@ -75,7 +75,7 @@ impl flags::Scip {
         let mut symbols_emitted: HashSet<TokenId> = HashSet::default();
         let mut tokens_to_symbol: HashMap<TokenId, String> = HashMap::new();
 
-        for file in si.files {
+        for StaticIndexedFile { file_id, tokens, .. } in si.files {
             let mut local_count = 0;
             let mut new_local_symbol = || {
                 let new_symbol = scip::types::Symbol::new_local(local_count);
@@ -84,7 +84,6 @@ impl flags::Scip {
                 new_symbol
             };
 
-            let StaticIndexedFile { file_id, tokens, .. } = file;
             let relative_path = match get_relative_filepath(&vfs, &rootpath, file_id) {
                 Some(relative_path) => relative_path,
                 None => continue,
@@ -107,28 +106,20 @@ impl flags::Scip {
 
                 let mut occurrence = scip_types::Occurrence::default();
                 occurrence.range = text_range_to_scip_range(&line_index, range);
-                occurrence.symbol = match tokens_to_symbol.get(&id) {
-                    Some(symbol) => symbol.clone(),
-                    None => {
-                        let symbol = match &token.moniker {
-                            Some(moniker) => moniker_to_symbol(&moniker),
-                            None => new_local_symbol(),
-                        };
-
-                        let symbol = scip::symbol::format_symbol(symbol);
-                        tokens_to_symbol.insert(id, symbol.clone());
-                        symbol
-                    }
-                };
+                occurrence.symbol = tokens_to_symbol
+                    .entry(id)
+                    .or_insert_with(|| {
+                        let symbol = token_to_symbol(&token).unwrap_or_else(&mut new_local_symbol);
+                        scip::symbol::format_symbol(symbol)
+                    })
+                    .clone();
 
                 if let Some(def) = token.definition {
                     if def.range == range {
                         occurrence.symbol_roles |= scip_types::SymbolRole::Definition as i32;
                     }
 
-                    if !symbols_emitted.contains(&id) {
-                        symbols_emitted.insert(id);
-
+                    if symbols_emitted.insert(id) {
                         let mut symbol_info = scip_types::SymbolInformation::default();
                         symbol_info.symbol = occurrence.symbol.clone();
                         if let Some(hover) = &token.hover {
@@ -207,9 +198,11 @@ fn new_descriptor(name: Name, suffix: scip_types::descriptor::Suffix) -> scip_ty
 ///
 /// Only returns a Symbol when it's a non-local symbol.
 ///     So if the visibility isn't outside of a document, then it will return None
-fn moniker_to_symbol(moniker: &MonikerResult) -> scip_types::Symbol {
+fn token_to_symbol(token: &TokenStaticData) -> Option<scip_types::Symbol> {
     use scip_types::descriptor::Suffix::*;
 
+    let moniker = token.moniker.as_ref()?;
+
     let package_name = moniker.package_information.name.clone();
     let version = moniker.package_information.version.clone();
     let descriptors = moniker
@@ -233,7 +226,7 @@ fn moniker_to_symbol(moniker: &MonikerResult) -> scip_types::Symbol {
         })
         .collect();
 
-    scip_types::Symbol {
+    Some(scip_types::Symbol {
         scheme: "rust-analyzer".into(),
         package: Some(scip_types::Package {
             manager: "cargo".to_string(),
@@ -244,19 +237,15 @@ fn moniker_to_symbol(moniker: &MonikerResult) -> scip_types::Symbol {
         .into(),
         descriptors,
         ..Default::default()
-    }
+    })
 }
 
 #[cfg(test)]
 mod test {
     use super::*;
-    use hir::Semantics;
-    use ide::{AnalysisHost, FilePosition};
-    use ide_db::defs::IdentClass;
-    use ide_db::{base_db::fixture::ChangeFixture, helpers::pick_best_token};
+    use ide::{AnalysisHost, FilePosition, StaticIndex, TextSize};
+    use ide_db::base_db::fixture::ChangeFixture;
     use scip::symbol::format_symbol;
-    use syntax::SyntaxKind::*;
-    use syntax::{AstNode, T};
 
     fn position(ra_fixture: &str) -> (AnalysisHost, FilePosition) {
         let mut host = AnalysisHost::default();
@@ -273,53 +262,33 @@ mod test {
     fn check_symbol(ra_fixture: &str, expected: &str) {
         let (host, position) = position(ra_fixture);
 
+        let analysis = host.analysis();
+        let si = StaticIndex::compute(&analysis);
+
         let FilePosition { file_id, offset } = position;
 
-        let db = host.raw_database();
-        let sema = &Semantics::new(db);
-        let file = sema.parse(file_id).syntax().clone();
-        let original_token = pick_best_token(file.token_at_offset(offset), |kind| match kind {
-            IDENT
-            | INT_NUMBER
-            | LIFETIME_IDENT
-            | T![self]
-            | T![super]
-            | T![crate]
-            | T![Self]
-            | COMMENT => 2,
-            kind if kind.is_trivia() => 0,
-            _ => 1,
-        })
-        .expect("OK OK");
-
-        let navs = sema
-            .descend_into_macros(original_token.clone())
-            .into_iter()
-            .filter_map(|token| {
-                IdentClass::classify_token(sema, &token).map(IdentClass::definitions).map(|it| {
-                    it.into_iter().flat_map(|def| {
-                        let module = def.module(db).unwrap();
-                        let current_crate = module.krate();
-
-                        match MonikerResult::from_def(sema.db, def, current_crate) {
-                            Some(moniker_result) => Some(moniker_to_symbol(&moniker_result)),
-                            None => None,
-                        }
-                    })
-                })
-            })
-            .flatten()
-            .collect::<Vec<_>>();
+        let mut found_symbol = None;
+        for file in &si.files {
+            if file.file_id != file_id {
+                continue;
+            }
+            for &(range, id) in &file.tokens {
+                if range.contains(offset - TextSize::from(1)) {
+                    let token = si.tokens.get(id).unwrap();
+                    found_symbol = token_to_symbol(token);
+                    break;
+                }
+            }
+        }
 
         if expected == "" {
-            assert_eq!(0, navs.len(), "must have no symbols {:?}", navs);
+            assert!(found_symbol.is_none(), "must have no symbols {:?}", found_symbol);
             return;
         }
 
-        assert_eq!(1, navs.len(), "must have one symbol {:?}", navs);
-
-        let res = navs.get(0).unwrap();
-        let formatted = format_symbol(res.clone());
+        assert!(found_symbol.is_some(), "must have one symbol {:?}", found_symbol);
+        let res = found_symbol.unwrap();
+        let formatted = format_symbol(res);
         assert_eq!(formatted, expected);
     }
 
diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/config.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/config.rs
index 577a8640a4c..85322f12a83 100644
--- a/src/tools/rust-analyzer/crates/rust-analyzer/src/config.rs
+++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/config.rs
@@ -69,6 +69,19 @@ config_data! {
         cargo_autoreload: bool           = "true",
         /// Run build scripts (`build.rs`) for more precise code analysis.
         cargo_buildScripts_enable: bool  = "true",
+        /// Specifies the working directory for running build scripts.
+        /// - "workspace": run build scripts for a workspace in the workspace's root directory.
+        ///   This is incompatible with `#rust-analyzer.cargo.buildScripts.invocationStrategy#` set to `once`.
+        /// - "root": run build scripts in the project's root directory.
+        /// This config only has an effect when `#rust-analyzer.cargo.buildScripts.overrideCommand#`
+        /// is set.
+        cargo_buildScripts_invocationLocation: InvocationLocation = "\"workspace\"",
+        /// Specifies the invocation strategy to use when running the build scripts command.
+        /// If `per_workspace` is set, the command will be executed for each workspace.
+        /// If `once` is set, the command will be executed once.
+        /// This config only has an effect when `#rust-analyzer.cargo.buildScripts.overrideCommand#`
+        /// is set.
+        cargo_buildScripts_invocationStrategy: InvocationStrategy = "\"per_workspace\"",
         /// Override the command rust-analyzer uses to run build scripts and
         /// build procedural macros. The command is required to output json
         /// and should therefore include `--message-format=json` or a similar
@@ -122,6 +135,20 @@ config_data! {
         ///
         /// Set to `"all"` to pass `--all-features` to Cargo.
         checkOnSave_features: Option<CargoFeaturesDef>      = "null",
+        /// Specifies the working directory for running checks.
+        /// - "workspace": run checks for workspaces in the corresponding workspaces' root directories.
+        // FIXME: Ideally we would support this in some way
+        ///   This falls back to "root" if `#rust-analyzer.cargo.checkOnSave.invocationStrategy#` is set to `once`.
+        /// - "root": run checks in the project's root directory.
+        /// This config only has an effect when `#rust-analyzer.cargo.buildScripts.overrideCommand#`
+        /// is set.
+        checkOnSave_invocationLocation: InvocationLocation = "\"workspace\"",
+        /// Specifies the invocation strategy to use when running the checkOnSave command.
+        /// If `per_workspace` is set, the command will be executed for each workspace.
+        /// If `once` is set, the command will be executed once.
+        /// This config only has an effect when `#rust-analyzer.cargo.buildScripts.overrideCommand#`
+        /// is set.
+        checkOnSave_invocationStrategy: InvocationStrategy = "\"per_workspace\"",
         /// Whether to pass `--no-default-features` to Cargo. Defaults to
         /// `#rust-analyzer.cargo.noDefaultFeatures#`.
         checkOnSave_noDefaultFeatures: Option<bool>      = "null",
@@ -1056,6 +1083,16 @@ impl Config {
             rustc_source,
             unset_test_crates: UnsetTestCrates::Only(self.data.cargo_unsetTest.clone()),
             wrap_rustc_in_build_scripts: self.data.cargo_buildScripts_useRustcWrapper,
+            invocation_strategy: match self.data.cargo_buildScripts_invocationStrategy {
+                InvocationStrategy::Once => project_model::InvocationStrategy::Once,
+                InvocationStrategy::PerWorkspace => project_model::InvocationStrategy::PerWorkspace,
+            },
+            invocation_location: match self.data.cargo_buildScripts_invocationLocation {
+                InvocationLocation::Root => {
+                    project_model::InvocationLocation::Root(self.root_path.clone())
+                }
+                InvocationLocation::Workspace => project_model::InvocationLocation::Workspace,
+            },
             run_build_script_command: self.data.cargo_buildScripts_overrideCommand.clone(),
             extra_env: self.data.cargo_extraEnv.clone(),
         }
@@ -1087,6 +1124,18 @@ impl Config {
                     command,
                     args,
                     extra_env: self.check_on_save_extra_env(),
+                    invocation_strategy: match self.data.checkOnSave_invocationStrategy {
+                        InvocationStrategy::Once => flycheck::InvocationStrategy::Once,
+                        InvocationStrategy::PerWorkspace => {
+                            flycheck::InvocationStrategy::PerWorkspace
+                        }
+                    },
+                    invocation_location: match self.data.checkOnSave_invocationLocation {
+                        InvocationLocation::Root => {
+                            flycheck::InvocationLocation::Root(self.root_path.clone())
+                        }
+                        InvocationLocation::Workspace => flycheck::InvocationLocation::Workspace,
+                    },
                 }
             }
             Some(_) | None => FlycheckConfig::CargoCommand {
@@ -1588,6 +1637,20 @@ enum CargoFeaturesDef {
 }
 
 #[derive(Deserialize, Debug, Clone)]
+#[serde(rename_all = "snake_case")]
+enum InvocationStrategy {
+    Once,
+    PerWorkspace,
+}
+
+#[derive(Deserialize, Debug, Clone)]
+#[serde(rename_all = "snake_case")]
+enum InvocationLocation {
+    Root,
+    Workspace,
+}
+
+#[derive(Deserialize, Debug, Clone)]
 #[serde(untagged)]
 enum LifetimeElisionDef {
     #[serde(deserialize_with = "true_or_always")]
@@ -2001,6 +2064,22 @@ fn field_props(field: &str, ty: &str, doc: &[&str], default: &str) -> serde_json
                 "Render annotations above the whole item, including documentation comments and attributes."
             ],
         },
+        "InvocationStrategy" => set! {
+            "type": "string",
+            "enum": ["per_workspace", "once"],
+            "enumDescriptions": [
+                "The command will be executed for each workspace.",
+                "The command will be executed once."
+            ],
+        },
+        "InvocationLocation" => set! {
+            "type": "string",
+            "enum": ["workspace", "root"],
+            "enumDescriptions": [
+                "The command will be executed in the corresponding workspace root.",
+                "The command will be executed in the project root."
+            ],
+        },
         _ => panic!("missing entry for {}: {}", ty, default),
     }
 
diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/dispatch.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/dispatch.rs
index f16559148e6..57899b59914 100644
--- a/src/tools/rust-analyzer/crates/rust-analyzer/src/dispatch.rs
+++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/dispatch.rs
@@ -52,7 +52,7 @@ impl<'a> RequestDispatcher<'a> {
             let _pctx = stdx::panic_context::enter(panic_context);
             f(self.global_state, params)
         };
-        if let Ok(response) = result_to_response::<R>(req.id.clone(), result) {
+        if let Ok(response) = result_to_response::<R>(req.id, result) {
             self.global_state.respond(response);
         }
 
@@ -80,7 +80,7 @@ impl<'a> RequestDispatcher<'a> {
             f(global_state_snapshot, params)
         });
 
-        if let Ok(response) = thread_result_to_response::<R>(req.id.clone(), result) {
+        if let Ok(response) = thread_result_to_response::<R>(req.id, result) {
             self.global_state.respond(response);
         }
 
diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/global_state.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/global_state.rs
index 000ff88e458..3fb06c31f7c 100644
--- a/src/tools/rust-analyzer/crates/rust-analyzer/src/global_state.rs
+++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/global_state.rs
@@ -64,7 +64,7 @@ pub(crate) struct GlobalState {
     pub(crate) source_root_config: SourceRootConfig,
     pub(crate) proc_macro_clients: Vec<Result<ProcMacroServer, String>>,
 
-    pub(crate) flycheck: Vec<FlycheckHandle>,
+    pub(crate) flycheck: Arc<[FlycheckHandle]>,
     pub(crate) flycheck_sender: Sender<flycheck::Message>,
     pub(crate) flycheck_receiver: Receiver<flycheck::Message>,
 
@@ -117,6 +117,7 @@ pub(crate) struct GlobalStateSnapshot {
     vfs: Arc<RwLock<(vfs::Vfs, NoHashHashMap<FileId, LineEndings>)>>,
     pub(crate) workspaces: Arc<Vec<ProjectWorkspace>>,
     pub(crate) proc_macros_loaded: bool,
+    pub(crate) flycheck: Arc<[FlycheckHandle]>,
 }
 
 impl std::panic::UnwindSafe for GlobalStateSnapshot {}
@@ -155,7 +156,7 @@ impl GlobalState {
             source_root_config: SourceRootConfig::default(),
             proc_macro_clients: vec![],
 
-            flycheck: Vec::new(),
+            flycheck: Arc::new([]),
             flycheck_sender,
             flycheck_receiver,
 
@@ -295,6 +296,7 @@ impl GlobalState {
             mem_docs: self.mem_docs.clone(),
             semantic_tokens_cache: Arc::clone(&self.semantic_tokens_cache),
             proc_macros_loaded: !self.fetch_build_data_queue.last_op_result().0.is_empty(),
+            flycheck: self.flycheck.clone(),
         }
     }
 
@@ -398,6 +400,10 @@ impl GlobalStateSnapshot {
         url_from_abs_path(path)
     }
 
+    pub(crate) fn file_id_to_file_path(&self, file_id: FileId) -> vfs::VfsPath {
+        self.vfs.read().0.file_path(file_id)
+    }
+
     pub(crate) fn cargo_target_for_crate_root(
         &self,
         crate_id: CrateId,
diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/handlers.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/handlers.rs
index 8c3ea77d061..34795a8eb40 100644
--- a/src/tools/rust-analyzer/crates/rust-analyzer/src/handlers.rs
+++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/handlers.rs
@@ -658,7 +658,7 @@ pub(crate) fn handle_parent_module(
 
         // check if invoked at the crate root
         let file_id = from_proto::file_id(&snap, &params.text_document.uri)?;
-        let crate_id = match snap.analysis.crate_for(file_id)?.first() {
+        let crate_id = match snap.analysis.crates_for(file_id)?.first() {
             Some(&crate_id) => crate_id,
             None => return Ok(None),
         };
@@ -1782,7 +1782,15 @@ fn run_rustfmt(
 ) -> Result<Option<Vec<lsp_types::TextEdit>>> {
     let file_id = from_proto::file_id(snap, &text_document.uri)?;
     let file = snap.analysis.file_text(file_id)?;
-    let crate_ids = snap.analysis.crate_for(file_id)?;
+
+    // find the edition of the package the file belongs to
+    // (if it belongs to multiple we'll just pick the first one and pray)
+    let edition = snap
+        .analysis
+        .relevant_crates_for(file_id)?
+        .into_iter()
+        .find_map(|crate_id| snap.cargo_target_for_crate_root(crate_id))
+        .map(|(ws, target)| ws[ws[target].package].edition);
 
     let line_index = snap.file_line_index(file_id)?;
 
@@ -1808,9 +1816,7 @@ fn run_rustfmt(
                     );
                 }
             }
-            if let Some(&crate_id) = crate_ids.first() {
-                // Assume all crates are in the same edition
-                let edition = snap.analysis.crate_edition(crate_id)?;
+            if let Some(edition) = edition {
                 cmd.arg("--edition");
                 cmd.arg(edition.to_string());
             }
diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/lsp_utils.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/lsp_utils.rs
index 5a37cbe2e33..b3cea64d417 100644
--- a/src/tools/rust-analyzer/crates/rust-analyzer/src/lsp_utils.rs
+++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/lsp_utils.rs
@@ -87,6 +87,7 @@ impl GlobalState {
         state: Progress,
         message: Option<String>,
         fraction: Option<f64>,
+        cancel_token: Option<String>,
     ) {
         if !self.config.work_done_progress() {
             return;
@@ -95,7 +96,10 @@ impl GlobalState {
             assert!((0.0..=1.0).contains(&f));
             (f * 100.0) as u32
         });
-        let token = lsp_types::ProgressToken::String(format!("rustAnalyzer/{}", title));
+        let cancellable = Some(cancel_token.is_some());
+        let token = lsp_types::ProgressToken::String(
+            cancel_token.unwrap_or_else(|| format!("rustAnalyzer/{}", title)),
+        );
         let work_done_progress = match state {
             Progress::Begin => {
                 self.send_request::<lsp_types::request::WorkDoneProgressCreate>(
@@ -105,14 +109,14 @@ impl GlobalState {
 
                 lsp_types::WorkDoneProgress::Begin(lsp_types::WorkDoneProgressBegin {
                     title: title.into(),
-                    cancellable: None,
+                    cancellable,
                     message,
                     percentage,
                 })
             }
             Progress::Report => {
                 lsp_types::WorkDoneProgress::Report(lsp_types::WorkDoneProgressReport {
-                    cancellable: None,
+                    cancellable,
                     message,
                     percentage,
                 })
diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/main_loop.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/main_loop.rs
index 15922dac651..2c928a58040 100644
--- a/src/tools/rust-analyzer/crates/rust-analyzer/src/main_loop.rs
+++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/main_loop.rs
@@ -10,7 +10,7 @@ use std::{
 use always_assert::always;
 use crossbeam_channel::{select, Receiver};
 use flycheck::FlycheckHandle;
-use ide_db::base_db::{SourceDatabase, SourceDatabaseExt, VfsPath};
+use ide_db::base_db::{SourceDatabaseExt, VfsPath};
 use itertools::Itertools;
 use lsp_server::{Connection, Notification, Request};
 use lsp_types::notification::Notification as _;
@@ -191,7 +191,7 @@ impl GlobalState {
         // NOTE: don't count blocking select! call as a loop-turn time
         let _p = profile::span("GlobalState::handle_event");
 
-        tracing::debug!("handle_event({:?})", event);
+        tracing::debug!("{:?} handle_event({:?})", loop_start, event);
         let task_queue_len = self.task_pool.handle.len();
         if task_queue_len > 0 {
             tracing::info!("task queue len: {}", task_queue_len);
@@ -257,7 +257,7 @@ impl GlobalState {
                         }
                     };
 
-                    self.report_progress("Indexing", state, message, Some(fraction));
+                    self.report_progress("Indexing", state, message, Some(fraction), None);
                 }
             }
             Event::Vfs(message) => {
@@ -465,7 +465,7 @@ impl GlobalState {
                     }
                 };
 
-                self.report_progress("Fetching", state, msg, None);
+                self.report_progress("Fetching", state, msg, None, None);
             }
             Task::FetchBuildData(progress) => {
                 let (state, msg) = match progress {
@@ -481,7 +481,7 @@ impl GlobalState {
                 };
 
                 if let Some(state) = state {
-                    self.report_progress("Loading", state, msg, None);
+                    self.report_progress("Loading", state, msg, None, None);
                 }
             }
         }
@@ -518,6 +518,7 @@ impl GlobalState {
                     state,
                     Some(format!("{}/{}", n_done, n_total)),
                     Some(Progress::fraction(n_done, n_total)),
+                    None,
                 )
             }
         }
@@ -542,7 +543,10 @@ impl GlobalState {
                             diag.fix,
                         ),
                         Err(err) => {
-                            tracing::error!("File with cargo diagnostic not found in VFS: {}", err);
+                            tracing::error!(
+                                "flycheck {id}: File with cargo diagnostic not found in VFS: {}",
+                                err
+                            );
                         }
                     };
                 }
@@ -584,7 +588,13 @@ impl GlobalState {
                 } else {
                     format!("cargo check (#{})", id + 1)
                 };
-                self.report_progress(&title, state, message, None);
+                self.report_progress(
+                    &title,
+                    state,
+                    message,
+                    None,
+                    Some(format!("rust-analyzer/checkOnSave/{}", id)),
+                );
             }
         }
     }
@@ -698,7 +708,16 @@ impl GlobalState {
                 this.cancel(id);
                 Ok(())
             })?
-            .on::<lsp_types::notification::WorkDoneProgressCancel>(|_this, _params| {
+            .on::<lsp_types::notification::WorkDoneProgressCancel>(|this, params| {
+                if let lsp_types::NumberOrString::String(s) = &params.token {
+                    if let Some(id) = s.strip_prefix("rust-analyzer/checkOnSave/") {
+                        if let Ok(id) = u32::from_str_radix(id, 10) {
+                            if let Some(flycheck) = this.flycheck.get(id as usize) {
+                                flycheck.cancel();
+                            }
+                        }
+                    }
+                }
                 // Just ignore this. It is OK to continue sending progress
                 // notifications for this token, as the client can't know when
                 // we accepted notification.
@@ -711,7 +730,7 @@ impl GlobalState {
                         .insert(path.clone(), DocumentData::new(params.text_document.version))
                         .is_err();
                     if already_exists {
-                        tracing::error!("duplicate DidOpenTextDocument: {}", path)
+                        tracing::error!("duplicate DidOpenTextDocument: {}", path);
                     }
                     this.vfs
                         .write()
@@ -758,69 +777,7 @@ impl GlobalState {
                 Ok(())
             })?
             .on::<lsp_types::notification::DidSaveTextDocument>(|this, params| {
-                let mut updated = false;
                 if let Ok(vfs_path) = from_proto::vfs_path(&params.text_document.uri) {
-                    let (vfs, _) = &*this.vfs.read();
-
-                    // Trigger flychecks for all workspaces that depend on the saved file
-                    if let Some(file_id) = vfs.file_id(&vfs_path) {
-                        let analysis = this.analysis_host.analysis();
-                        // Crates containing or depending on the saved file
-                        let crate_ids: Vec<_> = analysis
-                            .crate_for(file_id)?
-                            .into_iter()
-                            .flat_map(|id| {
-                                this.analysis_host
-                                    .raw_database()
-                                    .crate_graph()
-                                    .transitive_rev_deps(id)
-                            })
-                            .sorted()
-                            .unique()
-                            .collect();
-
-                        let crate_root_paths: Vec<_> = crate_ids
-                            .iter()
-                            .filter_map(|&crate_id| {
-                                analysis
-                                    .crate_root(crate_id)
-                                    .map(|file_id| {
-                                        vfs.file_path(file_id).as_path().map(ToOwned::to_owned)
-                                    })
-                                    .transpose()
-                            })
-                            .collect::<ide::Cancellable<_>>()?;
-                        let crate_root_paths: Vec<_> =
-                            crate_root_paths.iter().map(Deref::deref).collect();
-
-                        // Find all workspaces that have at least one target containing the saved file
-                        let workspace_ids =
-                            this.workspaces.iter().enumerate().filter(|(_, ws)| match ws {
-                                project_model::ProjectWorkspace::Cargo { cargo, .. } => {
-                                    cargo.packages().any(|pkg| {
-                                        cargo[pkg].targets.iter().any(|&it| {
-                                            crate_root_paths.contains(&cargo[it].root.as_path())
-                                        })
-                                    })
-                                }
-                                project_model::ProjectWorkspace::Json { project, .. } => project
-                                    .crates()
-                                    .any(|(c, _)| crate_ids.iter().any(|&crate_id| crate_id == c)),
-                                project_model::ProjectWorkspace::DetachedFiles { .. } => false,
-                            });
-
-                        // Find and trigger corresponding flychecks
-                        for flycheck in &this.flycheck {
-                            for (id, _) in workspace_ids.clone() {
-                                if id == flycheck.id() {
-                                    updated = true;
-                                    flycheck.restart();
-                                    continue;
-                                }
-                            }
-                        }
-                    }
-
                     // Re-fetch workspaces if a workspace related file has changed
                     if let Some(abs_path) = vfs_path.as_path() {
                         if reload::should_refresh_for_change(&abs_path, ChangeKind::Modify) {
@@ -828,13 +785,90 @@ impl GlobalState {
                                 .request_op(format!("DidSaveTextDocument {}", abs_path.display()));
                         }
                     }
+
+                    let file_id = this.vfs.read().0.file_id(&vfs_path);
+                    if let Some(file_id) = file_id {
+                        let world = this.snapshot();
+                        let mut updated = false;
+                        let task = move || -> std::result::Result<(), ide::Cancelled> {
+                            // Trigger flychecks for all workspaces that depend on the saved file
+                            // Crates containing or depending on the saved file
+                            let crate_ids: Vec<_> = world
+                                .analysis
+                                .crates_for(file_id)?
+                                .into_iter()
+                                .flat_map(|id| world.analysis.transitive_rev_deps(id))
+                                .flatten()
+                                .sorted()
+                                .unique()
+                                .collect();
+
+                            let crate_root_paths: Vec<_> = crate_ids
+                                .iter()
+                                .filter_map(|&crate_id| {
+                                    world
+                                        .analysis
+                                        .crate_root(crate_id)
+                                        .map(|file_id| {
+                                            world
+                                                .file_id_to_file_path(file_id)
+                                                .as_path()
+                                                .map(ToOwned::to_owned)
+                                        })
+                                        .transpose()
+                                })
+                                .collect::<ide::Cancellable<_>>()?;
+                            let crate_root_paths: Vec<_> =
+                                crate_root_paths.iter().map(Deref::deref).collect();
+
+                            // Find all workspaces that have at least one target containing the saved file
+                            let workspace_ids =
+                                world.workspaces.iter().enumerate().filter(|(_, ws)| match ws {
+                                    project_model::ProjectWorkspace::Cargo { cargo, .. } => {
+                                        cargo.packages().any(|pkg| {
+                                            cargo[pkg].targets.iter().any(|&it| {
+                                                crate_root_paths.contains(&cargo[it].root.as_path())
+                                            })
+                                        })
+                                    }
+                                    project_model::ProjectWorkspace::Json { project, .. } => {
+                                        project.crates().any(|(c, _)| {
+                                            crate_ids.iter().any(|&crate_id| crate_id == c)
+                                        })
+                                    }
+                                    project_model::ProjectWorkspace::DetachedFiles { .. } => false,
+                                });
+
+                            // Find and trigger corresponding flychecks
+                            for flycheck in world.flycheck.iter() {
+                                for (id, _) in workspace_ids.clone() {
+                                    if id == flycheck.id() {
+                                        updated = true;
+                                        flycheck.restart();
+                                        continue;
+                                    }
+                                }
+                            }
+                            // No specific flycheck was triggered, so let's trigger all of them.
+                            if !updated {
+                                for flycheck in world.flycheck.iter() {
+                                    flycheck.restart();
+                                }
+                            }
+                            Ok(())
+                        };
+                        this.task_pool.handle.spawn_with_sender(move |_| {
+                            if let Err(e) = std::panic::catch_unwind(task) {
+                                tracing::error!("DidSaveTextDocument flycheck task panicked: {e:?}")
+                            }
+                        });
+                        return Ok(());
+                    }
                 }
 
                 // No specific flycheck was triggered, so let's trigger all of them.
-                if !updated {
-                    for flycheck in &this.flycheck {
-                        flycheck.restart();
-                    }
+                for flycheck in this.flycheck.iter() {
+                    flycheck.restart();
                 }
                 Ok(())
             })?
diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/reload.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/reload.rs
index f8734893944..e1f651786de 100644
--- a/src/tools/rust-analyzer/crates/rust-analyzer/src/reload.rs
+++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/reload.rs
@@ -175,10 +175,8 @@ impl GlobalState {
                     sender.send(Task::FetchBuildData(BuildDataProgress::Report(msg))).unwrap()
                 }
             };
-            let mut res = Vec::new();
-            for ws in workspaces.iter() {
-                res.push(ws.run_build_scripts(&config, &progress));
-            }
+            let res = ProjectWorkspace::run_all_build_scripts(&workspaces, &config, &progress);
+
             sender.send(Task::FetchBuildData(BuildDataProgress::End((workspaces, res)))).unwrap();
         });
     }
@@ -468,39 +466,54 @@ impl GlobalState {
         let config = match self.config.flycheck() {
             Some(it) => it,
             None => {
-                self.flycheck = Vec::new();
+                self.flycheck = Arc::new([]);
                 self.diagnostics.clear_check_all();
                 return;
             }
         };
 
         let sender = self.flycheck_sender.clone();
-        self.flycheck = self
-            .workspaces
-            .iter()
-            .enumerate()
-            .filter_map(|(id, w)| match w {
-                ProjectWorkspace::Cargo { cargo, .. } => Some((id, cargo.workspace_root())),
-                ProjectWorkspace::Json { project, .. } => {
-                    // Enable flychecks for json projects if a custom flycheck command was supplied
-                    // in the workspace configuration.
-                    match config {
-                        FlycheckConfig::CustomCommand { .. } => Some((id, project.path())),
-                        _ => None,
-                    }
-                }
-                ProjectWorkspace::DetachedFiles { .. } => None,
-            })
-            .map(|(id, root)| {
-                let sender = sender.clone();
-                FlycheckHandle::spawn(
-                    id,
-                    Box::new(move |msg| sender.send(msg).unwrap()),
-                    config.clone(),
-                    root.to_path_buf(),
-                )
-            })
-            .collect();
+        let invocation_strategy = match config {
+            FlycheckConfig::CargoCommand { .. } => flycheck::InvocationStrategy::PerWorkspace,
+            FlycheckConfig::CustomCommand { invocation_strategy, .. } => invocation_strategy,
+        };
+
+        self.flycheck = match invocation_strategy {
+            flycheck::InvocationStrategy::Once => vec![FlycheckHandle::spawn(
+                0,
+                Box::new(move |msg| sender.send(msg).unwrap()),
+                config.clone(),
+                self.config.root_path().clone(),
+            )],
+            flycheck::InvocationStrategy::PerWorkspace => {
+                self.workspaces
+                    .iter()
+                    .enumerate()
+                    .filter_map(|(id, w)| match w {
+                        ProjectWorkspace::Cargo { cargo, .. } => Some((id, cargo.workspace_root())),
+                        ProjectWorkspace::Json { project, .. } => {
+                            // Enable flychecks for json projects if a custom flycheck command was supplied
+                            // in the workspace configuration.
+                            match config {
+                                FlycheckConfig::CustomCommand { .. } => Some((id, project.path())),
+                                _ => None,
+                            }
+                        }
+                        ProjectWorkspace::DetachedFiles { .. } => None,
+                    })
+                    .map(|(id, root)| {
+                        let sender = sender.clone();
+                        FlycheckHandle::spawn(
+                            id,
+                            Box::new(move |msg| sender.send(msg).unwrap()),
+                            config.clone(),
+                            root.to_path_buf(),
+                        )
+                    })
+                    .collect()
+            }
+        }
+        .into();
     }
 }
 
diff --git a/src/tools/rust-analyzer/crates/syntax/src/ast/edit_in_place.rs b/src/tools/rust-analyzer/crates/syntax/src/ast/edit_in_place.rs
index 229e7419b73..660c057e99c 100644
--- a/src/tools/rust-analyzer/crates/syntax/src/ast/edit_in_place.rs
+++ b/src/tools/rust-analyzer/crates/syntax/src/ast/edit_in_place.rs
@@ -645,7 +645,7 @@ impl ast::RecordPatFieldList {
 }
 
 fn get_or_insert_comma_after(syntax: &SyntaxNode) -> SyntaxToken {
-    let comma = match syntax
+    match syntax
         .siblings_with_tokens(Direction::Next)
         .filter_map(|it| it.into_token())
         .find(|it| it.kind() == T![,])
@@ -656,8 +656,7 @@ fn get_or_insert_comma_after(syntax: &SyntaxNode) -> SyntaxToken {
             ted::insert(Position::after(syntax), &comma);
             comma
         }
-    };
-    comma
+    }
 }
 
 impl ast::StmtList {
diff --git a/src/tools/rust-analyzer/crates/syntax/src/lib.rs b/src/tools/rust-analyzer/crates/syntax/src/lib.rs
index 4f5e273a520..84c66b27e69 100644
--- a/src/tools/rust-analyzer/crates/syntax/src/lib.rs
+++ b/src/tools/rust-analyzer/crates/syntax/src/lib.rs
@@ -92,7 +92,7 @@ impl<T> Parse<T> {
         SyntaxNode::new_root(self.green.clone())
     }
     pub fn errors(&self) -> &[SyntaxError] {
-        &*self.errors
+        &self.errors
     }
 }
 
diff --git a/src/tools/rust-analyzer/crates/test-utils/src/minicore.rs b/src/tools/rust-analyzer/crates/test-utils/src/minicore.rs
index 59b1c147d7f..69d2e62b256 100644
--- a/src/tools/rust-analyzer/crates/test-utils/src/minicore.rs
+++ b/src/tools/rust-analyzer/crates/test-utils/src/minicore.rs
@@ -27,7 +27,6 @@
 //!     generator: pin
 //!     hash:
 //!     index: sized
-//!     infallible:
 //!     iterator: option
 //!     iterators: iterator, fn
 //!     option:
@@ -37,7 +36,7 @@
 //!     result:
 //!     sized:
 //!     slice:
-//!     try: infallible
+//!     try:
 //!     unsize: sized
 
 pub mod marker {
@@ -151,9 +150,6 @@ pub mod convert {
         fn as_ref(&self) -> &T;
     }
     // endregion:as_ref
-    // region:infallible
-    pub enum Infallible {}
-    // endregion:infallible
 }
 
 pub mod ops {
@@ -330,7 +326,7 @@ pub mod ops {
             Continue(C),
             Break(B),
         }
-        pub trait FromResidual<R = <Self as Try>::Residual> {
+        pub trait FromResidual<R = Self::Residual> {
             #[lang = "from_residual"]
             fn from_residual(residual: R) -> Self;
         }
@@ -346,13 +342,13 @@ pub mod ops {
 
         impl<B, C> Try for ControlFlow<B, C> {
             type Output = C;
-            type Residual = ControlFlow<B, crate::convert::Infallible>;
+            type Residual = ControlFlow<B, convert::Infallible>;
             fn from_output(output: Self::Output) -> Self {}
             fn branch(self) -> ControlFlow<Self::Residual, Self::Output> {}
         }
 
         impl<B, C> FromResidual for ControlFlow<B, C> {
-            fn from_residual(residual: ControlFlow<B, crate::convert::Infallible>) -> Self {}
+            fn from_residual(residual: ControlFlow<B, convert::Infallible>) -> Self {}
         }
     }
     pub use self::try_::{ControlFlow, FromResidual, Try};
@@ -473,33 +469,6 @@ pub mod option {
             }
         }
     }
-    // region:try
-    impl<T> crate::ops::Try for Option<T> {
-        type Output = T;
-        type Residual = Option<crate::convert::Infallible>;
-
-        #[inline]
-        fn from_output(output: Self::Output) -> Self {
-            Some(output)
-        }
-
-        #[inline]
-        fn branch(self) -> crate::ops::ControlFlow<Self::Residual, Self::Output> {
-            match self {
-                Some(v) => crate::ops::ControlFlow::Continue(v),
-                None => crate::ops::ControlFlow::Break(None),
-            }
-        }
-    }
-    impl<T> crate::ops::FromResidual for Option<T> {
-        #[inline]
-        fn from_residual(residual: Option<crate::convert::Infallible>) -> Self {
-            match residual {
-                None => None,
-            }
-        }
-    }
-    // endregion:try
 }
 // endregion:option
 
diff --git a/src/tools/rust-analyzer/docs/user/generated_config.adoc b/src/tools/rust-analyzer/docs/user/generated_config.adoc
index acf0aaea859..502833de72c 100644
--- a/src/tools/rust-analyzer/docs/user/generated_config.adoc
+++ b/src/tools/rust-analyzer/docs/user/generated_config.adoc
@@ -24,6 +24,25 @@ Automatically refresh project info via `cargo metadata` on
 --
 Run build scripts (`build.rs`) for more precise code analysis.
 --
+[[rust-analyzer.cargo.buildScripts.invocationLocation]]rust-analyzer.cargo.buildScripts.invocationLocation (default: `"workspace"`)::
++
+--
+Specifies the working directory for running build scripts.
+- "workspace": run build scripts for a workspace in the workspace's root directory.
+  This is incompatible with `#rust-analyzer.cargo.buildScripts.invocationStrategy#` set to `once`.
+- "root": run build scripts in the project's root directory.
+This config only has an effect when `#rust-analyzer.cargo.buildScripts.overrideCommand#`
+is set.
+--
+[[rust-analyzer.cargo.buildScripts.invocationStrategy]]rust-analyzer.cargo.buildScripts.invocationStrategy (default: `"per_workspace"`)::
++
+--
+Specifies the invocation strategy to use when running the build scripts command.
+If `per_workspace` is set, the command will be executed for each workspace.
+If `once` is set, the command will be executed once.
+This config only has an effect when `#rust-analyzer.cargo.buildScripts.overrideCommand#`
+is set.
+--
 [[rust-analyzer.cargo.buildScripts.overrideCommand]]rust-analyzer.cargo.buildScripts.overrideCommand (default: `null`)::
 +
 --
@@ -118,6 +137,25 @@ List of features to activate. Defaults to
 
 Set to `"all"` to pass `--all-features` to Cargo.
 --
+[[rust-analyzer.checkOnSave.invocationLocation]]rust-analyzer.checkOnSave.invocationLocation (default: `"workspace"`)::
++
+--
+Specifies the working directory for running checks.
+- "workspace": run checks for workspaces in the corresponding workspaces' root directories.
+  This falls back to "root" if `#rust-analyzer.cargo.checkOnSave.invocationStrategy#` is set to `once`.
+- "root": run checks in the project's root directory.
+This config only has an effect when `#rust-analyzer.cargo.buildScripts.overrideCommand#`
+is set.
+--
+[[rust-analyzer.checkOnSave.invocationStrategy]]rust-analyzer.checkOnSave.invocationStrategy (default: `"per_workspace"`)::
++
+--
+Specifies the invocation strategy to use when running the checkOnSave command.
+If `per_workspace` is set, the command will be executed for each workspace.
+If `once` is set, the command will be executed once.
+This config only has an effect when `#rust-analyzer.cargo.buildScripts.overrideCommand#`
+is set.
+--
 [[rust-analyzer.checkOnSave.noDefaultFeatures]]rust-analyzer.checkOnSave.noDefaultFeatures (default: `null`)::
 +
 --
diff --git a/src/tools/rust-analyzer/editors/code/package-lock.json b/src/tools/rust-analyzer/editors/code/package-lock.json
index 3ff4b6897a1..a72865d4fe4 100644
--- a/src/tools/rust-analyzer/editors/code/package-lock.json
+++ b/src/tools/rust-analyzer/editors/code/package-lock.json
@@ -11,7 +11,7 @@
             "dependencies": {
                 "d3": "^7.6.1",
                 "d3-graphviz": "^4.1.1",
-                "vscode-languageclient": "^8.0.0-next.14"
+                "vscode-languageclient": "^8.0.2"
             },
             "devDependencies": {
                 "@types/node": "~16.11.7",
@@ -3791,39 +3791,39 @@
             }
         },
         "node_modules/vscode-jsonrpc": {
-            "version": "8.0.0-next.7",
-            "resolved": "https://registry.npmjs.org/vscode-jsonrpc/-/vscode-jsonrpc-8.0.0-next.7.tgz",
-            "integrity": "sha512-JX/F31LEsims0dAlOTKFE4E+AJMiJvdRSRViifFJSqSN7EzeYyWlfuDchF7g91oRNPZOIWfibTkDf3/UMsQGzQ==",
+            "version": "8.0.2",
+            "resolved": "https://registry.npmjs.org/vscode-jsonrpc/-/vscode-jsonrpc-8.0.2.tgz",
+            "integrity": "sha512-RY7HwI/ydoC1Wwg4gJ3y6LpU9FJRZAUnTYMXthqhFXXu77ErDd/xkREpGuk4MyYkk4a+XDWAMqe0S3KkelYQEQ==",
             "engines": {
                 "node": ">=14.0.0"
             }
         },
         "node_modules/vscode-languageclient": {
-            "version": "8.0.0-next.14",
-            "resolved": "https://registry.npmjs.org/vscode-languageclient/-/vscode-languageclient-8.0.0-next.14.tgz",
-            "integrity": "sha512-NqjkOuDTMu8uo+PhoMsV72VO9Gd3wBi/ZpOrkRUOrWKQo7yUdiIw183g8wjH8BImgbK9ZP51HM7TI0ZhCnI1Mw==",
+            "version": "8.0.2",
+            "resolved": "https://registry.npmjs.org/vscode-languageclient/-/vscode-languageclient-8.0.2.tgz",
+            "integrity": "sha512-lHlthJtphG9gibGb/y72CKqQUxwPsMXijJVpHEC2bvbFqxmkj9LwQ3aGU9dwjBLqsX1S4KjShYppLvg1UJDF/Q==",
             "dependencies": {
                 "minimatch": "^3.0.4",
                 "semver": "^7.3.5",
-                "vscode-languageserver-protocol": "3.17.0-next.16"
+                "vscode-languageserver-protocol": "3.17.2"
             },
             "engines": {
-                "vscode": "^1.66.0"
+                "vscode": "^1.67.0"
             }
         },
         "node_modules/vscode-languageserver-protocol": {
-            "version": "3.17.0-next.16",
-            "resolved": "https://registry.npmjs.org/vscode-languageserver-protocol/-/vscode-languageserver-protocol-3.17.0-next.16.tgz",
-            "integrity": "sha512-tx4DnXw9u3N7vw+bx6n2NKp6FoxoNwiP/biH83AS30I2AnTGyLd7afSeH6Oewn2E8jvB7K15bs12sMppkKOVeQ==",
+            "version": "3.17.2",
+            "resolved": "https://registry.npmjs.org/vscode-languageserver-protocol/-/vscode-languageserver-protocol-3.17.2.tgz",
+            "integrity": "sha512-8kYisQ3z/SQ2kyjlNeQxbkkTNmVFoQCqkmGrzLH6A9ecPlgTbp3wDTnUNqaUxYr4vlAcloxx8zwy7G5WdguYNg==",
             "dependencies": {
-                "vscode-jsonrpc": "8.0.0-next.7",
-                "vscode-languageserver-types": "3.17.0-next.9"
+                "vscode-jsonrpc": "8.0.2",
+                "vscode-languageserver-types": "3.17.2"
             }
         },
         "node_modules/vscode-languageserver-types": {
-            "version": "3.17.0-next.9",
-            "resolved": "https://registry.npmjs.org/vscode-languageserver-types/-/vscode-languageserver-types-3.17.0-next.9.tgz",
-            "integrity": "sha512-9/PeDNPYduaoXRUzYpqmu4ZV9L01HGo0wH9FUt+sSHR7IXwA7xoXBfNUlv8gB9H0D2WwEmMomSy1NmhjKQyn3A=="
+            "version": "3.17.2",
+            "resolved": "https://registry.npmjs.org/vscode-languageserver-types/-/vscode-languageserver-types-3.17.2.tgz",
+            "integrity": "sha512-zHhCWatviizPIq9B7Vh9uvrH6x3sK8itC84HkamnBWoDFJtzBf7SWlpLCZUit72b3os45h6RWQNC9xHRDF8dRA=="
         },
         "node_modules/which": {
             "version": "2.0.2",
@@ -6634,33 +6634,33 @@
             }
         },
         "vscode-jsonrpc": {
-            "version": "8.0.0-next.7",
-            "resolved": "https://registry.npmjs.org/vscode-jsonrpc/-/vscode-jsonrpc-8.0.0-next.7.tgz",
-            "integrity": "sha512-JX/F31LEsims0dAlOTKFE4E+AJMiJvdRSRViifFJSqSN7EzeYyWlfuDchF7g91oRNPZOIWfibTkDf3/UMsQGzQ=="
+            "version": "8.0.2",
+            "resolved": "https://registry.npmjs.org/vscode-jsonrpc/-/vscode-jsonrpc-8.0.2.tgz",
+            "integrity": "sha512-RY7HwI/ydoC1Wwg4gJ3y6LpU9FJRZAUnTYMXthqhFXXu77ErDd/xkREpGuk4MyYkk4a+XDWAMqe0S3KkelYQEQ=="
         },
         "vscode-languageclient": {
-            "version": "8.0.0-next.14",
-            "resolved": "https://registry.npmjs.org/vscode-languageclient/-/vscode-languageclient-8.0.0-next.14.tgz",
-            "integrity": "sha512-NqjkOuDTMu8uo+PhoMsV72VO9Gd3wBi/ZpOrkRUOrWKQo7yUdiIw183g8wjH8BImgbK9ZP51HM7TI0ZhCnI1Mw==",
+            "version": "8.0.2",
+            "resolved": "https://registry.npmjs.org/vscode-languageclient/-/vscode-languageclient-8.0.2.tgz",
+            "integrity": "sha512-lHlthJtphG9gibGb/y72CKqQUxwPsMXijJVpHEC2bvbFqxmkj9LwQ3aGU9dwjBLqsX1S4KjShYppLvg1UJDF/Q==",
             "requires": {
                 "minimatch": "^3.0.4",
                 "semver": "^7.3.5",
-                "vscode-languageserver-protocol": "3.17.0-next.16"
+                "vscode-languageserver-protocol": "3.17.2"
             }
         },
         "vscode-languageserver-protocol": {
-            "version": "3.17.0-next.16",
-            "resolved": "https://registry.npmjs.org/vscode-languageserver-protocol/-/vscode-languageserver-protocol-3.17.0-next.16.tgz",
-            "integrity": "sha512-tx4DnXw9u3N7vw+bx6n2NKp6FoxoNwiP/biH83AS30I2AnTGyLd7afSeH6Oewn2E8jvB7K15bs12sMppkKOVeQ==",
+            "version": "3.17.2",
+            "resolved": "https://registry.npmjs.org/vscode-languageserver-protocol/-/vscode-languageserver-protocol-3.17.2.tgz",
+            "integrity": "sha512-8kYisQ3z/SQ2kyjlNeQxbkkTNmVFoQCqkmGrzLH6A9ecPlgTbp3wDTnUNqaUxYr4vlAcloxx8zwy7G5WdguYNg==",
             "requires": {
-                "vscode-jsonrpc": "8.0.0-next.7",
-                "vscode-languageserver-types": "3.17.0-next.9"
+                "vscode-jsonrpc": "8.0.2",
+                "vscode-languageserver-types": "3.17.2"
             }
         },
         "vscode-languageserver-types": {
-            "version": "3.17.0-next.9",
-            "resolved": "https://registry.npmjs.org/vscode-languageserver-types/-/vscode-languageserver-types-3.17.0-next.9.tgz",
-            "integrity": "sha512-9/PeDNPYduaoXRUzYpqmu4ZV9L01HGo0wH9FUt+sSHR7IXwA7xoXBfNUlv8gB9H0D2WwEmMomSy1NmhjKQyn3A=="
+            "version": "3.17.2",
+            "resolved": "https://registry.npmjs.org/vscode-languageserver-types/-/vscode-languageserver-types-3.17.2.tgz",
+            "integrity": "sha512-zHhCWatviizPIq9B7Vh9uvrH6x3sK8itC84HkamnBWoDFJtzBf7SWlpLCZUit72b3os45h6RWQNC9xHRDF8dRA=="
         },
         "which": {
             "version": "2.0.2",
diff --git a/src/tools/rust-analyzer/editors/code/package.json b/src/tools/rust-analyzer/editors/code/package.json
index f1dd3aa79ff..6771cad28a7 100644
--- a/src/tools/rust-analyzer/editors/code/package.json
+++ b/src/tools/rust-analyzer/editors/code/package.json
@@ -37,7 +37,7 @@
     "dependencies": {
         "d3": "^7.6.1",
         "d3-graphviz": "^4.1.1",
-        "vscode-languageclient": "^8.0.0-next.14"
+        "vscode-languageclient": "^8.0.2"
     },
     "devDependencies": {
         "@types/node": "~16.11.7",
@@ -60,6 +60,7 @@
         "onCommand:rust-analyzer.analyzerStatus",
         "onCommand:rust-analyzer.memoryUsage",
         "onCommand:rust-analyzer.reloadWorkspace",
+        "onCommand:rust-analyzer.startServer",
         "workspaceContains:*/Cargo.toml",
         "workspaceContains:*/rust-project.json"
     ],
@@ -192,6 +193,16 @@
                 "category": "rust-analyzer"
             },
             {
+                "command": "rust-analyzer.startServer",
+                "title": "Start server",
+                "category": "rust-analyzer"
+            },
+            {
+                "command": "rust-analyzer.stopServer",
+                "title": "Stop server",
+                "category": "rust-analyzer"
+            },
+            {
                 "command": "rust-analyzer.onEnter",
                 "title": "Enhanced enter key",
                 "category": "rust-analyzer"
@@ -421,6 +432,32 @@
                     "default": true,
                     "type": "boolean"
                 },
+                "rust-analyzer.cargo.buildScripts.invocationLocation": {
+                    "markdownDescription": "Specifies the working directory for running build scripts.\n- \"workspace\": run build scripts for a workspace in the workspace's root directory.\n    This is incompatible with `#rust-analyzer.cargo.buildScripts.invocationStrategy#` set to `once`.\n- \"root\": run build scripts in the project's root directory.\nThis config only has an effect when `#rust-analyzer.cargo.buildScripts.overrideCommand#`\nis set.",
+                    "default": "workspace",
+                    "type": "string",
+                    "enum": [
+                        "workspace",
+                        "root"
+                    ],
+                    "enumDescriptions": [
+                        "The command will be executed in the corresponding workspace root.",
+                        "The command will be executed in the project root."
+                    ]
+                },
+                "rust-analyzer.cargo.buildScripts.invocationStrategy": {
+                    "markdownDescription": "Specifies the invocation strategy to use when running the build scripts command.\nIf `per_workspace` is set, the command will be executed for each workspace.\nIf `once` is set, the command will be executed once.\nThis config only has an effect when `#rust-analyzer.cargo.buildScripts.overrideCommand#`\nis set.",
+                    "default": "per_workspace",
+                    "type": "string",
+                    "enum": [
+                        "per_workspace",
+                        "once"
+                    ],
+                    "enumDescriptions": [
+                        "The command will be executed for each workspace.",
+                        "The command will be executed once."
+                    ]
+                },
                 "rust-analyzer.cargo.buildScripts.overrideCommand": {
                     "markdownDescription": "Override the command rust-analyzer uses to run build scripts and\nbuild procedural macros. The command is required to output json\nand should therefore include `--message-format=json` or a similar\noption.\n\nBy default, a cargo invocation will be constructed for the configured\ntargets and features, with the following base command line:\n\n```bash\ncargo check --quiet --workspace --message-format=json --all-targets\n```\n.",
                     "default": null,
@@ -546,6 +583,32 @@
                         }
                     ]
                 },
+                "rust-analyzer.checkOnSave.invocationLocation": {
+                    "markdownDescription": "Specifies the working directory for running checks.\n- \"workspace\": run checks for workspaces in the corresponding workspaces' root directories.\n    This falls back to \"root\" if `#rust-analyzer.cargo.checkOnSave.invocationStrategy#` is set to `once`.\n- \"root\": run checks in the project's root directory.\nThis config only has an effect when `#rust-analyzer.cargo.buildScripts.overrideCommand#`\nis set.",
+                    "default": "workspace",
+                    "type": "string",
+                    "enum": [
+                        "workspace",
+                        "root"
+                    ],
+                    "enumDescriptions": [
+                        "The command will be executed in the corresponding workspace root.",
+                        "The command will be executed in the project root."
+                    ]
+                },
+                "rust-analyzer.checkOnSave.invocationStrategy": {
+                    "markdownDescription": "Specifies the invocation strategy to use when running the checkOnSave command.\nIf `per_workspace` is set, the command will be executed for each workspace.\nIf `once` is set, the command will be executed once.\nThis config only has an effect when `#rust-analyzer.cargo.buildScripts.overrideCommand#`\nis set.",
+                    "default": "per_workspace",
+                    "type": "string",
+                    "enum": [
+                        "per_workspace",
+                        "once"
+                    ],
+                    "enumDescriptions": [
+                        "The command will be executed for each workspace.",
+                        "The command will be executed once."
+                    ]
+                },
                 "rust-analyzer.checkOnSave.noDefaultFeatures": {
                     "markdownDescription": "Whether to pass `--no-default-features` to Cargo. Defaults to\n`#rust-analyzer.cargo.noDefaultFeatures#`.",
                     "default": null,
diff --git a/src/tools/rust-analyzer/editors/code/src/ast_inspector.ts b/src/tools/rust-analyzer/editors/code/src/ast_inspector.ts
index e57fb20e2cf..176040120f4 100644
--- a/src/tools/rust-analyzer/editors/code/src/ast_inspector.ts
+++ b/src/tools/rust-analyzer/editors/code/src/ast_inspector.ts
@@ -35,8 +35,10 @@ export class AstInspector implements vscode.HoverProvider, vscode.DefinitionProv
     });
 
     constructor(ctx: Ctx) {
-        ctx.pushCleanup(vscode.languages.registerHoverProvider({ scheme: "rust-analyzer" }, this));
-        ctx.pushCleanup(vscode.languages.registerDefinitionProvider({ language: "rust" }, this));
+        ctx.pushExtCleanup(
+            vscode.languages.registerHoverProvider({ scheme: "rust-analyzer" }, this)
+        );
+        ctx.pushExtCleanup(vscode.languages.registerDefinitionProvider({ language: "rust" }, this));
         vscode.workspace.onDidCloseTextDocument(
             this.onDidCloseTextDocument,
             this,
@@ -52,8 +54,6 @@ export class AstInspector implements vscode.HoverProvider, vscode.DefinitionProv
             this,
             ctx.subscriptions
         );
-
-        ctx.pushCleanup(this);
     }
     dispose() {
         this.setRustEditor(undefined);
diff --git a/src/tools/rust-analyzer/editors/code/src/bootstrap.ts b/src/tools/rust-analyzer/editors/code/src/bootstrap.ts
new file mode 100644
index 00000000000..374c3b8144c
--- /dev/null
+++ b/src/tools/rust-analyzer/editors/code/src/bootstrap.ts
@@ -0,0 +1,148 @@
+import * as vscode from "vscode";
+import * as os from "os";
+import { Config } from "./config";
+import { log, isValidExecutable } from "./util";
+import { PersistentState } from "./persistent_state";
+import { exec } from "child_process";
+
+export async function bootstrap(
+    context: vscode.ExtensionContext,
+    config: Config,
+    state: PersistentState
+): Promise<string> {
+    const path = await getServer(context, config, state);
+    if (!path) {
+        throw new Error(
+            "Rust Analyzer Language Server is not available. " +
+                "Please, ensure its [proper installation](https://rust-analyzer.github.io/manual.html#installation)."
+        );
+    }
+
+    log.info("Using server binary at", path);
+
+    if (!isValidExecutable(path)) {
+        if (config.serverPath) {
+            throw new Error(`Failed to execute ${path} --version. \`config.server.path\` or \`config.serverPath\` has been set explicitly.\
+            Consider removing this config or making a valid server binary available at that path.`);
+        } else {
+            throw new Error(`Failed to execute ${path} --version`);
+        }
+    }
+
+    return path;
+}
+
+async function patchelf(dest: vscode.Uri): Promise<void> {
+    await vscode.window.withProgress(
+        {
+            location: vscode.ProgressLocation.Notification,
+            title: "Patching rust-analyzer for NixOS",
+        },
+        async (progress, _) => {
+            const expression = `
+            {srcStr, pkgs ? import <nixpkgs> {}}:
+                pkgs.stdenv.mkDerivation {
+                    name = "rust-analyzer";
+                    src = /. + srcStr;
+                    phases = [ "installPhase" "fixupPhase" ];
+                    installPhase = "cp $src $out";
+                    fixupPhase = ''
+                    chmod 755 $out
+                    patchelf --set-interpreter "$(cat $NIX_CC/nix-support/dynamic-linker)" $out
+                    '';
+                }
+            `;
+            const origFile = vscode.Uri.file(dest.fsPath + "-orig");
+            await vscode.workspace.fs.rename(dest, origFile, { overwrite: true });
+            try {
+                progress.report({ message: "Patching executable", increment: 20 });
+                await new Promise((resolve, reject) => {
+                    const handle = exec(
+                        `nix-build -E - --argstr srcStr '${origFile.fsPath}' -o '${dest.fsPath}'`,
+                        (err, stdout, stderr) => {
+                            if (err != null) {
+                                reject(Error(stderr));
+                            } else {
+                                resolve(stdout);
+                            }
+                        }
+                    );
+                    handle.stdin?.write(expression);
+                    handle.stdin?.end();
+                });
+            } finally {
+                await vscode.workspace.fs.delete(origFile);
+            }
+        }
+    );
+}
+
+async function getServer(
+    context: vscode.ExtensionContext,
+    config: Config,
+    state: PersistentState
+): Promise<string | undefined> {
+    const explicitPath = serverPath(config);
+    if (explicitPath) {
+        if (explicitPath.startsWith("~/")) {
+            return os.homedir() + explicitPath.slice("~".length);
+        }
+        return explicitPath;
+    }
+    if (config.package.releaseTag === null) return "rust-analyzer";
+
+    const ext = process.platform === "win32" ? ".exe" : "";
+    const bundled = vscode.Uri.joinPath(context.extensionUri, "server", `rust-analyzer${ext}`);
+    const bundledExists = await vscode.workspace.fs.stat(bundled).then(
+        () => true,
+        () => false
+    );
+    if (bundledExists) {
+        let server = bundled;
+        if (await isNixOs()) {
+            await vscode.workspace.fs.createDirectory(config.globalStorageUri).then();
+            const dest = vscode.Uri.joinPath(config.globalStorageUri, `rust-analyzer${ext}`);
+            let exists = await vscode.workspace.fs.stat(dest).then(
+                () => true,
+                () => false
+            );
+            if (exists && config.package.version !== state.serverVersion) {
+                await vscode.workspace.fs.delete(dest);
+                exists = false;
+            }
+            if (!exists) {
+                await vscode.workspace.fs.copy(bundled, dest);
+                await patchelf(dest);
+            }
+            server = dest;
+        }
+        await state.updateServerVersion(config.package.version);
+        return server.fsPath;
+    }
+
+    await state.updateServerVersion(undefined);
+    await vscode.window.showErrorMessage(
+        "Unfortunately we don't ship binaries for your platform yet. " +
+            "You need to manually clone the rust-analyzer repository and " +
+            "run `cargo xtask install --server` to build the language server from sources. " +
+            "If you feel that your platform should be supported, please create an issue " +
+            "about that [here](https://github.com/rust-lang/rust-analyzer/issues) and we " +
+            "will consider it."
+    );
+    return undefined;
+}
+function serverPath(config: Config): string | null {
+    return process.env.__RA_LSP_SERVER_DEBUG ?? config.serverPath;
+}
+
+async function isNixOs(): Promise<boolean> {
+    try {
+        const contents = (
+            await vscode.workspace.fs.readFile(vscode.Uri.file("/etc/os-release"))
+        ).toString();
+        const idString = contents.split("\n").find((a) => a.startsWith("ID=")) || "ID=linux";
+        return idString.indexOf("nixos") !== -1;
+    } catch {
+        return false;
+    }
+}
diff --git a/src/tools/rust-analyzer/editors/code/src/client.ts b/src/tools/rust-analyzer/editors/code/src/client.ts
index 05d4d08f70b..fb667619c86 100644
--- a/src/tools/rust-analyzer/editors/code/src/client.ts
+++ b/src/tools/rust-analyzer/editors/code/src/client.ts
@@ -4,9 +4,7 @@ import * as ra from "../src/lsp_ext";
 import * as Is from "vscode-languageclient/lib/common/utils/is";
 import { assert } from "./util";
 import { WorkspaceEdit } from "vscode";
-import { Workspace } from "./ctx";
-import { substituteVariablesInEnv } from "./config";
-import { outputChannel, traceOutputChannel } from "./main";
+import { substituteVSCodeVariables } from "./config";
 import { randomUUID } from "crypto";
 
 export interface Env {
@@ -65,40 +63,42 @@ function renderHoverActions(actions: ra.CommandLinkGroup[]): vscode.MarkdownStri
 }
 
 export async function createClient(
-    serverPath: string,
-    workspace: Workspace,
-    extraEnv: Env
+    traceOutputChannel: vscode.OutputChannel,
+    outputChannel: vscode.OutputChannel,
+    initializationOptions: vscode.WorkspaceConfiguration,
+    serverOptions: lc.ServerOptions
 ): Promise<lc.LanguageClient> {
-    // '.' Is the fallback if no folder is open
-    // TODO?: Workspace folders support Uri's (eg: file://test.txt).
-    // It might be a good idea to test if the uri points to a file.
-
-    const newEnv = substituteVariablesInEnv(Object.assign({}, process.env, extraEnv));
-    const run: lc.Executable = {
-        command: serverPath,
-        options: { env: newEnv },
-    };
-    const serverOptions: lc.ServerOptions = {
-        run,
-        debug: run,
-    };
-
-    let initializationOptions = vscode.workspace.getConfiguration("rust-analyzer");
-
-    if (workspace.kind === "Detached Files") {
-        initializationOptions = {
-            detachedFiles: workspace.files.map((file) => file.uri.fsPath),
-            ...initializationOptions,
-        };
-    }
-
     const clientOptions: lc.LanguageClientOptions = {
         documentSelector: [{ scheme: "file", language: "rust" }],
         initializationOptions,
         diagnosticCollectionName: "rustc",
-        traceOutputChannel: traceOutputChannel(),
-        outputChannel: outputChannel(),
+        traceOutputChannel,
+        outputChannel,
         middleware: {
+            workspace: {
+                // HACK: This is a workaround, when the client has been disposed, VSCode
+                // continues to emit events to the client and the default one for this event
+                // attempt to restart the client for no reason
+                async didChangeWatchedFile(event, next) {
+                    if (client.isRunning()) {
+                        await next(event);
+                    }
+                },
+                async configuration(
+                    params: lc.ConfigurationParams,
+                    token: vscode.CancellationToken,
+                    next: lc.ConfigurationRequest.HandlerSignature
+                ) {
+                    const resp = await next(params, token);
+                    if (resp && Array.isArray(resp)) {
+                        return resp.map((val) => {
+                            return substituteVSCodeVariables(val);
+                        });
+                    } else {
+                        return resp;
+                    }
+                },
+            },
             async provideHover(
                 document: vscode.TextDocument,
                 position: vscode.Position,
@@ -255,6 +255,9 @@ export async function createClient(
 }
 
 class ExperimentalFeatures implements lc.StaticFeature {
+    getState(): lc.FeatureState {
+        return { kind: "static" };
+    }
     fillClientCapabilities(capabilities: lc.ClientCapabilities): void {
         const caps: any = capabilities.experimental ?? {};
         caps.snippetTextEdit = true;
diff --git a/src/tools/rust-analyzer/editors/code/src/commands.ts b/src/tools/rust-analyzer/editors/code/src/commands.ts
index b9ad525e361..12ceb4f2df8 100644
--- a/src/tools/rust-analyzer/editors/code/src/commands.ts
+++ b/src/tools/rust-analyzer/editors/code/src/commands.ts
@@ -21,16 +21,16 @@ export function analyzerStatus(ctx: Ctx): Cmd {
         readonly uri = vscode.Uri.parse("rust-analyzer-status://status");
         readonly eventEmitter = new vscode.EventEmitter<vscode.Uri>();
 
-        provideTextDocumentContent(_uri: vscode.Uri): vscode.ProviderResult<string> {
+        async provideTextDocumentContent(_uri: vscode.Uri): Promise<string> {
             if (!vscode.window.activeTextEditor) return "";
+            const client = await ctx.getClient();
 
             const params: ra.AnalyzerStatusParams = {};
             const doc = ctx.activeRustEditor?.document;
             if (doc != null) {
-                params.textDocument =
-                    ctx.client.code2ProtocolConverter.asTextDocumentIdentifier(doc);
+                params.textDocument = client.code2ProtocolConverter.asTextDocumentIdentifier(doc);
             }
-            return ctx.client.sendRequest(ra.analyzerStatus, params);
+            return await client.sendRequest(ra.analyzerStatus, params);
         }
 
         get onDidChange(): vscode.Event<vscode.Uri> {
@@ -38,7 +38,7 @@ export function analyzerStatus(ctx: Ctx): Cmd {
         }
     })();
 
-    ctx.pushCleanup(
+    ctx.pushExtCleanup(
         vscode.workspace.registerTextDocumentContentProvider("rust-analyzer-status", tdcp)
     );
 
@@ -60,9 +60,14 @@ export function memoryUsage(ctx: Ctx): Cmd {
         provideTextDocumentContent(_uri: vscode.Uri): vscode.ProviderResult<string> {
             if (!vscode.window.activeTextEditor) return "";
 
-            return ctx.client.sendRequest(ra.memoryUsage).then((mem: any) => {
-                return "Per-query memory usage:\n" + mem + "\n(note: database has been cleared)";
-            });
+            return ctx
+                .getClient()
+                .then((it) => it.sendRequest(ra.memoryUsage))
+                .then((mem: any) => {
+                    return (
+                        "Per-query memory usage:\n" + mem + "\n(note: database has been cleared)"
+                    );
+                });
         }
 
         get onDidChange(): vscode.Event<vscode.Uri> {
@@ -70,7 +75,7 @@ export function memoryUsage(ctx: Ctx): Cmd {
         }
     })();
 
-    ctx.pushCleanup(
+    ctx.pushExtCleanup(
         vscode.workspace.registerTextDocumentContentProvider("rust-analyzer-memory", tdcp)
     );
 
@@ -83,23 +88,19 @@ export function memoryUsage(ctx: Ctx): Cmd {
 
 export function shuffleCrateGraph(ctx: Ctx): Cmd {
     return async () => {
-        const client = ctx.client;
-        if (!client) return;
-
-        await client.sendRequest(ra.shuffleCrateGraph);
+        return ctx.getClient().then((it) => it.sendRequest(ra.shuffleCrateGraph));
     };
 }
 
 export function matchingBrace(ctx: Ctx): Cmd {
     return async () => {
         const editor = ctx.activeRustEditor;
-        const client = ctx.client;
-        if (!editor || !client) return;
+        if (!editor) return;
+
+        const client = await ctx.getClient();
 
         const response = await client.sendRequest(ra.matchingBrace, {
-            textDocument: ctx.client.code2ProtocolConverter.asTextDocumentIdentifier(
-                editor.document
-            ),
+            textDocument: client.code2ProtocolConverter.asTextDocumentIdentifier(editor.document),
             positions: editor.selections.map((s) =>
                 client.code2ProtocolConverter.asPosition(s.active)
             ),
@@ -116,14 +117,13 @@ export function matchingBrace(ctx: Ctx): Cmd {
 export function joinLines(ctx: Ctx): Cmd {
     return async () => {
         const editor = ctx.activeRustEditor;
-        const client = ctx.client;
-        if (!editor || !client) return;
+        if (!editor) return;
+
+        const client = await ctx.getClient();
 
         const items: lc.TextEdit[] = await client.sendRequest(ra.joinLines, {
             ranges: editor.selections.map((it) => client.code2ProtocolConverter.asRange(it)),
-            textDocument: ctx.client.code2ProtocolConverter.asTextDocumentIdentifier(
-                editor.document
-            ),
+            textDocument: client.code2ProtocolConverter.asTextDocumentIdentifier(editor.document),
         });
         const textEdits = await client.protocol2CodeConverter.asTextEdits(items);
         await editor.edit((builder) => {
@@ -145,14 +145,12 @@ export function moveItemDown(ctx: Ctx): Cmd {
 export function moveItem(ctx: Ctx, direction: ra.Direction): Cmd {
     return async () => {
         const editor = ctx.activeRustEditor;
-        const client = ctx.client;
-        if (!editor || !client) return;
+        if (!editor) return;
+        const client = await ctx.getClient();
 
         const lcEdits = await client.sendRequest(ra.moveItem, {
             range: client.code2ProtocolConverter.asRange(editor.selection),
-            textDocument: ctx.client.code2ProtocolConverter.asTextDocumentIdentifier(
-                editor.document
-            ),
+            textDocument: client.code2ProtocolConverter.asTextDocumentIdentifier(editor.document),
             direction,
         });
 
@@ -166,13 +164,13 @@ export function moveItem(ctx: Ctx, direction: ra.Direction): Cmd {
 export function onEnter(ctx: Ctx): Cmd {
     async function handleKeypress() {
         const editor = ctx.activeRustEditor;
-        const client = ctx.client;
 
-        if (!editor || !client) return false;
+        if (!editor) return false;
 
+        const client = await ctx.getClient();
         const lcEdits = await client
             .sendRequest(ra.onEnter, {
-                textDocument: ctx.client.code2ProtocolConverter.asTextDocumentIdentifier(
+                textDocument: client.code2ProtocolConverter.asTextDocumentIdentifier(
                     editor.document
                 ),
                 position: client.code2ProtocolConverter.asPosition(editor.selection.active),
@@ -198,14 +196,13 @@ export function onEnter(ctx: Ctx): Cmd {
 export function parentModule(ctx: Ctx): Cmd {
     return async () => {
         const editor = vscode.window.activeTextEditor;
-        const client = ctx.client;
-        if (!editor || !client) return;
+        if (!editor) return;
         if (!(isRustDocument(editor.document) || isCargoTomlDocument(editor.document))) return;
 
+        const client = await ctx.getClient();
+
         const locations = await client.sendRequest(ra.parentModule, {
-            textDocument: ctx.client.code2ProtocolConverter.asTextDocumentIdentifier(
-                editor.document
-            ),
+            textDocument: client.code2ProtocolConverter.asTextDocumentIdentifier(editor.document),
             position: client.code2ProtocolConverter.asPosition(editor.selection.active),
         });
         if (!locations) return;
@@ -236,13 +233,11 @@ export function parentModule(ctx: Ctx): Cmd {
 export function openCargoToml(ctx: Ctx): Cmd {
     return async () => {
         const editor = ctx.activeRustEditor;
-        const client = ctx.client;
-        if (!editor || !client) return;
+        if (!editor) return;
 
+        const client = await ctx.getClient();
         const response = await client.sendRequest(ra.openCargoToml, {
-            textDocument: ctx.client.code2ProtocolConverter.asTextDocumentIdentifier(
-                editor.document
-            ),
+            textDocument: client.code2ProtocolConverter.asTextDocumentIdentifier(editor.document),
         });
         if (!response) return;
 
@@ -259,12 +254,13 @@ export function openCargoToml(ctx: Ctx): Cmd {
 export function ssr(ctx: Ctx): Cmd {
     return async () => {
         const editor = vscode.window.activeTextEditor;
-        const client = ctx.client;
-        if (!editor || !client) return;
+        if (!editor) return;
+
+        const client = await ctx.getClient();
 
         const position = editor.selection.active;
         const selections = editor.selections;
-        const textDocument = ctx.client.code2ProtocolConverter.asTextDocumentIdentifier(
+        const textDocument = client.code2ProtocolConverter.asTextDocumentIdentifier(
             editor.document
         );
 
@@ -314,6 +310,10 @@ export function ssr(ctx: Ctx): Cmd {
 
 export function serverVersion(ctx: Ctx): Cmd {
     return async () => {
+        if (!ctx.serverPath) {
+            void vscode.window.showWarningMessage(`rust-analyzer server is not running`);
+            return;
+        }
         const { stdout } = spawnSync(ctx.serverPath, ["--version"], { encoding: "utf8" });
         const versionString = stdout.slice(`rust-analyzer `.length).trim();
 
@@ -354,21 +354,22 @@ export function syntaxTree(ctx: Ctx): Cmd {
             }
         }
 
-        provideTextDocumentContent(
+        async provideTextDocumentContent(
             uri: vscode.Uri,
             ct: vscode.CancellationToken
-        ): vscode.ProviderResult<string> {
+        ): Promise<string> {
             const rustEditor = ctx.activeRustEditor;
             if (!rustEditor) return "";
+            const client = await ctx.getClient();
 
             // When the range based query is enabled we take the range of the selection
             const range =
                 uri.query === "range=true" && !rustEditor.selection.isEmpty
-                    ? ctx.client.code2ProtocolConverter.asRange(rustEditor.selection)
+                    ? client.code2ProtocolConverter.asRange(rustEditor.selection)
                     : null;
 
             const params = { textDocument: { uri: rustEditor.document.uri.toString() }, range };
-            return ctx.client.sendRequest(ra.syntaxTree, params, ct);
+            return client.sendRequest(ra.syntaxTree, params, ct);
         }
 
         get onDidChange(): vscode.Event<vscode.Uri> {
@@ -376,12 +377,11 @@ export function syntaxTree(ctx: Ctx): Cmd {
         }
     })();
 
-    void new AstInspector(ctx);
-
-    ctx.pushCleanup(
+    ctx.pushExtCleanup(new AstInspector(ctx));
+    ctx.pushExtCleanup(
         vscode.workspace.registerTextDocumentContentProvider("rust-analyzer-syntax-tree", tdcp)
     );
-    ctx.pushCleanup(
+    ctx.pushExtCleanup(
         vscode.languages.setLanguageConfiguration("ra_syntax_tree", {
             brackets: [["[", ")"]],
         })
@@ -437,14 +437,14 @@ export function viewHir(ctx: Ctx): Cmd {
             }
         }
 
-        provideTextDocumentContent(
+        async provideTextDocumentContent(
             _uri: vscode.Uri,
             ct: vscode.CancellationToken
-        ): vscode.ProviderResult<string> {
+        ): Promise<string> {
             const rustEditor = ctx.activeRustEditor;
-            const client = ctx.client;
-            if (!rustEditor || !client) return "";
+            if (!rustEditor) return "";
 
+            const client = await ctx.getClient();
             const params = {
                 textDocument: client.code2ProtocolConverter.asTextDocumentIdentifier(
                     rustEditor.document
@@ -459,7 +459,7 @@ export function viewHir(ctx: Ctx): Cmd {
         }
     })();
 
-    ctx.pushCleanup(
+    ctx.pushExtCleanup(
         vscode.workspace.registerTextDocumentContentProvider("rust-analyzer-hir", tdcp)
     );
 
@@ -503,13 +503,13 @@ export function viewFileText(ctx: Ctx): Cmd {
             }
         }
 
-        provideTextDocumentContent(
+        async provideTextDocumentContent(
             _uri: vscode.Uri,
             ct: vscode.CancellationToken
-        ): vscode.ProviderResult<string> {
+        ): Promise<string> {
             const rustEditor = ctx.activeRustEditor;
-            const client = ctx.client;
-            if (!rustEditor || !client) return "";
+            if (!rustEditor) return "";
+            const client = await ctx.getClient();
 
             const params = client.code2ProtocolConverter.asTextDocumentIdentifier(
                 rustEditor.document
@@ -522,7 +522,7 @@ export function viewFileText(ctx: Ctx): Cmd {
         }
     })();
 
-    ctx.pushCleanup(
+    ctx.pushExtCleanup(
         vscode.workspace.registerTextDocumentContentProvider("rust-analyzer-file-text", tdcp)
     );
 
@@ -566,13 +566,13 @@ export function viewItemTree(ctx: Ctx): Cmd {
             }
         }
 
-        provideTextDocumentContent(
+        async provideTextDocumentContent(
             _uri: vscode.Uri,
             ct: vscode.CancellationToken
-        ): vscode.ProviderResult<string> {
+        ): Promise<string> {
             const rustEditor = ctx.activeRustEditor;
-            const client = ctx.client;
-            if (!rustEditor || !client) return "";
+            if (!rustEditor) return "";
+            const client = await ctx.getClient();
 
             const params = {
                 textDocument: client.code2ProtocolConverter.asTextDocumentIdentifier(
@@ -587,7 +587,7 @@ export function viewItemTree(ctx: Ctx): Cmd {
         }
     })();
 
-    ctx.pushCleanup(
+    ctx.pushExtCleanup(
         vscode.workspace.registerTextDocumentContentProvider("rust-analyzer-item-tree", tdcp)
     );
 
@@ -618,8 +618,8 @@ function crateGraph(ctx: Ctx, full: boolean): Cmd {
         const params = {
             full: full,
         };
-
-        const dot = await ctx.client.sendRequest(ra.viewCrateGraph, params);
+        const client = await ctx.getClient();
+        const dot = await client.sendRequest(ra.viewCrateGraph, params);
         const uri = panel.webview.asWebviewUri(nodeModulesPath);
 
         const html = `
@@ -690,13 +690,13 @@ export function expandMacro(ctx: Ctx): Cmd {
         eventEmitter = new vscode.EventEmitter<vscode.Uri>();
         async provideTextDocumentContent(_uri: vscode.Uri): Promise<string> {
             const editor = vscode.window.activeTextEditor;
-            const client = ctx.client;
-            if (!editor || !client) return "";
+            if (!editor) return "";
+            const client = await ctx.getClient();
 
             const position = editor.selection.active;
 
             const expanded = await client.sendRequest(ra.expandMacro, {
-                textDocument: ctx.client.code2ProtocolConverter.asTextDocumentIdentifier(
+                textDocument: client.code2ProtocolConverter.asTextDocumentIdentifier(
                     editor.document
                 ),
                 position,
@@ -712,7 +712,7 @@ export function expandMacro(ctx: Ctx): Cmd {
         }
     })();
 
-    ctx.pushCleanup(
+    ctx.pushExtCleanup(
         vscode.workspace.registerTextDocumentContentProvider("rust-analyzer-expand-macro", tdcp)
     );
 
@@ -724,11 +724,11 @@ export function expandMacro(ctx: Ctx): Cmd {
 }
 
 export function reloadWorkspace(ctx: Ctx): Cmd {
-    return async () => ctx.client.sendRequest(ra.reloadWorkspace);
+    return async () => (await ctx.getClient()).sendRequest(ra.reloadWorkspace);
 }
 
 async function showReferencesImpl(
-    client: LanguageClient,
+    client: LanguageClient | undefined,
     uri: string,
     position: lc.Position,
     locations: lc.Location[]
@@ -745,7 +745,7 @@ async function showReferencesImpl(
 
 export function showReferences(ctx: Ctx): Cmd {
     return async (uri: string, position: lc.Position, locations: lc.Location[]) => {
-        await showReferencesImpl(ctx.client, uri, position, locations);
+        await showReferencesImpl(await ctx.getClient(), uri, position, locations);
     };
 }
 
@@ -762,25 +762,23 @@ export function applyActionGroup(_ctx: Ctx): Cmd {
 
 export function gotoLocation(ctx: Ctx): Cmd {
     return async (locationLink: lc.LocationLink) => {
-        const client = ctx.client;
-        if (client) {
-            const uri = client.protocol2CodeConverter.asUri(locationLink.targetUri);
-            let range = client.protocol2CodeConverter.asRange(locationLink.targetSelectionRange);
-            // collapse the range to a cursor position
-            range = range.with({ end: range.start });
+        const client = await ctx.getClient();
+        const uri = client.protocol2CodeConverter.asUri(locationLink.targetUri);
+        let range = client.protocol2CodeConverter.asRange(locationLink.targetSelectionRange);
+        // collapse the range to a cursor position
+        range = range.with({ end: range.start });
 
-            await vscode.window.showTextDocument(uri, { selection: range });
-        }
+        await vscode.window.showTextDocument(uri, { selection: range });
     };
 }
 
 export function openDocs(ctx: Ctx): Cmd {
     return async () => {
-        const client = ctx.client;
         const editor = vscode.window.activeTextEditor;
-        if (!editor || !client) {
+        if (!editor) {
             return;
         }
+        const client = await ctx.getClient();
 
         const position = editor.selection.active;
         const textDocument = { uri: editor.document.uri.toString() };
@@ -795,20 +793,21 @@ export function openDocs(ctx: Ctx): Cmd {
 
 export function cancelFlycheck(ctx: Ctx): Cmd {
     return async () => {
-        await ctx.client.sendRequest(ra.cancelFlycheck);
+        const client = await ctx.getClient();
+        await client.sendRequest(ra.cancelFlycheck);
     };
 }
 
 export function resolveCodeAction(ctx: Ctx): Cmd {
-    const client = ctx.client;
     return async (params: lc.CodeAction) => {
+        const client = await ctx.getClient();
         params.command = undefined;
-        const item = await client.sendRequest(lc.CodeActionResolveRequest.type, params);
-        if (!item.edit) {
+        const item = await client?.sendRequest(lc.CodeActionResolveRequest.type, params);
+        if (!item?.edit) {
             return;
         }
         const itemEdit = item.edit;
-        const edit = await client.protocol2CodeConverter.asWorkspaceEdit(itemEdit);
+        const edit = await client?.protocol2CodeConverter.asWorkspaceEdit(itemEdit);
         // filter out all text edits and recreate the WorkspaceEdit without them so we can apply
         // snippet edits on our own
         const lcFileSystemEdit = {
@@ -847,11 +846,10 @@ export function run(ctx: Ctx): Cmd {
 }
 
 export function peekTests(ctx: Ctx): Cmd {
-    const client = ctx.client;
-
     return async () => {
         const editor = ctx.activeRustEditor;
-        if (!editor || !client) return;
+        if (!editor) return;
+        const client = await ctx.getClient();
 
         await vscode.window.withProgress(
             {
@@ -937,10 +935,10 @@ export function newDebugConfig(ctx: Ctx): Cmd {
     };
 }
 
-export function linkToCommand(ctx: Ctx): Cmd {
+export function linkToCommand(_: Ctx): Cmd {
     return async (commandId: string) => {
         const link = LINKED_COMMANDS.get(commandId);
-        if (ctx.client && link) {
+        if (link) {
             const { command, arguments: args = [] } = link;
             await vscode.commands.executeCommand(command, ...args);
         }
diff --git a/src/tools/rust-analyzer/editors/code/src/config.ts b/src/tools/rust-analyzer/editors/code/src/config.ts
index 15846a5e864..632a7d86faa 100644
--- a/src/tools/rust-analyzer/editors/code/src/config.ts
+++ b/src/tools/rust-analyzer/editors/code/src/config.ts
@@ -1,4 +1,5 @@
-import path = require("path");
+import * as path from "path";
+import * as os from "os";
 import * as vscode from "vscode";
 import { Env } from "./client";
 import { log } from "./util";
@@ -10,23 +11,17 @@ export type RunnableEnvCfg =
 
 export class Config {
     readonly extensionId = "rust-lang.rust-analyzer";
+    configureLang: vscode.Disposable | undefined;
 
     readonly rootSection = "rust-analyzer";
-    private readonly requiresWorkspaceReloadOpts = [
-        "serverPath",
-        "server",
-        // FIXME: This shouldn't be here, changing this setting should reload
-        // `continueCommentsOnNewline` behavior without restart
-        "typing",
-    ].map((opt) => `${this.rootSection}.${opt}`);
     private readonly requiresReloadOpts = [
         "cargo",
         "procMacro",
+        "serverPath",
+        "server",
         "files",
         "lens", // works as lens.*
-    ]
-        .map((opt) => `${this.rootSection}.${opt}`)
-        .concat(this.requiresWorkspaceReloadOpts);
+    ].map((opt) => `${this.rootSection}.${opt}`);
 
     readonly package: {
         version: string;
@@ -44,6 +39,11 @@ export class Config {
             ctx.subscriptions
         );
         this.refreshLogging();
+        this.configureLanguage();
+    }
+
+    dispose() {
+        this.configureLang?.dispose();
     }
 
     private refreshLogging() {
@@ -57,33 +57,86 @@ export class Config {
     private async onDidChangeConfiguration(event: vscode.ConfigurationChangeEvent) {
         this.refreshLogging();
 
+        this.configureLanguage();
+
         const requiresReloadOpt = this.requiresReloadOpts.find((opt) =>
             event.affectsConfiguration(opt)
         );
 
         if (!requiresReloadOpt) return;
 
-        const requiresWorkspaceReloadOpt = this.requiresWorkspaceReloadOpts.find((opt) =>
-            event.affectsConfiguration(opt)
-        );
-
-        if (!requiresWorkspaceReloadOpt && this.restartServerOnConfigChange) {
+        if (this.restartServerOnConfigChange) {
             await vscode.commands.executeCommand("rust-analyzer.reload");
             return;
         }
 
-        const message = requiresWorkspaceReloadOpt
-            ? `Changing "${requiresWorkspaceReloadOpt}" requires a window reload`
-            : `Changing "${requiresReloadOpt}" requires a reload`;
-        const userResponse = await vscode.window.showInformationMessage(message, "Reload now");
-
-        if (userResponse === "Reload now") {
-            const command = requiresWorkspaceReloadOpt
-                ? "workbench.action.reloadWindow"
-                : "rust-analyzer.reload";
-            if (userResponse === "Reload now") {
-                await vscode.commands.executeCommand(command);
-            }
+        const message = `Changing "${requiresReloadOpt}" requires a server restart`;
+        const userResponse = await vscode.window.showInformationMessage(message, "Restart now");
+
+        if (userResponse) {
+            const command = "rust-analyzer.reload";
+            await vscode.commands.executeCommand(command);
+        }
+    }
+
+    /**
+     * Sets up additional language configuration that's impossible to do via a
+     * separate language-configuration.json file. See [1] for more information.
+     *
+     * [1]: https://github.com/Microsoft/vscode/issues/11514#issuecomment-244707076
+     */
+    private configureLanguage() {
+        if (this.typingContinueCommentsOnNewline && !this.configureLang) {
+            const indentAction = vscode.IndentAction.None;
+
+            this.configureLang = vscode.languages.setLanguageConfiguration("rust", {
+                onEnterRules: [
+                    {
+                        // Doc single-line comment
+                        // e.g. ///|
+                        beforeText: /^\s*\/{3}.*$/,
+                        action: { indentAction, appendText: "/// " },
+                    },
+                    {
+                        // Parent doc single-line comment
+                        // e.g. //!|
+                        beforeText: /^\s*\/{2}\!.*$/,
+                        action: { indentAction, appendText: "//! " },
+                    },
+                    {
+                        // Begins an auto-closed multi-line comment (standard or parent doc)
+                        // e.g. /** | */ or /*! | */
+                        beforeText: /^\s*\/\*(\*|\!)(?!\/)([^\*]|\*(?!\/))*$/,
+                        afterText: /^\s*\*\/$/,
+                        action: {
+                            indentAction: vscode.IndentAction.IndentOutdent,
+                            appendText: " * ",
+                        },
+                    },
+                    {
+                        // Begins a multi-line comment (standard or parent doc)
+                        // e.g. /** ...| or /*! ...|
+                        beforeText: /^\s*\/\*(\*|\!)(?!\/)([^\*]|\*(?!\/))*$/,
+                        action: { indentAction, appendText: " * " },
+                    },
+                    {
+                        // Continues a multi-line comment
+                        // e.g.  * ...|
+                        beforeText: /^(\ \ )*\ \*(\ ([^\*]|\*(?!\/))*)?$/,
+                        action: { indentAction, appendText: "* " },
+                    },
+                    {
+                        // Dedents after closing a multi-line comment
+                        // e.g.  */|
+                        beforeText: /^(\ \ )*\ \*\/\s*$/,
+                        action: { indentAction, removeText: 1 },
+                    },
+                ],
+            });
+        }
+        if (!this.typingContinueCommentsOnNewline && this.configureLang) {
+            this.configureLang.dispose();
+            this.configureLang = undefined;
         }
     }
 
@@ -187,6 +240,37 @@ export class Config {
     }
 }
 
+const VarRegex = new RegExp(/\$\{(.+?)\}/g);
+
+export function substituteVSCodeVariableInString(val: string): string {
+    return val.replace(VarRegex, (substring: string, varName) => {
+        if (typeof varName === "string") {
+            return computeVscodeVar(varName) || substring;
+        } else {
+            return substring;
+        }
+    });
+}
+
+export function substituteVSCodeVariables(resp: any): any {
+    if (typeof resp === "string") {
+        return substituteVSCodeVariableInString(resp);
+    } else if (resp && Array.isArray(resp)) {
+        return resp.map((val) => {
+            return substituteVSCodeVariables(val);
+        });
+    } else if (resp && typeof resp === "object") {
+        const res: { [key: string]: any } = {};
+        for (const key in resp) {
+            const val = resp[key];
+            res[key] = substituteVSCodeVariables(val);
+        }
+        return res;
+    } else if (typeof resp === "function") {
+        return null;
+    }
+    return resp;
+}
 export function substituteVariablesInEnv(env: Env): Env {
     const missingDeps = new Set<string>();
     // vscode uses `env:ENV_NAME` for env vars resolution, and it's easier
@@ -233,7 +317,7 @@ export function substituteVariablesInEnv(env: Env): Env {
             }
         } else {
             envWithDeps[dep] = {
-                value: computeVscodeVar(dep),
+                value: computeVscodeVar(dep) || "${" + dep + "}",
                 deps: [],
             };
         }
@@ -264,37 +348,34 @@ export function substituteVariablesInEnv(env: Env): Env {
     return resolvedEnv;
 }
 
-function computeVscodeVar(varName: string): string {
+function computeVscodeVar(varName: string): string | null {
+    const workspaceFolder = () => {
+        const folders = vscode.workspace.workspaceFolders ?? [];
+        if (folders.length === 1) {
+            // TODO: support for remote workspaces?
+            return folders[0].uri.fsPath;
+        } else if (folders.length > 1) {
+            // could use currently opened document to detect the correct
+            // workspace. However, that would be determined by the document
+            // user has opened on Editor startup. Could lead to
+            // unpredictable workspace selection in practice.
+            // It's better to pick the first one
+            return folders[0].uri.fsPath;
+        } else {
+            // no workspace opened
+            return "";
+        }
+    };
     // https://code.visualstudio.com/docs/editor/variables-reference
     const supportedVariables: { [k: string]: () => string } = {
-        workspaceFolder: () => {
-            const folders = vscode.workspace.workspaceFolders ?? [];
-            if (folders.length === 1) {
-                // TODO: support for remote workspaces?
-                return folders[0].uri.fsPath;
-            } else if (folders.length > 1) {
-                // could use currently opened document to detect the correct
-                // workspace. However, that would be determined by the document
-                // user has opened on Editor startup. Could lead to
-                // unpredictable workspace selection in practice.
-                // It's better to pick the first one
-                return folders[0].uri.fsPath;
-            } else {
-                // no workspace opened
-                return "";
-            }
-        },
+        workspaceFolder,
 
         workspaceFolderBasename: () => {
-            const workspaceFolder = computeVscodeVar("workspaceFolder");
-            if (workspaceFolder) {
-                return path.basename(workspaceFolder);
-            } else {
-                return "";
-            }
+            return path.basename(workspaceFolder());
         },
 
         cwd: () => process.cwd(),
+        userHome: () => os.homedir(),
 
         // see
         // https://github.com/microsoft/vscode/blob/08ac1bb67ca2459496b272d8f4a908757f24f56f/src/vs/workbench/api/common/extHostVariableResolverService.ts#L81
@@ -308,7 +389,7 @@ function computeVscodeVar(varName: string): string {
     if (varName in supportedVariables) {
         return supportedVariables[varName]();
     } else {
-        // can't resolve, keep the expression as is
-        return "${" + varName + "}";
+        // return "${" + varName + "}";
+        return null;
     }
 }
diff --git a/src/tools/rust-analyzer/editors/code/src/ctx.ts b/src/tools/rust-analyzer/editors/code/src/ctx.ts
index 26510011d43..044a9470aa9 100644
--- a/src/tools/rust-analyzer/editors/code/src/ctx.ts
+++ b/src/tools/rust-analyzer/editors/code/src/ctx.ts
@@ -2,10 +2,12 @@ import * as vscode from "vscode";
 import * as lc from "vscode-languageclient/node";
 import * as ra from "./lsp_ext";
 
-import { Config } from "./config";
+import { Config, substituteVariablesInEnv, substituteVSCodeVariables } from "./config";
 import { createClient } from "./client";
-import { isRustEditor, RustEditor } from "./util";
+import { isRustEditor, log, RustEditor } from "./util";
 import { ServerStatusParams } from "./lsp_ext";
+import { PersistentState } from "./persistent_state";
+import { bootstrap } from "./bootstrap";
 
 export type Workspace =
     | {
@@ -16,66 +18,192 @@ export type Workspace =
           files: vscode.TextDocument[];
       };
 
+export type CommandFactory = {
+    enabled: (ctx: Ctx) => Cmd;
+    disabled?: (ctx: Ctx) => Cmd;
+};
+
 export class Ctx {
-    private constructor(
-        readonly config: Config,
-        private readonly extCtx: vscode.ExtensionContext,
-        readonly client: lc.LanguageClient,
-        readonly serverPath: string,
-        readonly statusBar: vscode.StatusBarItem
-    ) {}
-
-    static async create(
-        config: Config,
-        extCtx: vscode.ExtensionContext,
-        serverPath: string,
-        workspace: Workspace
-    ): Promise<Ctx> {
-        const client = await createClient(serverPath, workspace, config.serverExtraEnv);
-
-        const statusBar = vscode.window.createStatusBarItem(vscode.StatusBarAlignment.Left);
-        extCtx.subscriptions.push(statusBar);
-        statusBar.text = "rust-analyzer";
-        statusBar.tooltip = "ready";
-        statusBar.command = "rust-analyzer.analyzerStatus";
-        statusBar.show();
-
-        const res = new Ctx(config, extCtx, client, serverPath, statusBar);
-
-        res.pushCleanup(client.start());
-        await client.onReady();
-        client.onNotification(ra.serverStatus, (params) => res.setServerStatus(params));
-        return res;
+    readonly statusBar: vscode.StatusBarItem;
+    readonly config: Config;
+
+    private client: lc.LanguageClient | undefined;
+    private _serverPath: string | undefined;
+    private traceOutputChannel: vscode.OutputChannel | undefined;
+    private outputChannel: vscode.OutputChannel | undefined;
+    private clientSubscriptions: Disposable[];
+    private state: PersistentState;
+    private commandFactories: Record<string, CommandFactory>;
+    private commandDisposables: Disposable[];
+
+    workspace: Workspace;
+
+    constructor(
+        readonly extCtx: vscode.ExtensionContext,
+        workspace: Workspace,
+        commandFactories: Record<string, CommandFactory>
+    ) {
+        extCtx.subscriptions.push(this);
+        this.statusBar = vscode.window.createStatusBarItem(vscode.StatusBarAlignment.Left);
+        this.statusBar.text = "rust-analyzer";
+        this.statusBar.tooltip = "ready";
+        this.statusBar.command = "rust-analyzer.analyzerStatus";
+        this.statusBar.show();
+        this.workspace = workspace;
+        this.clientSubscriptions = [];
+        this.commandDisposables = [];
+        this.commandFactories = commandFactories;
+
+        this.state = new PersistentState(extCtx.globalState);
+        this.config = new Config(extCtx);
+
+        this.updateCommands();
     }
 
-    get activeRustEditor(): RustEditor | undefined {
-        const editor = vscode.window.activeTextEditor;
-        return editor && isRustEditor(editor) ? editor : undefined;
+    dispose() {
+        this.config.dispose();
+        this.statusBar.dispose();
+        void this.disposeClient();
+        this.commandDisposables.forEach((disposable) => disposable.dispose());
     }
 
-    get visibleRustEditors(): RustEditor[] {
-        return vscode.window.visibleTextEditors.filter(isRustEditor);
+    clientFetcher() {
+        const self = this;
+        return {
+            get client(): lc.LanguageClient | undefined {
+                return self.client;
+            },
+        };
     }
 
-    registerCommand(name: string, factory: (ctx: Ctx) => Cmd) {
-        const fullName = `rust-analyzer.${name}`;
-        const cmd = factory(this);
-        const d = vscode.commands.registerCommand(fullName, cmd);
-        this.pushCleanup(d);
+    async getClient() {
+        if (!this.traceOutputChannel) {
+            this.traceOutputChannel = vscode.window.createOutputChannel(
+                "Rust Analyzer Language Server Trace"
+            );
+            this.pushExtCleanup(this.traceOutputChannel);
+        }
+        if (!this.outputChannel) {
+            this.outputChannel = vscode.window.createOutputChannel("Rust Analyzer Language Server");
+            this.pushExtCleanup(this.outputChannel);
+        }
+
+        if (!this.client) {
+            this._serverPath = await bootstrap(this.extCtx, this.config, this.state).catch(
+                (err) => {
+                    let message = "bootstrap error. ";
+
+                    message +=
+                        'See the logs in "OUTPUT > Rust Analyzer Client" (should open automatically). ';
+                    message +=
+                        'To enable verbose logs use { "rust-analyzer.trace.extension": true }';
+
+                    log.error("Bootstrap error", err);
+                    throw new Error(message);
+                }
+            );
+            const newEnv = substituteVariablesInEnv(
+                Object.assign({}, process.env, this.config.serverExtraEnv)
+            );
+            const run: lc.Executable = {
+                command: this._serverPath,
+                options: { env: newEnv },
+            };
+            const serverOptions = {
+                run,
+                debug: run,
+            };
+
+            let rawInitializationOptions = vscode.workspace.getConfiguration("rust-analyzer");
+
+            if (this.workspace.kind === "Detached Files") {
+                rawInitializationOptions = {
+                    detachedFiles: this.workspace.files.map((file) => file.uri.fsPath),
+                    ...rawInitializationOptions,
+                };
+            }
+
+            const initializationOptions = substituteVSCodeVariables(rawInitializationOptions);
+
+            this.client = await createClient(
+                this.traceOutputChannel,
+                this.outputChannel,
+                initializationOptions,
+                serverOptions
+            );
+            this.pushClientCleanup(
+                this.client.onNotification(ra.serverStatus, (params) =>
+                    this.setServerStatus(params)
+                )
+            );
+        }
+        return this.client;
     }
 
-    get extensionPath(): string {
-        return this.extCtx.extensionPath;
+    async activate() {
+        log.info("Activating language client");
+        const client = await this.getClient();
+        await client.start();
+        this.updateCommands();
+        return client;
+    }
+
+    async deactivate() {
+        log.info("Deactivating language client");
+        await this.client?.stop();
+        this.updateCommands();
+    }
+
+    async stop() {
+        log.info("Stopping language client");
+        await this.disposeClient();
+        this.updateCommands();
+    }
+
+    private async disposeClient() {
+        this.clientSubscriptions?.forEach((disposable) => disposable.dispose());
+        this.clientSubscriptions = [];
+        await this.client?.dispose();
+        this._serverPath = undefined;
+        this.client = undefined;
+    }
+
+    get activeRustEditor(): RustEditor | undefined {
+        const editor = vscode.window.activeTextEditor;
+        return editor && isRustEditor(editor) ? editor : undefined;
     }
 
-    get globalState(): vscode.Memento {
-        return this.extCtx.globalState;
+    get extensionPath(): string {
+        return this.extCtx.extensionPath;
     }
 
     get subscriptions(): Disposable[] {
         return this.extCtx.subscriptions;
     }
 
+    get serverPath(): string | undefined {
+        return this._serverPath;
+    }
+
+    private updateCommands() {
+        this.commandDisposables.forEach((disposable) => disposable.dispose());
+        this.commandDisposables = [];
+        const fetchFactory = (factory: CommandFactory, fullName: string) => {
+            return this.client && this.client.isRunning()
+                ? factory.enabled
+                : factory.disabled ||
+                      ((_) => () =>
+                          vscode.window.showErrorMessage(
+                              `command ${fullName} failed: rust-analyzer server is not running`
+                          ));
+        };
+        for (const [name, factory] of Object.entries(this.commandFactories)) {
+            const fullName = `rust-analyzer.${name}`;
+            const callback = fetchFactory(factory, fullName)(this);
+            this.commandDisposables.push(vscode.commands.registerCommand(fullName, callback));
+        }
+    }
+
     setServerStatus(status: ServerStatusParams) {
         let icon = "";
         const statusBar = this.statusBar;
@@ -111,9 +239,13 @@ export class Ctx {
         statusBar.text = `${icon}rust-analyzer`;
     }
 
-    pushCleanup(d: Disposable) {
+    pushExtCleanup(d: Disposable) {
         this.extCtx.subscriptions.push(d);
     }
+
+    private pushClientCleanup(d: Disposable) {
+        this.clientSubscriptions.push(d);
+    }
 }
 
 export interface Disposable {
diff --git a/src/tools/rust-analyzer/editors/code/src/main.ts b/src/tools/rust-analyzer/editors/code/src/main.ts
index 41bde4195e0..8c3a676ffb0 100644
--- a/src/tools/rust-analyzer/editors/code/src/main.ts
+++ b/src/tools/rust-analyzer/editors/code/src/main.ts
@@ -1,53 +1,37 @@
 import * as vscode from "vscode";
 import * as lc from "vscode-languageclient/node";
-import * as os from "os";
 
 import * as commands from "./commands";
-import { Ctx } from "./ctx";
-import { Config } from "./config";
-import { log, isValidExecutable, isRustDocument } from "./util";
-import { PersistentState } from "./persistent_state";
+import { CommandFactory, Ctx, Workspace } from "./ctx";
+import { isRustDocument } from "./util";
 import { activateTaskProvider } from "./tasks";
 import { setContextValue } from "./util";
-import { exec } from "child_process";
-
-let ctx: Ctx | undefined;
 
 const RUST_PROJECT_CONTEXT_NAME = "inRustProject";
 
-let TRACE_OUTPUT_CHANNEL: vscode.OutputChannel | null = null;
-export function traceOutputChannel() {
-    if (!TRACE_OUTPUT_CHANNEL) {
-        TRACE_OUTPUT_CHANNEL = vscode.window.createOutputChannel(
-            "Rust Analyzer Language Server Trace"
-        );
-    }
-    return TRACE_OUTPUT_CHANNEL;
-}
-let OUTPUT_CHANNEL: vscode.OutputChannel | null = null;
-export function outputChannel() {
-    if (!OUTPUT_CHANNEL) {
-        OUTPUT_CHANNEL = vscode.window.createOutputChannel("Rust Analyzer Language Server");
-    }
-    return OUTPUT_CHANNEL;
+export interface RustAnalyzerExtensionApi {
+    // FIXME: this should be non-optional
+    readonly client?: lc.LanguageClient;
 }
 
-export interface RustAnalyzerExtensionApi {
-    client?: lc.LanguageClient;
+export async function deactivate() {
+    await setContextValue(RUST_PROJECT_CONTEXT_NAME, undefined);
 }
 
 export async function activate(
     context: vscode.ExtensionContext
 ): Promise<RustAnalyzerExtensionApi> {
-    // VS Code doesn't show a notification when an extension fails to activate
-    // so we do it ourselves.
-    return await tryActivate(context).catch((err) => {
-        void vscode.window.showErrorMessage(`Cannot activate rust-analyzer: ${err.message}`);
-        throw err;
-    });
-}
+    if (vscode.extensions.getExtension("rust-lang.rust")) {
+        vscode.window
+            .showWarningMessage(
+                `You have both the rust-analyzer (rust-lang.rust-analyzer) and Rust (rust-lang.rust) ` +
+                    "plugins enabled. These are known to conflict and cause various functions of " +
+                    "both plugins to not work correctly. You should disable one of them.",
+                "Got it"
+            )
+            .then(() => {}, console.error);
+    }
 
-async function tryActivate(context: vscode.ExtensionContext): Promise<RustAnalyzerExtensionApi> {
     // We only support local folders, not eg. Live Share (`vlsl:` scheme), so don't activate if
     // only those are in use.
     // (r-a still somewhat works with Live Share, because commands are tunneled to the host)
@@ -65,351 +49,118 @@ async function tryActivate(context: vscode.ExtensionContext): Promise<RustAnalyz
         return {};
     }
 
-    const config = new Config(context);
-    const state = new PersistentState(context.globalState);
-    const serverPath = await bootstrap(context, config, state).catch((err) => {
-        let message = "bootstrap error. ";
-
-        message += 'See the logs in "OUTPUT > Rust Analyzer Client" (should open automatically). ';
-        message += 'To enable verbose logs use { "rust-analyzer.trace.extension": true }';
+    const workspace: Workspace =
+        folders.length === 0
+            ? {
+                  kind: "Detached Files",
+                  files: rustDocuments,
+              }
+            : { kind: "Workspace Folder" };
 
-        log.error("Bootstrap error", err);
-        throw new Error(message);
+    const ctx = new Ctx(context, workspace, createCommands());
+    // VS Code doesn't show a notification when an extension fails to activate
+    // so we do it ourselves.
+    const api = await activateServer(ctx).catch((err) => {
+        void vscode.window.showErrorMessage(
+            `Cannot activate rust-analyzer extension: ${err.message}`
+        );
+        throw err;
     });
+    await setContextValue(RUST_PROJECT_CONTEXT_NAME, true);
+    return api;
+}
 
-    if (folders.length === 0) {
-        ctx = await Ctx.create(config, context, serverPath, {
-            kind: "Detached Files",
-            files: rustDocuments,
-        });
-    } else {
-        // Note: we try to start the server before we activate type hints so that it
-        // registers its `onDidChangeDocument` handler before us.
-        //
-        // This a horribly, horribly wrong way to deal with this problem.
-        ctx = await Ctx.create(config, context, serverPath, { kind: "Workspace Folder" });
-        ctx.pushCleanup(activateTaskProvider(ctx.config));
-    }
-    await initCommonContext(context, ctx);
-
-    warnAboutExtensionConflicts();
-
-    if (config.typingContinueCommentsOnNewline) {
-        ctx.pushCleanup(configureLanguage());
+async function activateServer(ctx: Ctx): Promise<RustAnalyzerExtensionApi> {
+    if (ctx.workspace.kind === "Workspace Folder") {
+        ctx.pushExtCleanup(activateTaskProvider(ctx.config));
     }
 
     vscode.workspace.onDidChangeConfiguration(
-        (_) =>
-            ctx?.client
-                ?.sendNotification("workspace/didChangeConfiguration", { settings: "" })
-                .catch(log.error),
+        async (_) => {
+            await ctx
+                .clientFetcher()
+                .client?.sendNotification("workspace/didChangeConfiguration", { settings: "" });
+        },
         null,
         ctx.subscriptions
     );
 
-    return {
-        client: ctx.client,
-    };
-}
-
-async function initCommonContext(context: vscode.ExtensionContext, ctx: Ctx) {
-    // Register a "dumb" onEnter command for the case where server fails to
-    // start.
-    //
-    // FIXME: refactor command registration code such that commands are
-    // **always** registered, even if the server does not start. Use API like
-    // this perhaps?
-    //
-    // ```TypeScript
-    // registerCommand(
-    //    factory: (Ctx) => ((Ctx) => any),
-    //    fallback: () => any = () => vscode.window.showErrorMessage(
-    //        "rust-analyzer is not available"
-    //    ),
-    // )
-    const defaultOnEnter = vscode.commands.registerCommand("rust-analyzer.onEnter", () =>
-        vscode.commands.executeCommand("default:type", { text: "\n" })
-    );
-    context.subscriptions.push(defaultOnEnter);
-
-    await setContextValue(RUST_PROJECT_CONTEXT_NAME, true);
-
-    // Commands which invokes manually via command palette, shortcut, etc.
-
-    // Reloading is inspired by @DanTup maneuver: https://github.com/microsoft/vscode/issues/45774#issuecomment-373423895
-    ctx.registerCommand("reload", (_) => async () => {
-        void vscode.window.showInformationMessage("Reloading rust-analyzer...");
-        await doDeactivate();
-        while (context.subscriptions.length > 0) {
-            try {
-                context.subscriptions.pop()!.dispose();
-            } catch (err) {
-                log.error("Dispose error:", err);
-            }
-        }
-        await activate(context).catch(log.error);
-    });
-
-    ctx.registerCommand("analyzerStatus", commands.analyzerStatus);
-    ctx.registerCommand("memoryUsage", commands.memoryUsage);
-    ctx.registerCommand("shuffleCrateGraph", commands.shuffleCrateGraph);
-    ctx.registerCommand("reloadWorkspace", commands.reloadWorkspace);
-    ctx.registerCommand("matchingBrace", commands.matchingBrace);
-    ctx.registerCommand("joinLines", commands.joinLines);
-    ctx.registerCommand("parentModule", commands.parentModule);
-    ctx.registerCommand("syntaxTree", commands.syntaxTree);
-    ctx.registerCommand("viewHir", commands.viewHir);
-    ctx.registerCommand("viewFileText", commands.viewFileText);
-    ctx.registerCommand("viewItemTree", commands.viewItemTree);
-    ctx.registerCommand("viewCrateGraph", commands.viewCrateGraph);
-    ctx.registerCommand("viewFullCrateGraph", commands.viewFullCrateGraph);
-    ctx.registerCommand("expandMacro", commands.expandMacro);
-    ctx.registerCommand("run", commands.run);
-    ctx.registerCommand("copyRunCommandLine", commands.copyRunCommandLine);
-    ctx.registerCommand("debug", commands.debug);
-    ctx.registerCommand("newDebugConfig", commands.newDebugConfig);
-    ctx.registerCommand("openDocs", commands.openDocs);
-    ctx.registerCommand("openCargoToml", commands.openCargoToml);
-    ctx.registerCommand("peekTests", commands.peekTests);
-    ctx.registerCommand("moveItemUp", commands.moveItemUp);
-    ctx.registerCommand("moveItemDown", commands.moveItemDown);
-    ctx.registerCommand("cancelFlycheck", commands.cancelFlycheck);
-
-    defaultOnEnter.dispose();
-    ctx.registerCommand("onEnter", commands.onEnter);
-
-    ctx.registerCommand("ssr", commands.ssr);
-    ctx.registerCommand("serverVersion", commands.serverVersion);
-
-    // Internal commands which are invoked by the server.
-    ctx.registerCommand("runSingle", commands.runSingle);
-    ctx.registerCommand("debugSingle", commands.debugSingle);
-    ctx.registerCommand("showReferences", commands.showReferences);
-    ctx.registerCommand("applySnippetWorkspaceEdit", commands.applySnippetWorkspaceEditCommand);
-    ctx.registerCommand("resolveCodeAction", commands.resolveCodeAction);
-    ctx.registerCommand("applyActionGroup", commands.applyActionGroup);
-    ctx.registerCommand("gotoLocation", commands.gotoLocation);
-
-    ctx.registerCommand("linkToCommand", commands.linkToCommand);
-}
-
-export async function deactivate() {
-    TRACE_OUTPUT_CHANNEL?.dispose();
-    TRACE_OUTPUT_CHANNEL = null;
-    OUTPUT_CHANNEL?.dispose();
-    OUTPUT_CHANNEL = null;
-    await doDeactivate();
-}
-
-async function doDeactivate() {
-    await setContextValue(RUST_PROJECT_CONTEXT_NAME, undefined);
-    await ctx?.client.stop();
-    ctx = undefined;
-}
-
-async function bootstrap(
-    context: vscode.ExtensionContext,
-    config: Config,
-    state: PersistentState
-): Promise<string> {
-    const path = await getServer(context, config, state);
-    if (!path) {
-        throw new Error(
-            "Rust Analyzer Language Server is not available. " +
-                "Please, ensure its [proper installation](https://rust-analyzer.github.io/manual.html#installation)."
-        );
-    }
-
-    log.info("Using server binary at", path);
-
-    if (!isValidExecutable(path)) {
-        if (config.serverPath) {
-            throw new Error(`Failed to execute ${path} --version. \`config.server.path\` or \`config.serverPath\` has been set explicitly.\
-            Consider removing this config or making a valid server binary available at that path.`);
-        } else {
-            throw new Error(`Failed to execute ${path} --version`);
-        }
-    }
-
-    return path;
+    await ctx.activate();
+    return ctx.clientFetcher();
 }
 
-async function patchelf(dest: vscode.Uri): Promise<void> {
-    await vscode.window.withProgress(
-        {
-            location: vscode.ProgressLocation.Notification,
-            title: "Patching rust-analyzer for NixOS",
+function createCommands(): Record<string, CommandFactory> {
+    return {
+        onEnter: {
+            enabled: commands.onEnter,
+            disabled: (_) => () => vscode.commands.executeCommand("default:type", { text: "\n" }),
         },
-        async (progress, _) => {
-            const expression = `
-            {srcStr, pkgs ? import <nixpkgs> {}}:
-                pkgs.stdenv.mkDerivation {
-                    name = "rust-analyzer";
-                    src = /. + srcStr;
-                    phases = [ "installPhase" "fixupPhase" ];
-                    installPhase = "cp $src $out";
-                    fixupPhase = ''
-                    chmod 755 $out
-                    patchelf --set-interpreter "$(cat $NIX_CC/nix-support/dynamic-linker)" $out
-                    '';
-                }
-            `;
-            const origFile = vscode.Uri.file(dest.fsPath + "-orig");
-            await vscode.workspace.fs.rename(dest, origFile, { overwrite: true });
-            try {
-                progress.report({ message: "Patching executable", increment: 20 });
-                await new Promise((resolve, reject) => {
-                    const handle = exec(
-                        `nix-build -E - --argstr srcStr '${origFile.fsPath}' -o '${dest.fsPath}'`,
-                        (err, stdout, stderr) => {
-                            if (err != null) {
-                                reject(Error(stderr));
-                            } else {
-                                resolve(stdout);
-                            }
-                        }
-                    );
-                    handle.stdin?.write(expression);
-                    handle.stdin?.end();
-                });
-            } finally {
-                await vscode.workspace.fs.delete(origFile);
-            }
-        }
-    );
-}
-
-async function getServer(
-    context: vscode.ExtensionContext,
-    config: Config,
-    state: PersistentState
-): Promise<string | undefined> {
-    const explicitPath = serverPath(config);
-    if (explicitPath) {
-        if (explicitPath.startsWith("~/")) {
-            return os.homedir() + explicitPath.slice("~".length);
-        }
-        return explicitPath;
-    }
-    if (config.package.releaseTag === null) return "rust-analyzer";
-
-    const ext = process.platform === "win32" ? ".exe" : "";
-    const bundled = vscode.Uri.joinPath(context.extensionUri, "server", `rust-analyzer${ext}`);
-    const bundledExists = await vscode.workspace.fs.stat(bundled).then(
-        () => true,
-        () => false
-    );
-    if (bundledExists) {
-        let server = bundled;
-        if (await isNixOs()) {
-            await vscode.workspace.fs.createDirectory(config.globalStorageUri).then();
-            const dest = vscode.Uri.joinPath(config.globalStorageUri, `rust-analyzer${ext}`);
-            let exists = await vscode.workspace.fs.stat(dest).then(
-                () => true,
-                () => false
-            );
-            if (exists && config.package.version !== state.serverVersion) {
-                await vscode.workspace.fs.delete(dest);
-                exists = false;
-            }
-            if (!exists) {
-                await vscode.workspace.fs.copy(bundled, dest);
-                await patchelf(dest);
-            }
-            server = dest;
-        }
-        await state.updateServerVersion(config.package.version);
-        return server.fsPath;
-    }
-
-    await state.updateServerVersion(undefined);
-    await vscode.window.showErrorMessage(
-        "Unfortunately we don't ship binaries for your platform yet. " +
-            "You need to manually clone the rust-analyzer repository and " +
-            "run `cargo xtask install --server` to build the language server from sources. " +
-            "If you feel that your platform should be supported, please create an issue " +
-            "about that [here](https://github.com/rust-lang/rust-analyzer/issues) and we " +
-            "will consider it."
-    );
-    return undefined;
-}
-
-function serverPath(config: Config): string | null {
-    return process.env.__RA_LSP_SERVER_DEBUG ?? config.serverPath;
-}
-
-async function isNixOs(): Promise<boolean> {
-    try {
-        const contents = (
-            await vscode.workspace.fs.readFile(vscode.Uri.file("/etc/os-release"))
-        ).toString();
-        const idString = contents.split("\n").find((a) => a.startsWith("ID=")) || "ID=linux";
-        return idString.indexOf("nixos") !== -1;
-    } catch {
-        return false;
-    }
-}
-
-function warnAboutExtensionConflicts() {
-    if (vscode.extensions.getExtension("rust-lang.rust")) {
-        vscode.window
-            .showWarningMessage(
-                `You have both the rust-analyzer (rust-lang.rust-analyzer) and Rust (rust-lang.rust) ` +
-                    "plugins enabled. These are known to conflict and cause various functions of " +
-                    "both plugins to not work correctly. You should disable one of them.",
-                "Got it"
-            )
-            .then(() => {}, console.error);
-    }
-}
-
-/**
- * Sets up additional language configuration that's impossible to do via a
- * separate language-configuration.json file. See [1] for more information.
- *
- * [1]: https://github.com/Microsoft/vscode/issues/11514#issuecomment-244707076
- */
-function configureLanguage(): vscode.Disposable {
-    const indentAction = vscode.IndentAction.None;
-    return vscode.languages.setLanguageConfiguration("rust", {
-        onEnterRules: [
-            {
-                // Doc single-line comment
-                // e.g. ///|
-                beforeText: /^\s*\/{3}.*$/,
-                action: { indentAction, appendText: "/// " },
-            },
-            {
-                // Parent doc single-line comment
-                // e.g. //!|
-                beforeText: /^\s*\/{2}\!.*$/,
-                action: { indentAction, appendText: "//! " },
+        reload: {
+            enabled: (ctx) => async () => {
+                void vscode.window.showInformationMessage("Reloading rust-analyzer...");
+                // FIXME: We should re-use the client, that is ctx.deactivate() if none of the configs have changed
+                await ctx.stop();
+                await ctx.activate();
             },
-            {
-                // Begins an auto-closed multi-line comment (standard or parent doc)
-                // e.g. /** | */ or /*! | */
-                beforeText: /^\s*\/\*(\*|\!)(?!\/)([^\*]|\*(?!\/))*$/,
-                afterText: /^\s*\*\/$/,
-                action: { indentAction: vscode.IndentAction.IndentOutdent, appendText: " * " },
+            disabled: (ctx) => async () => {
+                void vscode.window.showInformationMessage("Reloading rust-analyzer...");
+                await ctx.activate();
             },
-            {
-                // Begins a multi-line comment (standard or parent doc)
-                // e.g. /** ...| or /*! ...|
-                beforeText: /^\s*\/\*(\*|\!)(?!\/)([^\*]|\*(?!\/))*$/,
-                action: { indentAction, appendText: " * " },
+        },
+        startServer: {
+            enabled: (ctx) => async () => {
+                await ctx.activate();
             },
-            {
-                // Continues a multi-line comment
-                // e.g.  * ...|
-                beforeText: /^(\ \ )*\ \*(\ ([^\*]|\*(?!\/))*)?$/,
-                action: { indentAction, appendText: "* " },
+            disabled: (ctx) => async () => {
+                await ctx.activate();
             },
-            {
-                // Dedents after closing a multi-line comment
-                // e.g.  */|
-                beforeText: /^(\ \ )*\ \*\/\s*$/,
-                action: { indentAction, removeText: 1 },
+        },
+        stopServer: {
+            enabled: (ctx) => async () => {
+                // FIXME: We should re-use the client, that is ctx.deactivate() if none of the configs have changed
+                await ctx.stop();
+                ctx.setServerStatus({
+                    health: "ok",
+                    quiescent: true,
+                    message: "server is not running",
+                });
             },
-        ],
-    });
+        },
+
+        analyzerStatus: { enabled: commands.analyzerStatus },
+        memoryUsage: { enabled: commands.memoryUsage },
+        shuffleCrateGraph: { enabled: commands.shuffleCrateGraph },
+        reloadWorkspace: { enabled: commands.reloadWorkspace },
+        matchingBrace: { enabled: commands.matchingBrace },
+        joinLines: { enabled: commands.joinLines },
+        parentModule: { enabled: commands.parentModule },
+        syntaxTree: { enabled: commands.syntaxTree },
+        viewHir: { enabled: commands.viewHir },
+        viewFileText: { enabled: commands.viewFileText },
+        viewItemTree: { enabled: commands.viewItemTree },
+        viewCrateGraph: { enabled: commands.viewCrateGraph },
+        viewFullCrateGraph: { enabled: commands.viewFullCrateGraph },
+        expandMacro: { enabled: commands.expandMacro },
+        run: { enabled: commands.run },
+        copyRunCommandLine: { enabled: commands.copyRunCommandLine },
+        debug: { enabled: commands.debug },
+        newDebugConfig: { enabled: commands.newDebugConfig },
+        openDocs: { enabled: commands.openDocs },
+        openCargoToml: { enabled: commands.openCargoToml },
+        peekTests: { enabled: commands.peekTests },
+        moveItemUp: { enabled: commands.moveItemUp },
+        moveItemDown: { enabled: commands.moveItemDown },
+        cancelFlycheck: { enabled: commands.cancelFlycheck },
+        ssr: { enabled: commands.ssr },
+        serverVersion: { enabled: commands.serverVersion },
+        // Internal commands which are invoked by the server.
+        applyActionGroup: { enabled: commands.applyActionGroup },
+        applySnippetWorkspaceEdit: { enabled: commands.applySnippetWorkspaceEditCommand },
+        debugSingle: { enabled: commands.debugSingle },
+        gotoLocation: { enabled: commands.gotoLocation },
+        linkToCommand: { enabled: commands.linkToCommand },
+        resolveCodeAction: { enabled: commands.resolveCodeAction },
+        runSingle: { enabled: commands.runSingle },
+        showReferences: { enabled: commands.showReferences },
+    };
 }
diff --git a/src/tools/rust-analyzer/editors/code/src/run.ts b/src/tools/rust-analyzer/editors/code/src/run.ts
index 22e5eda6827..dadaa41b1d1 100644
--- a/src/tools/rust-analyzer/editors/code/src/run.ts
+++ b/src/tools/rust-analyzer/editors/code/src/run.ts
@@ -18,9 +18,9 @@ export async function selectRunnable(
     showButtons: boolean = true
 ): Promise<RunnableQuickPick | undefined> {
     const editor = ctx.activeRustEditor;
-    const client = ctx.client;
-    if (!editor || !client) return;
+    if (!editor) return;
 
+    const client = await ctx.getClient();
     const textDocument: lc.TextDocumentIdentifier = {
         uri: editor.document.uri.toString(),
     };
diff --git a/src/version b/src/version
index b6148bc0a75..65ee0959841 100644
--- a/src/version
+++ b/src/version
@@ -1 +1 @@
-1.66.0
+1.67.0