about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--compiler/rustc_ast/src/ast.rs3
-rw-r--r--compiler/rustc_ast_lowering/src/asm.rs11
-rw-r--r--compiler/rustc_ast_lowering/src/expr.rs24
-rw-r--r--compiler/rustc_ast_lowering/src/lib.rs2
-rw-r--r--compiler/rustc_ast_lowering/src/path.rs22
-rw-r--r--compiler/rustc_ast_pretty/src/pprust/state.rs3
-rw-r--r--compiler/rustc_borrowck/src/dataflow.rs6
-rw-r--r--compiler/rustc_borrowck/src/def_use.rs3
-rw-r--r--compiler/rustc_borrowck/src/invalidation.rs1
-rw-r--r--compiler/rustc_borrowck/src/lib.rs1
-rw-r--r--compiler/rustc_borrowck/src/type_check/input_output.rs26
-rw-r--r--compiler/rustc_borrowck/src/type_check/mod.rs10
-rw-r--r--compiler/rustc_builtin_macros/src/asm.rs2
-rw-r--r--compiler/rustc_builtin_macros/src/deriving/generic/mod.rs154
-rw-r--r--compiler/rustc_builtin_macros/src/deriving/generic/ty.rs16
-rw-r--r--compiler/rustc_codegen_cranelift/src/base.rs22
-rw-r--r--compiler/rustc_codegen_gcc/src/asm.rs9
-rw-r--r--compiler/rustc_codegen_llvm/src/asm.rs29
-rw-r--r--compiler/rustc_codegen_llvm/src/intrinsic.rs2
-rw-r--r--compiler/rustc_codegen_llvm/src/llvm/ffi.rs1
-rw-r--r--compiler/rustc_codegen_ssa/src/mir/analyze.rs5
-rw-r--r--compiler/rustc_codegen_ssa/src/mir/block.rs61
-rw-r--r--compiler/rustc_codegen_ssa/src/traits/asm.rs1
-rw-r--r--compiler/rustc_const_eval/src/const_eval/eval_queries.rs3
-rw-r--r--compiler/rustc_const_eval/src/interpret/eval_context.rs1
-rw-r--r--compiler/rustc_const_eval/src/transform/check_consts/check.rs3
-rw-r--r--compiler/rustc_const_eval/src/transform/check_consts/qualifs.rs3
-rw-r--r--compiler/rustc_const_eval/src/transform/check_consts/resolver.rs31
-rw-r--r--compiler/rustc_const_eval/src/transform/promote_consts.rs4
-rw-r--r--compiler/rustc_const_eval/src/transform/validate.rs5
-rw-r--r--compiler/rustc_data_structures/src/functor.rs6
-rw-r--r--compiler/rustc_expand/src/mbe/macro_rules.rs18
-rw-r--r--compiler/rustc_feature/src/active.rs2
-rw-r--r--compiler/rustc_hir/src/hir.rs48
-rw-r--r--compiler/rustc_hir/src/lang_items.rs1
-rw-r--r--compiler/rustc_hir_pretty/src/lib.rs3
-rw-r--r--compiler/rustc_infer/src/infer/error_reporting/need_type_info.rs92
-rw-r--r--compiler/rustc_infer/src/infer/mod.rs23
-rw-r--r--compiler/rustc_infer/src/traits/engine.rs20
-rw-r--r--compiler/rustc_infer/src/traits/mod.rs10
-rw-r--r--compiler/rustc_infer/src/traits/util.rs10
-rw-r--r--compiler/rustc_lexer/src/cursor.rs33
-rw-r--r--compiler/rustc_lexer/src/lib.rs20
-rw-r--r--compiler/rustc_lint/src/array_into_iter.rs5
-rw-r--r--compiler/rustc_lint/src/builtin.rs64
-rw-r--r--compiler/rustc_lint/src/levels.rs15
-rw-r--r--compiler/rustc_lint/src/noop_method_call.rs10
-rw-r--r--compiler/rustc_lint/src/traits.rs20
-rw-r--r--compiler/rustc_lint/src/types.rs7
-rw-r--r--compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp13
-rw-r--r--compiler/rustc_middle/src/hir/map/mod.rs3
-rw-r--r--compiler/rustc_middle/src/lib.rs1
-rw-r--r--compiler/rustc_middle/src/mir/interpret/queries.rs2
-rw-r--r--compiler/rustc_middle/src/mir/mod.rs15
-rw-r--r--compiler/rustc_middle/src/mir/terminator.rs44
-rw-r--r--compiler/rustc_middle/src/mir/type_foldable.rs17
-rw-r--r--compiler/rustc_middle/src/mir/visit.rs12
-rw-r--r--compiler/rustc_middle/src/traits/select.rs10
-rw-r--r--compiler/rustc_middle/src/traits/util.rs4
-rw-r--r--compiler/rustc_middle/src/ty/adt.rs24
-rw-r--r--compiler/rustc_middle/src/ty/diagnostics.rs4
-rw-r--r--compiler/rustc_middle/src/ty/layout.rs2
-rw-r--r--compiler/rustc_middle/src/ty/mod.rs132
-rw-r--r--compiler/rustc_middle/src/ty/relate.rs13
-rw-r--r--compiler/rustc_middle/src/ty/structural_impls.rs2
-rw-r--r--compiler/rustc_middle/src/ty/sty.rs4
-rw-r--r--compiler/rustc_middle/src/ty/util.rs8
-rw-r--r--compiler/rustc_mir_build/src/build/expr/into.rs4
-rw-r--r--compiler/rustc_mir_build/src/build/scope.rs7
-rw-r--r--compiler/rustc_mir_dataflow/src/framework/direction.rs59
-rw-r--r--compiler/rustc_mir_dataflow/src/framework/graphviz.rs40
-rw-r--r--compiler/rustc_mir_dataflow/src/framework/mod.rs38
-rw-r--r--compiler/rustc_mir_dataflow/src/framework/tests.rs4
-rw-r--r--compiler/rustc_mir_dataflow/src/impls/borrowed_locals.rs6
-rw-r--r--compiler/rustc_mir_dataflow/src/impls/init_locals.rs14
-rw-r--r--compiler/rustc_mir_dataflow/src/impls/liveness.rs22
-rw-r--r--compiler/rustc_mir_dataflow/src/impls/mod.rs90
-rw-r--r--compiler/rustc_mir_dataflow/src/impls/storage_liveness.rs20
-rw-r--r--compiler/rustc_mir_dataflow/src/lib.rs6
-rw-r--r--compiler/rustc_mir_dataflow/src/move_paths/builder.rs1
-rw-r--r--compiler/rustc_mir_dataflow/src/rustc_peek.rs1
-rw-r--r--compiler/rustc_mir_transform/src/add_retag.rs8
-rw-r--r--compiler/rustc_mir_transform/src/check_const_item_mutation.rs6
-rw-r--r--compiler/rustc_mir_transform/src/check_packed_ref.rs6
-rw-r--r--compiler/rustc_mir_transform/src/check_unsafety.rs1
-rw-r--r--compiler/rustc_mir_transform/src/const_debuginfo.rs8
-rw-r--r--compiler/rustc_mir_transform/src/const_goto.rs7
-rw-r--r--compiler/rustc_mir_transform/src/const_prop.rs10
-rw-r--r--compiler/rustc_mir_transform/src/coverage/mod.rs4
-rw-r--r--compiler/rustc_mir_transform/src/deduplicate_blocks.rs7
-rw-r--r--compiler/rustc_mir_transform/src/dest_prop.rs16
-rw-r--r--compiler/rustc_mir_transform/src/early_otherwise_branch.rs12
-rw-r--r--compiler/rustc_mir_transform/src/elaborate_drops.rs4
-rw-r--r--compiler/rustc_mir_transform/src/function_item_references.rs6
-rw-r--r--compiler/rustc_mir_transform/src/generator.rs4
-rw-r--r--compiler/rustc_mir_transform/src/inline.rs32
-rw-r--r--compiler/rustc_mir_transform/src/instcombine.rs4
-rw-r--r--compiler/rustc_mir_transform/src/lib.rs261
-rw-r--r--compiler/rustc_mir_transform/src/lower_slice_len.rs4
-rw-r--r--compiler/rustc_mir_transform/src/marker.rs20
-rw-r--r--compiler/rustc_mir_transform/src/match_branches.rs8
-rw-r--r--compiler/rustc_mir_transform/src/multiple_return_terminators.rs8
-rw-r--r--compiler/rustc_mir_transform/src/normalize_array_len.rs8
-rw-r--r--compiler/rustc_mir_transform/src/nrvo.rs8
-rw-r--r--compiler/rustc_mir_transform/src/pass_manager.rs144
-rw-r--r--compiler/rustc_mir_transform/src/remove_noop_landing_pads.rs16
-rw-r--r--compiler/rustc_mir_transform/src/remove_storage_markers.rs4
-rw-r--r--compiler/rustc_mir_transform/src/remove_zsts.rs4
-rw-r--r--compiler/rustc_mir_transform/src/reveal_all.rs15
-rw-r--r--compiler/rustc_mir_transform/src/separate_const_switch.rs8
-rw-r--r--compiler/rustc_mir_transform/src/shim.rs20
-rw-r--r--compiler/rustc_mir_transform/src/simplify.rs4
-rw-r--r--compiler/rustc_mir_transform/src/simplify_comparison_integral.rs4
-rw-r--r--compiler/rustc_mir_transform/src/uninhabited_enum_branching.rs4
-rw-r--r--compiler/rustc_mir_transform/src/unreachable_prop.rs12
-rw-r--r--compiler/rustc_parse/src/parser/generics.rs13
-rw-r--r--compiler/rustc_passes/src/check_attr.rs36
-rw-r--r--compiler/rustc_query_system/src/lib.rs1
-rw-r--r--compiler/rustc_resolve/src/late/diagnostics.rs20
-rw-r--r--compiler/rustc_session/src/options.rs23
-rw-r--r--compiler/rustc_session/src/session.rs14
-rw-r--r--compiler/rustc_span/src/lib.rs11
-rw-r--r--compiler/rustc_span/src/symbol.rs4
-rw-r--r--compiler/rustc_trait_selection/src/autoderef.rs2
-rw-r--r--compiler/rustc_trait_selection/src/infer.rs1
-rw-r--r--compiler/rustc_trait_selection/src/traits/auto_trait.rs7
-rw-r--r--compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs2
-rw-r--r--compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs8
-rw-r--r--compiler/rustc_trait_selection/src/traits/fulfill.rs39
-rw-r--r--compiler/rustc_trait_selection/src/traits/mod.rs36
-rw-r--r--compiler/rustc_trait_selection/src/traits/object_safety.rs8
-rw-r--r--compiler/rustc_trait_selection/src/traits/project.rs2
-rw-r--r--compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs14
-rw-r--r--compiler/rustc_trait_selection/src/traits/select/confirmation.rs16
-rw-r--r--compiler/rustc_trait_selection/src/traits/select/mod.rs236
-rw-r--r--compiler/rustc_trait_selection/src/traits/specialize/mod.rs6
-rw-r--r--compiler/rustc_trait_selection/src/traits/util.rs10
-rw-r--r--compiler/rustc_trait_selection/src/traits/wf.rs7
-rw-r--r--compiler/rustc_ty_utils/src/needs_drop.rs6
-rw-r--r--compiler/rustc_ty_utils/src/ty.rs85
-rw-r--r--compiler/rustc_typeck/src/astconv/mod.rs2
-rw-r--r--compiler/rustc_typeck/src/bounds.rs2
-rw-r--r--compiler/rustc_typeck/src/check/compare_method.rs31
-rw-r--r--compiler/rustc_typeck/src/check/demand.rs2
-rw-r--r--compiler/rustc_typeck/src/check/fn_ctxt/_impl.rs10
-rw-r--r--compiler/rustc_typeck/src/check/inherited.rs14
-rw-r--r--compiler/rustc_typeck/src/check/method/mod.rs2
-rw-r--r--compiler/rustc_typeck/src/check/method/probe.rs2
-rw-r--r--compiler/rustc_typeck/src/check/method/suggest.rs2
-rw-r--r--compiler/rustc_typeck/src/check/wfcheck.rs1
-rw-r--r--compiler/rustc_typeck/src/collect.rs10
-rw-r--r--library/alloc/src/boxed.rs173
-rw-r--r--library/alloc/src/collections/vec_deque/mod.rs57
-rw-r--r--library/core/src/any.rs174
-rw-r--r--library/core/src/array/mod.rs116
-rw-r--r--library/core/src/future/future.rs6
-rw-r--r--library/core/src/future/into_future.rs1
-rw-r--r--library/core/src/iter/traits/iterator.rs124
-rw-r--r--library/core/src/ops/control_flow.rs5
-rw-r--r--library/core/src/ops/mod.rs5
-rw-r--r--library/core/src/ops/try_trait.rs58
-rw-r--r--library/core/src/option.rs10
-rw-r--r--library/core/src/result.rs5
-rw-r--r--library/core/tests/array.rs2
-rw-r--r--library/core/tests/iter/traits/iterator.rs28
-rw-r--r--library/core/tests/lib.rs1
-rw-r--r--library/std/src/lib.rs5
-rw-r--r--library/std/src/sys/unix/os.rs6
-rw-r--r--library/std/src/thread/local.rs15
-rw-r--r--library/std/src/thread/mod.rs7
-rw-r--r--library/unwind/build.rs3
-rw-r--r--src/doc/unstable-book/src/library-features/asm.md3
-rw-r--r--src/etc/htmldocck.py80
-rw-r--r--src/librustdoc/clean/auto_trait.rs19
-rw-r--r--src/librustdoc/clean/blanket_impl.rs11
-rw-r--r--src/librustdoc/clean/inline.rs23
-rw-r--r--src/librustdoc/clean/mod.rs794
-rw-r--r--src/librustdoc/html/templates/page.html6
m---------src/llvm-project0
-rw-r--r--src/test/codegen/asm-may_unwind.rs25
-rw-r--r--src/test/codegen/auxiliary/thread_local_aux.rs1
-rw-r--r--src/test/codegen/thread-local.rs1
-rw-r--r--src/test/mir-opt/early_otherwise_branch_noopt.rs2
-rw-r--r--src/test/rustdoc/mixing-doc-comments-and-attrs.S1_top-doc.html4
-rw-r--r--src/test/rustdoc/mixing-doc-comments-and-attrs.S2_top-doc.html4
-rw-r--r--src/test/rustdoc/mixing-doc-comments-and-attrs.rs12
-rw-r--r--src/test/ui/asm/aarch64/bad-options.stderr24
-rw-r--r--src/test/ui/asm/aarch64/may_unwind.rs37
-rw-r--r--src/test/ui/asm/aarch64/parse-error.stderr20
-rw-r--r--src/test/ui/asm/may_unwind.rs9
-rw-r--r--src/test/ui/asm/x86_64/bad-options.stderr24
-rw-r--r--src/test/ui/asm/x86_64/may_unwind.rs37
-rw-r--r--src/test/ui/asm/x86_64/parse-error.stderr20
-rw-r--r--src/test/ui/async-await/async-error-span.stderr1
-rw-r--r--src/test/ui/async-await/async-fn-size-moved-locals.rs6
-rw-r--r--src/test/ui/async-await/await-into-future.rs30
-rw-r--r--src/test/ui/async-await/issue-70594.stderr2
-rw-r--r--src/test/ui/async-await/issues/issue-62009-1.stderr2
-rw-r--r--src/test/ui/async-await/unresolved_type_param.rs8
-rw-r--r--src/test/ui/async-await/unresolved_type_param.stderr26
-rw-r--r--src/test/ui/const-generics/generic_const_exprs/const_eval_resolve_canonical.rs8
-rw-r--r--src/test/ui/const-generics/generic_const_exprs/const_eval_resolve_canonical.stderr33
-rw-r--r--src/test/ui/const-generics/issues/issue-83249.rs23
-rw-r--r--src/test/ui/const-generics/issues/issue-83249.stderr11
-rw-r--r--src/test/ui/const-generics/issues/issue-83288.rs69
-rw-r--r--src/test/ui/const-generics/issues/issue-87470.rs24
-rw-r--r--src/test/ui/const-generics/issues/issue-87964.rs29
-rw-r--r--src/test/ui/const-generics/issues/issue-89146.rs26
-rw-r--r--src/test/ui/const-generics/issues/issue-89320.rs19
-rw-r--r--src/test/ui/derives/issue-36617.rs13
-rw-r--r--src/test/ui/derives/issue-36617.stderr89
-rw-r--r--src/test/ui/feature-gates/feature-gate-asm_unwind.rs10
-rw-r--r--src/test/ui/feature-gates/feature-gate-asm_unwind.stderr12
-rw-r--r--src/test/ui/feature-gates/issue-43106-gating-of-bench.rs2
-rw-r--r--src/test/ui/feature-gates/issue-43106-gating-of-bench.stderr13
-rw-r--r--src/test/ui/feature-gates/issue-43106-gating-of-builtin-attrs-error.stderr30
-rw-r--r--src/test/ui/feature-gates/issue-43106-gating-of-test.rs2
-rw-r--r--src/test/ui/feature-gates/issue-43106-gating-of-test.stderr13
-rw-r--r--src/test/ui/feature-gates/thread-local-const-init.rs4
-rw-r--r--src/test/ui/feature-gates/thread-local-const-init.stderr13
-rw-r--r--src/test/ui/generator/issue-91477.rs7
-rw-r--r--src/test/ui/generator/issue-91477.stderr9
-rw-r--r--src/test/ui/imports/issue-28134.rs1
-rw-r--r--src/test/ui/imports/issue-28134.stderr13
-rw-r--r--src/test/ui/infinite/infinite-struct.stderr2
-rw-r--r--src/test/ui/infinite/infinite-tag-type-recursion.stderr2
-rw-r--r--src/test/ui/issues-71798.stderr1
-rw-r--r--src/test/ui/issues/issue-38821.stderr4
-rw-r--r--src/test/ui/issues/issue-50480.rs11
-rw-r--r--src/test/ui/issues/issue-50480.stderr89
-rw-r--r--src/test/ui/issues/issue-88150.rs21
-rw-r--r--src/test/ui/keyword/keyword-self-as-type-param.rs6
-rw-r--r--src/test/ui/keyword/keyword-self-as-type-param.stderr29
-rw-r--r--src/test/ui/lifetimes/undeclared-lifetime-used-in-debug-macro-issue-70152.stderr3
-rw-r--r--src/test/ui/macros/macro-pat-pattern-followed-by-or-in-2021.stderr12
-rw-r--r--src/test/ui/macros/macro-pat2021-pattern-followed-by-or.stderr12
-rw-r--r--src/test/ui/numeric/numeric-cast.stderr20
-rw-r--r--src/test/ui/rfc-2632-const-trait-impl/assoc-type.rs1
-rw-r--r--src/test/ui/rfc-2632-const-trait-impl/assoc-type.stderr4
-rw-r--r--src/test/ui/span/issue-43927-non-ADT-derive.rs1
-rw-r--r--src/test/ui/span/issue-43927-non-ADT-derive.stderr13
-rw-r--r--src/test/ui/suggestions/async-fn-ctor-passed-as-arg-where-it-should-have-been-called.stderr2
-rw-r--r--src/test/ui/suggestions/derive-macro-missing-bounds.rs89
-rw-r--r--src/test/ui/suggestions/derive-macro-missing-bounds.stderr107
-rw-r--r--src/test/ui/type/issue-91268.rs9
-rw-r--r--src/test/ui/type/issue-91268.stderr50
-rw-r--r--src/test/ui/union/issue-81199.rs21
-rw-r--r--src/test/ui/union/issue-81199.stderr29
-rw-r--r--src/tools/clippy/clippy_lints/src/future_not_send.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/redundant_clone.rs8
-rw-r--r--src/tools/compiletest/src/runtest.rs12
-rw-r--r--src/tools/rustfmt/.github/workflows/linux.yml5
-rw-r--r--src/tools/rustfmt/.github/workflows/mac.yml5
-rw-r--r--src/tools/rustfmt/.github/workflows/windows.yml5
-rw-r--r--src/tools/rustfmt/Configurations.md102
-rw-r--r--src/tools/rustfmt/README.md11
-rw-r--r--src/tools/rustfmt/config_proc_macro/src/lib.rs42
-rw-r--r--src/tools/rustfmt/src/comment.rs62
-rw-r--r--src/tools/rustfmt/src/config/mod.rs86
-rw-r--r--src/tools/rustfmt/src/expr.rs57
-rw-r--r--src/tools/rustfmt/src/ignore_path.rs24
-rw-r--r--src/tools/rustfmt/src/items.rs526
-rw-r--r--src/tools/rustfmt/src/lists.rs13
-rw-r--r--src/tools/rustfmt/src/macros.rs5
-rw-r--r--src/tools/rustfmt/src/syntux/session.rs15
-rw-r--r--src/tools/rustfmt/src/test/mod.rs13
-rw-r--r--src/tools/rustfmt/src/types.rs13
-rw-r--r--src/tools/rustfmt/src/visitor.rs4
-rw-r--r--src/tools/rustfmt/tests/source/comments-in-lists/wrap-comments-not-normalized.rs129
-rw-r--r--src/tools/rustfmt/tests/source/comments-in-lists/wrap-comments-true.rs130
-rw-r--r--src/tools/rustfmt/tests/source/issue-5088/deeply_nested_long_comment_wrap_comments_true.rs33
-rw-r--r--src/tools/rustfmt/tests/source/issue-5088/start_with_empty_comment_very_long_itemized_block_wrap_comments_true.rs19
-rw-r--r--src/tools/rustfmt/tests/source/issue-5088/very_long_comment_wrap_comments_true.rs13
-rw-r--r--src/tools/rustfmt/tests/source/issue_4823.rs5
-rw-r--r--src/tools/rustfmt/tests/source/issue_5027.rs7
-rw-r--r--src/tools/rustfmt/tests/source/issue_5086.rs2
-rw-r--r--src/tools/rustfmt/tests/target/comments-in-lists/format-doc-comments.rs96
-rw-r--r--src/tools/rustfmt/tests/target/comments-in-lists/wrap-comments-false.rs85
-rw-r--r--src/tools/rustfmt/tests/target/comments-in-lists/wrap-comments-not-normalized.rs142
-rw-r--r--src/tools/rustfmt/tests/target/comments-in-lists/wrap-comments-true.rs143
-rw-r--r--src/tools/rustfmt/tests/target/issue-5088/deeply_nested_long_comment_wrap_comments_false.rs33
-rw-r--r--src/tools/rustfmt/tests/target/issue-5088/deeply_nested_long_comment_wrap_comments_true.rs49
-rw-r--r--src/tools/rustfmt/tests/target/issue-5088/multi_line_itemized_block_wrap_comments_false.rs17
-rw-r--r--src/tools/rustfmt/tests/target/issue-5088/multi_line_itemized_block_wrap_comments_true.rs17
-rw-r--r--src/tools/rustfmt/tests/target/issue-5088/multi_line_text_with_itemized_block_wrap_comments_false.rs37
-rw-r--r--src/tools/rustfmt/tests/target/issue-5088/multi_line_text_with_itemized_block_wrap_comments_true.rs37
-rw-r--r--src/tools/rustfmt/tests/target/issue-5088/single_line_itemized_block_wrap_comments_false.rs9
-rw-r--r--src/tools/rustfmt/tests/target/issue-5088/single_line_itemized_block_wrap_comments_true.rs9
-rw-r--r--src/tools/rustfmt/tests/target/issue-5088/start_with_empty_comment_very_long_itemized_block_wrap_comments_false.rs19
-rw-r--r--src/tools/rustfmt/tests/target/issue-5088/start_with_empty_comment_very_long_itemized_block_wrap_comments_true.rs27
-rw-r--r--src/tools/rustfmt/tests/target/issue-5088/start_with_empty_comment_wrap_comments_false.rs17
-rw-r--r--src/tools/rustfmt/tests/target/issue-5088/start_with_empty_comment_wrap_comments_true.rs17
-rw-r--r--src/tools/rustfmt/tests/target/issue-5088/very_long_comment_wrap_comments_false.rs13
-rw-r--r--src/tools/rustfmt/tests/target/issue-5088/very_long_comment_wrap_comments_true.rs21
-rw-r--r--src/tools/rustfmt/tests/target/issue-5095.rs27
-rw-r--r--src/tools/rustfmt/tests/target/issue_4823.rs5
-rw-r--r--src/tools/rustfmt/tests/target/issue_5027.rs17
-rw-r--r--src/tools/rustfmt/tests/target/issue_5086.rs2
298 files changed, 5870 insertions, 2227 deletions
diff --git a/compiler/rustc_ast/src/ast.rs b/compiler/rustc_ast/src/ast.rs
index 4d4c6217ad0..03b957adeda 100644
--- a/compiler/rustc_ast/src/ast.rs
+++ b/compiler/rustc_ast/src/ast.rs
@@ -1981,7 +1981,7 @@ pub enum InlineAsmRegOrRegClass {
 
 bitflags::bitflags! {
     #[derive(Encodable, Decodable, HashStable_Generic)]
-    pub struct InlineAsmOptions: u8 {
+    pub struct InlineAsmOptions: u16 {
         const PURE = 1 << 0;
         const NOMEM = 1 << 1;
         const READONLY = 1 << 2;
@@ -1990,6 +1990,7 @@ bitflags::bitflags! {
         const NOSTACK = 1 << 5;
         const ATT_SYNTAX = 1 << 6;
         const RAW = 1 << 7;
+        const MAY_UNWIND = 1 << 8;
     }
 }
 
diff --git a/compiler/rustc_ast_lowering/src/asm.rs b/compiler/rustc_ast_lowering/src/asm.rs
index cfa97ff84ec..9f27ace25ab 100644
--- a/compiler/rustc_ast_lowering/src/asm.rs
+++ b/compiler/rustc_ast_lowering/src/asm.rs
@@ -49,6 +49,17 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
                 .struct_span_err(sp, "the `att_syntax` option is only supported on x86")
                 .emit();
         }
+        if asm.options.contains(InlineAsmOptions::MAY_UNWIND)
+            && !self.sess.features_untracked().asm_unwind
+        {
+            feature_err(
+                &self.sess.parse_sess,
+                sym::asm_unwind,
+                sp,
+                "the `may_unwind` option is unstable",
+            )
+            .emit();
+        }
 
         let mut clobber_abis = FxHashMap::default();
         if let Some(asm_arch) = asm_arch {
diff --git a/compiler/rustc_ast_lowering/src/expr.rs b/compiler/rustc_ast_lowering/src/expr.rs
index 9c579209fe5..c9578c2f50f 100644
--- a/compiler/rustc_ast_lowering/src/expr.rs
+++ b/compiler/rustc_ast_lowering/src/expr.rs
@@ -593,7 +593,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
 
     /// Desugar `<expr>.await` into:
     /// ```rust
-    /// match <expr> {
+    /// match ::std::future::IntoFuture::into_future(<expr>) {
     ///     mut pinned => loop {
     ///         match unsafe { ::std::future::Future::poll(
     ///             <::std::pin::Pin>::new_unchecked(&mut pinned),
@@ -629,7 +629,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
             await_span,
             self.allow_gen_future.clone(),
         );
-        let expr = self.lower_expr(expr);
+        let expr = self.lower_expr_mut(expr);
 
         let pinned_ident = Ident::with_dummy_span(sym::pinned);
         let (pinned_pat, pinned_pat_hid) =
@@ -746,10 +746,26 @@ impl<'hir> LoweringContext<'_, 'hir> {
         // mut pinned => loop { ... }
         let pinned_arm = self.arm(pinned_pat, loop_expr);
 
-        // match <expr> {
+        // `match ::std::future::IntoFuture::into_future(<expr>) { ... }`
+        let into_future_span = self.mark_span_with_reason(
+            DesugaringKind::Await,
+            await_span,
+            self.allow_into_future.clone(),
+        );
+        let into_future_expr = self.expr_call_lang_item_fn(
+            into_future_span,
+            hir::LangItem::IntoFutureIntoFuture,
+            arena_vec![self; expr],
+        );
+
+        // match <into_future_expr> {
         //     mut pinned => loop { .. }
         // }
-        hir::ExprKind::Match(expr, arena_vec![self; pinned_arm], hir::MatchSource::AwaitDesugar)
+        hir::ExprKind::Match(
+            into_future_expr,
+            arena_vec![self; pinned_arm],
+            hir::MatchSource::AwaitDesugar,
+        )
     }
 
     fn lower_expr_closure(
diff --git a/compiler/rustc_ast_lowering/src/lib.rs b/compiler/rustc_ast_lowering/src/lib.rs
index 2a246a99a70..1a4f0a26f2b 100644
--- a/compiler/rustc_ast_lowering/src/lib.rs
+++ b/compiler/rustc_ast_lowering/src/lib.rs
@@ -162,6 +162,7 @@ struct LoweringContext<'a, 'hir: 'a> {
 
     allow_try_trait: Option<Lrc<[Symbol]>>,
     allow_gen_future: Option<Lrc<[Symbol]>>,
+    allow_into_future: Option<Lrc<[Symbol]>>,
 }
 
 pub trait ResolverAstLowering {
@@ -320,6 +321,7 @@ pub fn lower_crate<'a, 'hir>(
         in_scope_lifetimes: Vec::new(),
         allow_try_trait: Some([sym::try_trait_v2][..].into()),
         allow_gen_future: Some([sym::gen_future][..].into()),
+        allow_into_future: Some([sym::into_future][..].into()),
     }
     .lower_crate(krate)
 }
diff --git a/compiler/rustc_ast_lowering/src/path.rs b/compiler/rustc_ast_lowering/src/path.rs
index cf0ee4fc28f..78afc339748 100644
--- a/compiler/rustc_ast_lowering/src/path.rs
+++ b/compiler/rustc_ast_lowering/src/path.rs
@@ -229,15 +229,19 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
                         if let Ok(snippet) = self.sess.source_map().span_to_snippet(data.span) {
                             // Do not suggest going from `Trait()` to `Trait<>`
                             if !data.inputs.is_empty() {
-                                if let Some(split) = snippet.find('(') {
-                                    let trait_name = &snippet[0..split];
-                                    let args = &snippet[split + 1..snippet.len() - 1];
-                                    err.span_suggestion(
-                                        data.span,
-                                        "use angle brackets instead",
-                                        format!("{}<{}>", trait_name, args),
-                                        Applicability::MaybeIncorrect,
-                                    );
+                                // Suggest replacing `(` and `)` with `<` and `>`
+                                // The snippet may be missing the closing `)`, skip that case
+                                if snippet.ends_with(')') {
+                                    if let Some(split) = snippet.find('(') {
+                                        let trait_name = &snippet[0..split];
+                                        let args = &snippet[split + 1..snippet.len() - 1];
+                                        err.span_suggestion(
+                                            data.span,
+                                            "use angle brackets instead",
+                                            format!("{}<{}>", trait_name, args),
+                                            Applicability::MaybeIncorrect,
+                                        );
+                                    }
                                 }
                             }
                         };
diff --git a/compiler/rustc_ast_pretty/src/pprust/state.rs b/compiler/rustc_ast_pretty/src/pprust/state.rs
index f1f2387866d..0dc1f093947 100644
--- a/compiler/rustc_ast_pretty/src/pprust/state.rs
+++ b/compiler/rustc_ast_pretty/src/pprust/state.rs
@@ -2338,6 +2338,9 @@ impl<'a> State<'a> {
                 if opts.contains(InlineAsmOptions::RAW) {
                     options.push("raw");
                 }
+                if opts.contains(InlineAsmOptions::MAY_UNWIND) {
+                    options.push("may_unwind");
+                }
                 s.commasep(Inconsistent, &options, |s, &opt| {
                     s.word(opt);
                 });
diff --git a/compiler/rustc_borrowck/src/dataflow.rs b/compiler/rustc_borrowck/src/dataflow.rs
index 7db8d4520d4..15372ec1534 100644
--- a/compiler/rustc_borrowck/src/dataflow.rs
+++ b/compiler/rustc_borrowck/src/dataflow.rs
@@ -5,7 +5,7 @@ use rustc_middle::ty::RegionVid;
 use rustc_middle::ty::TyCtxt;
 use rustc_mir_dataflow::impls::{EverInitializedPlaces, MaybeUninitializedPlaces};
 use rustc_mir_dataflow::ResultsVisitable;
-use rustc_mir_dataflow::{self, fmt::DebugWithContext, GenKill};
+use rustc_mir_dataflow::{self, fmt::DebugWithContext, CallReturnPlaces, GenKill};
 use rustc_mir_dataflow::{Analysis, Direction, Results};
 use std::fmt;
 use std::iter;
@@ -434,9 +434,7 @@ impl<'tcx> rustc_mir_dataflow::GenKillAnalysis<'tcx> for Borrows<'_, 'tcx> {
         &self,
         _trans: &mut impl GenKill<Self::Idx>,
         _block: mir::BasicBlock,
-        _func: &mir::Operand<'tcx>,
-        _args: &[mir::Operand<'tcx>],
-        _dest_place: mir::Place<'tcx>,
+        _return_places: CallReturnPlaces<'_, 'tcx>,
     ) {
     }
 }
diff --git a/compiler/rustc_borrowck/src/def_use.rs b/compiler/rustc_borrowck/src/def_use.rs
index 689ec249a2f..70acbc9ee2d 100644
--- a/compiler/rustc_borrowck/src/def_use.rs
+++ b/compiler/rustc_borrowck/src/def_use.rs
@@ -17,7 +17,7 @@ pub fn categorize(context: PlaceContext) -> Option<DefUse> {
         PlaceContext::MutatingUse(MutatingUseContext::Store) |
 
         // This is potentially both a def and a use...
-        PlaceContext::MutatingUse(MutatingUseContext::AsmOutput) |
+        PlaceContext::MutatingUse(MutatingUseContext::LlvmAsmOutput) |
 
         // We let Call define the result in both the success and
         // unwind cases. This is not really correct, however it
@@ -26,6 +26,7 @@ pub fn categorize(context: PlaceContext) -> Option<DefUse> {
         // the def in call only to the input from the success
         // path and not the unwind path. -nmatsakis
         PlaceContext::MutatingUse(MutatingUseContext::Call) |
+        PlaceContext::MutatingUse(MutatingUseContext::AsmOutput) |
         PlaceContext::MutatingUse(MutatingUseContext::Yield) |
 
         // Storage live and storage dead aren't proper defines, but we can ignore
diff --git a/compiler/rustc_borrowck/src/invalidation.rs b/compiler/rustc_borrowck/src/invalidation.rs
index efd34f4e0a5..c03e4d8a448 100644
--- a/compiler/rustc_borrowck/src/invalidation.rs
+++ b/compiler/rustc_borrowck/src/invalidation.rs
@@ -199,6 +199,7 @@ impl<'cx, 'tcx> Visitor<'tcx> for InvalidationGenerator<'cx, 'tcx> {
                 options: _,
                 line_spans: _,
                 destination: _,
+                cleanup: _,
             } => {
                 for op in operands {
                     match *op {
diff --git a/compiler/rustc_borrowck/src/lib.rs b/compiler/rustc_borrowck/src/lib.rs
index ceaae9d66cd..88fab269109 100644
--- a/compiler/rustc_borrowck/src/lib.rs
+++ b/compiler/rustc_borrowck/src/lib.rs
@@ -791,6 +791,7 @@ impl<'cx, 'tcx> rustc_mir_dataflow::ResultsVisitor<'cx, 'tcx> for MirBorrowckCtx
                 options: _,
                 line_spans: _,
                 destination: _,
+                cleanup: _,
             } => {
                 for op in operands {
                     match *op {
diff --git a/compiler/rustc_borrowck/src/type_check/input_output.rs b/compiler/rustc_borrowck/src/type_check/input_output.rs
index 92d2d04f23f..bc740de5150 100644
--- a/compiler/rustc_borrowck/src/type_check/input_output.rs
+++ b/compiler/rustc_borrowck/src/type_check/input_output.rs
@@ -117,9 +117,29 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
             }
         }
 
-        assert!(body.yield_ty().is_some() == universal_regions.yield_ty.is_some());
-        if let Some(mir_yield_ty) = body.yield_ty() {
-            let ur_yield_ty = universal_regions.yield_ty.unwrap();
+        debug!(
+            "equate_inputs_and_outputs: body.yield_ty {:?}, universal_regions.yield_ty {:?}",
+            body.yield_ty(),
+            universal_regions.yield_ty
+        );
+
+        // We will not have a universal_regions.yield_ty if we yield (by accident)
+        // outside of a generator and return an `impl Trait`, so emit a delay_span_bug
+        // because we don't want to panic in an assert here if we've already got errors.
+        if body.yield_ty().is_some() != universal_regions.yield_ty.is_some() {
+            self.tcx().sess.delay_span_bug(
+                body.span,
+                &format!(
+                    "Expected body to have yield_ty ({:?}) iff we have a UR yield_ty ({:?})",
+                    body.yield_ty(),
+                    universal_regions.yield_ty,
+                ),
+            );
+        }
+
+        if let (Some(mir_yield_ty), Some(ur_yield_ty)) =
+            (body.yield_ty(), universal_regions.yield_ty)
+        {
             let yield_span = body.local_decls[RETURN_PLACE].source_info.span;
             self.equate_normalized_input_or_output(ur_yield_ty, mir_yield_ty, yield_span);
         }
diff --git a/compiler/rustc_borrowck/src/type_check/mod.rs b/compiler/rustc_borrowck/src/type_check/mod.rs
index d90154f1643..6a263bd63ad 100644
--- a/compiler/rustc_borrowck/src/type_check/mod.rs
+++ b/compiler/rustc_borrowck/src/type_check/mod.rs
@@ -31,7 +31,7 @@ use rustc_middle::ty::fold::TypeFoldable;
 use rustc_middle::ty::subst::{GenericArgKind, SubstsRef, UserSubsts};
 use rustc_middle::ty::{
     self, CanonicalUserTypeAnnotation, CanonicalUserTypeAnnotations, OpaqueTypeKey, RegionVid,
-    ToPredicate, Ty, TyCtxt, UserType, UserTypeAnnotationIndex,
+    ToPredicate, Ty, TyCtxt, UserType, UserTypeAnnotationIndex, WithConstness,
 };
 use rustc_span::def_id::CRATE_DEF_ID;
 use rustc_span::{Span, DUMMY_SP};
@@ -1828,10 +1828,16 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
                     self.assert_iscleanup(body, block_data, unwind, true);
                 }
             }
-            TerminatorKind::InlineAsm { destination, .. } => {
+            TerminatorKind::InlineAsm { destination, cleanup, .. } => {
                 if let Some(target) = destination {
                     self.assert_iscleanup(body, block_data, target, is_cleanup);
                 }
+                if let Some(cleanup) = cleanup {
+                    if is_cleanup {
+                        span_mirbug!(self, block_data, "cleanup on cleanup block")
+                    }
+                    self.assert_iscleanup(body, block_data, cleanup, true);
+                }
             }
         }
     }
diff --git a/compiler/rustc_builtin_macros/src/asm.rs b/compiler/rustc_builtin_macros/src/asm.rs
index 41662f46f11..b374769cbea 100644
--- a/compiler/rustc_builtin_macros/src/asm.rs
+++ b/compiler/rustc_builtin_macros/src/asm.rs
@@ -420,6 +420,8 @@ fn parse_options<'a>(
             try_set_option(p, args, sym::att_syntax, ast::InlineAsmOptions::ATT_SYNTAX);
         } else if p.eat_keyword(kw::Raw) {
             try_set_option(p, args, kw::Raw, ast::InlineAsmOptions::RAW);
+        } else if p.eat_keyword(sym::may_unwind) {
+            try_set_option(p, args, kw::Raw, ast::InlineAsmOptions::MAY_UNWIND);
         } else {
             return p.unexpected();
         }
diff --git a/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs b/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs
index 994a74a5a9b..1427a2aada3 100644
--- a/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs
+++ b/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs
@@ -567,8 +567,11 @@ impl<'a> TraitDef<'a> {
             })
         });
 
-        let Generics { mut params, mut where_clause, span } =
+        let Generics { mut params, mut where_clause, .. } =
             self.generics.to_generics(cx, self.span, type_ident, generics);
+        where_clause.span = generics.where_clause.span;
+        let ctxt = self.span.ctxt();
+        let span = generics.span.with_ctxt(ctxt);
 
         // Create the generic parameters
         params.extend(generics.params.iter().map(|param| match &param.kind {
@@ -589,12 +592,12 @@ impl<'a> TraitDef<'a> {
                         param.bounds.iter().cloned()
                     ).collect();
 
-                cx.typaram(self.span, param.ident, vec![], bounds, None)
+                cx.typaram(param.ident.span.with_ctxt(ctxt), param.ident, vec![], bounds, None)
             }
             GenericParamKind::Const { ty, kw_span, .. } => {
                 let const_nodefault_kind = GenericParamKind::Const {
                     ty: ty.clone(),
-                    kw_span: *kw_span,
+                    kw_span: kw_span.with_ctxt(ctxt),
 
                     // We can't have default values inside impl block
                     default: None,
@@ -607,28 +610,27 @@ impl<'a> TraitDef<'a> {
 
         // and similarly for where clauses
         where_clause.predicates.extend(generics.where_clause.predicates.iter().map(|clause| {
-            match *clause {
-                ast::WherePredicate::BoundPredicate(ref wb) => {
+            match clause {
+                ast::WherePredicate::BoundPredicate(wb) => {
+                    let span = wb.span.with_ctxt(ctxt);
                     ast::WherePredicate::BoundPredicate(ast::WhereBoundPredicate {
-                        span: self.span,
-                        bound_generic_params: wb.bound_generic_params.clone(),
-                        bounded_ty: wb.bounded_ty.clone(),
-                        bounds: wb.bounds.to_vec(),
+                        span,
+                        ..wb.clone()
                     })
                 }
-                ast::WherePredicate::RegionPredicate(ref rb) => {
+                ast::WherePredicate::RegionPredicate(wr) => {
+                    let span = wr.span.with_ctxt(ctxt);
                     ast::WherePredicate::RegionPredicate(ast::WhereRegionPredicate {
-                        span: self.span,
-                        lifetime: rb.lifetime,
-                        bounds: rb.bounds.to_vec(),
+                        span,
+                        ..wr.clone()
                     })
                 }
-                ast::WherePredicate::EqPredicate(ref we) => {
+                ast::WherePredicate::EqPredicate(we) => {
+                    let span = we.span.with_ctxt(ctxt);
                     ast::WherePredicate::EqPredicate(ast::WhereEqPredicate {
                         id: ast::DUMMY_NODE_ID,
-                        span: self.span,
-                        lhs_ty: we.lhs_ty.clone(),
-                        rhs_ty: we.rhs_ty.clone(),
+                        span,
+                        ..we.clone()
                     })
                 }
             }
@@ -691,13 +693,13 @@ impl<'a> TraitDef<'a> {
             .iter()
             .map(|param| match param.kind {
                 GenericParamKind::Lifetime { .. } => {
-                    GenericArg::Lifetime(cx.lifetime(self.span, param.ident))
+                    GenericArg::Lifetime(cx.lifetime(param.ident.span.with_ctxt(ctxt), param.ident))
                 }
                 GenericParamKind::Type { .. } => {
-                    GenericArg::Type(cx.ty_ident(self.span, param.ident))
+                    GenericArg::Type(cx.ty_ident(param.ident.span.with_ctxt(ctxt), param.ident))
                 }
                 GenericParamKind::Const { .. } => {
-                    GenericArg::Const(cx.const_ident(self.span, param.ident))
+                    GenericArg::Const(cx.const_ident(param.ident.span.with_ctxt(ctxt), param.ident))
                 }
             })
             .collect();
@@ -845,16 +847,17 @@ impl<'a> MethodDef<'a> {
         nonself_args: &[P<Expr>],
         fields: &SubstructureFields<'_>,
     ) -> P<Expr> {
+        let span = trait_.span;
         let substructure = Substructure {
             type_ident,
-            method_ident: Ident::new(self.name, trait_.span),
+            method_ident: Ident::new(self.name, span),
             self_args,
             nonself_args,
             fields,
         };
         let mut f = self.combine_substructure.borrow_mut();
         let f: &mut CombineSubstructureFunc<'_> = &mut *f;
-        f(cx, trait_.span, &substructure)
+        f(cx, span, &substructure)
     }
 
     fn get_ret_ty(
@@ -882,9 +885,10 @@ impl<'a> MethodDef<'a> {
         let mut nonself_args = Vec::new();
         let mut arg_tys = Vec::new();
         let mut nonstatic = false;
+        let span = trait_.span;
 
         let ast_explicit_self = self.explicit_self.as_ref().map(|self_ptr| {
-            let (self_expr, explicit_self) = ty::get_explicit_self(cx, trait_.span, self_ptr);
+            let (self_expr, explicit_self) = ty::get_explicit_self(cx, span, self_ptr);
 
             self_args.push(self_expr);
             nonstatic = true;
@@ -893,11 +897,11 @@ impl<'a> MethodDef<'a> {
         });
 
         for (ty, name) in self.args.iter() {
-            let ast_ty = ty.to_ty(cx, trait_.span, type_ident, generics);
-            let ident = Ident::new(*name, trait_.span);
+            let ast_ty = ty.to_ty(cx, span, type_ident, generics);
+            let ident = Ident::new(*name, span);
             arg_tys.push((ident, ast_ty));
 
-            let arg_expr = cx.expr_ident(trait_.span, ident);
+            let arg_expr = cx.expr_ident(span, ident);
 
             match *ty {
                 // for static methods, just treat any Self
@@ -906,7 +910,7 @@ impl<'a> MethodDef<'a> {
                     self_args.push(arg_expr);
                 }
                 Ptr(ref ty, _) if matches!(**ty, Self_) && nonstatic => {
-                    self_args.push(cx.expr_deref(trait_.span, arg_expr))
+                    self_args.push(cx.expr_deref(span, arg_expr))
                 }
                 _ => {
                     nonself_args.push(arg_expr);
@@ -927,33 +931,33 @@ impl<'a> MethodDef<'a> {
         arg_types: Vec<(Ident, P<ast::Ty>)>,
         body: P<Expr>,
     ) -> P<ast::AssocItem> {
+        let span = trait_.span;
         // Create the generics that aren't for `Self`.
-        let fn_generics = self.generics.to_generics(cx, trait_.span, type_ident, generics);
+        let fn_generics = self.generics.to_generics(cx, span, type_ident, generics);
 
         let args = {
             let self_args = explicit_self.map(|explicit_self| {
-                let ident = Ident::with_dummy_span(kw::SelfLower).with_span_pos(trait_.span);
+                let ident = Ident::with_dummy_span(kw::SelfLower).with_span_pos(span);
                 ast::Param::from_self(ast::AttrVec::default(), explicit_self, ident)
             });
-            let nonself_args =
-                arg_types.into_iter().map(|(name, ty)| cx.param(trait_.span, name, ty));
+            let nonself_args = arg_types.into_iter().map(|(name, ty)| cx.param(span, name, ty));
             self_args.into_iter().chain(nonself_args).collect()
         };
 
         let ret_type = self.get_ret_ty(cx, trait_, generics, type_ident);
 
-        let method_ident = Ident::new(self.name, trait_.span);
+        let method_ident = Ident::new(self.name, span);
         let fn_decl = cx.fn_decl(args, ast::FnRetTy::Ty(ret_type));
         let body_block = cx.block_expr(body);
 
-        let unsafety = if self.is_unsafe { ast::Unsafe::Yes(trait_.span) } else { ast::Unsafe::No };
+        let unsafety = if self.is_unsafe { ast::Unsafe::Yes(span) } else { ast::Unsafe::No };
 
-        let trait_lo_sp = trait_.span.shrink_to_lo();
+        let trait_lo_sp = span.shrink_to_lo();
 
         let sig = ast::FnSig {
             header: ast::FnHeader { unsafety, ext: ast::Extern::None, ..ast::FnHeader::default() },
             decl: fn_decl,
-            span: trait_.span,
+            span,
         };
         let defaultness = ast::Defaultness::Final;
 
@@ -961,7 +965,7 @@ impl<'a> MethodDef<'a> {
         P(ast::AssocItem {
             id: ast::DUMMY_NODE_ID,
             attrs: self.attributes.clone(),
-            span: trait_.span,
+            span,
             vis: ast::Visibility {
                 span: trait_lo_sp,
                 kind: ast::VisibilityKind::Inherited,
@@ -1024,11 +1028,11 @@ impl<'a> MethodDef<'a> {
         nonself_args: &[P<Expr>],
         use_temporaries: bool,
     ) -> P<Expr> {
-        let mut raw_fields = Vec::new(); // Vec<[fields of self],
-        // [fields of next Self arg], [etc]>
+        let mut raw_fields = Vec::new(); // Vec<[fields of self], [fields of next Self arg], [etc]>
+        let span = trait_.span;
         let mut patterns = Vec::new();
         for i in 0..self_args.len() {
-            let struct_path = cx.path(trait_.span, vec![type_ident]);
+            let struct_path = cx.path(span, vec![type_ident]);
             let (pat, ident_expr) = trait_.create_struct_pattern(
                 cx,
                 struct_path,
@@ -1048,7 +1052,7 @@ impl<'a> MethodDef<'a> {
             let mut other_fields: Vec<vec::IntoIter<_>> = raw_fields.collect();
             first_field
                 .map(|(span, opt_id, field, attrs)| FieldInfo {
-                    span,
+                    span: span.with_ctxt(trait_.span.ctxt()),
                     name: opt_id,
                     self_: field,
                     other: other_fields
@@ -1062,7 +1066,7 @@ impl<'a> MethodDef<'a> {
                 })
                 .collect()
         } else {
-            cx.span_bug(trait_.span, "no `self` parameter for method in generic `derive`")
+            cx.span_bug(span, "no `self` parameter for method in generic `derive`")
         };
 
         // body of the inner most destructuring match
@@ -1079,11 +1083,7 @@ impl<'a> MethodDef<'a> {
         // structs. This is actually right-to-left, but it shouldn't
         // matter.
         for (arg_expr, pat) in iter::zip(self_args, patterns) {
-            body = cx.expr_match(
-                trait_.span,
-                arg_expr.clone(),
-                vec![cx.arm(trait_.span, pat.clone(), body)],
-            )
+            body = cx.expr_match(span, arg_expr.clone(), vec![cx.arm(span, pat.clone(), body)])
         }
 
         body
@@ -1193,7 +1193,7 @@ impl<'a> MethodDef<'a> {
         mut self_args: Vec<P<Expr>>,
         nonself_args: &[P<Expr>],
     ) -> P<Expr> {
-        let sp = trait_.span;
+        let span = trait_.span;
         let variants = &enum_def.variants;
 
         let self_arg_names = iter::once("__self".to_string())
@@ -1208,7 +1208,7 @@ impl<'a> MethodDef<'a> {
 
         let self_arg_idents = self_arg_names
             .iter()
-            .map(|name| Ident::from_str_and_span(name, sp))
+            .map(|name| Ident::from_str_and_span(name, span))
             .collect::<Vec<Ident>>();
 
         // The `vi_idents` will be bound, solely in the catch-all, to
@@ -1218,7 +1218,7 @@ impl<'a> MethodDef<'a> {
             .iter()
             .map(|name| {
                 let vi_suffix = format!("{}_vi", &name[..]);
-                Ident::from_str_and_span(&vi_suffix, trait_.span)
+                Ident::from_str_and_span(&vi_suffix, span)
             })
             .collect::<Vec<Ident>>();
 
@@ -1248,7 +1248,7 @@ impl<'a> MethodDef<'a> {
                         self_arg_name,
                         ast::Mutability::Not,
                     );
-                    (cx.pat(sp, PatKind::Ref(p, ast::Mutability::Not)), idents)
+                    (cx.pat(span, PatKind::Ref(p, ast::Mutability::Not)), idents)
                 };
 
                 // A single arm has form (&VariantK, &VariantK, ...) => BodyK
@@ -1267,7 +1267,7 @@ impl<'a> MethodDef<'a> {
                 }
 
                 // Here is the pat = `(&VariantK, &VariantK, ...)`
-                let single_pat = cx.pat_tuple(sp, subpats);
+                let single_pat = cx.pat_tuple(span, subpats);
 
                 // For the BodyK, we need to delegate to our caller,
                 // passing it an EnumMatching to indicate which case
@@ -1284,7 +1284,7 @@ impl<'a> MethodDef<'a> {
                     .into_iter()
                     .enumerate()
                     // For each arg field of self, pull out its getter expr ...
-                    .map(|(field_index, (sp, opt_ident, self_getter_expr, attrs))| {
+                    .map(|(field_index, (span, opt_ident, self_getter_expr, attrs))| {
                         // ... but FieldInfo also wants getter expr
                         // for matching other arguments of Self type;
                         // so walk across the *other* self_pats_idents
@@ -1307,7 +1307,7 @@ impl<'a> MethodDef<'a> {
                             .collect::<Vec<P<Expr>>>();
 
                         FieldInfo {
-                            span: sp,
+                            span,
                             name: opt_ident,
                             self_: self_getter_expr,
                             other: others,
@@ -1330,7 +1330,7 @@ impl<'a> MethodDef<'a> {
                     &substructure,
                 );
 
-                cx.arm(sp, single_pat, arm_expr)
+                cx.arm(span, single_pat, arm_expr)
             })
             .collect();
 
@@ -1353,12 +1353,12 @@ impl<'a> MethodDef<'a> {
                 // Since we know that all the arguments will match if we reach
                 // the match expression we add the unreachable intrinsics as the
                 // result of the catch all which should help llvm in optimizing it
-                Some(deriving::call_unreachable(cx, sp))
+                Some(deriving::call_unreachable(cx, span))
             }
             _ => None,
         };
         if let Some(arm) = default {
-            match_arms.push(cx.arm(sp, cx.pat_wild(sp), arm));
+            match_arms.push(cx.arm(span, cx.pat_wild(span), arm));
         }
 
         // We will usually need the catch-all after matching the
@@ -1392,23 +1392,23 @@ impl<'a> MethodDef<'a> {
 
             // We also build an expression which checks whether all discriminants are equal
             // discriminant_test = __self0_vi == __self1_vi && __self0_vi == __self2_vi && ...
-            let mut discriminant_test = cx.expr_bool(sp, true);
+            let mut discriminant_test = cx.expr_bool(span, true);
 
             let mut first_ident = None;
             for (&ident, self_arg) in iter::zip(&vi_idents, &self_args) {
-                let self_addr = cx.expr_addr_of(sp, self_arg.clone());
+                let self_addr = cx.expr_addr_of(span, self_arg.clone());
                 let variant_value =
-                    deriving::call_intrinsic(cx, sp, sym::discriminant_value, vec![self_addr]);
-                let let_stmt = cx.stmt_let(sp, false, ident, variant_value);
+                    deriving::call_intrinsic(cx, span, sym::discriminant_value, vec![self_addr]);
+                let let_stmt = cx.stmt_let(span, false, ident, variant_value);
                 index_let_stmts.push(let_stmt);
 
                 match first_ident {
                     Some(first) => {
-                        let first_expr = cx.expr_ident(sp, first);
-                        let id = cx.expr_ident(sp, ident);
-                        let test = cx.expr_binary(sp, BinOpKind::Eq, first_expr, id);
+                        let first_expr = cx.expr_ident(span, first);
+                        let id = cx.expr_ident(span, ident);
+                        let test = cx.expr_binary(span, BinOpKind::Eq, first_expr, id);
                         discriminant_test =
-                            cx.expr_binary(sp, BinOpKind::And, discriminant_test, test)
+                            cx.expr_binary(span, BinOpKind::And, discriminant_test, test)
                     }
                     None => {
                         first_ident = Some(ident);
@@ -1430,8 +1430,8 @@ impl<'a> MethodDef<'a> {
             // them when they are fed as r-values into a tuple
             // expression; here add a layer of borrowing, turning
             // `(*self, *__arg_0, ...)` into `(&*self, &*__arg_0, ...)`.
-            self_args.map_in_place(|self_arg| cx.expr_addr_of(sp, self_arg));
-            let match_arg = cx.expr(sp, ast::ExprKind::Tup(self_args));
+            self_args.map_in_place(|self_arg| cx.expr_addr_of(span, self_arg));
+            let match_arg = cx.expr(span, ast::ExprKind::Tup(self_args));
 
             // Lastly we create an expression which branches on all discriminants being equal
             //  if discriminant_test {
@@ -1445,10 +1445,10 @@ impl<'a> MethodDef<'a> {
             //  else {
             //      <delegated expression referring to __self0_vi, et al.>
             //  }
-            let all_match = cx.expr_match(sp, match_arg, match_arms);
-            let arm_expr = cx.expr_if(sp, discriminant_test, all_match, Some(arm_expr));
+            let all_match = cx.expr_match(span, match_arg, match_arms);
+            let arm_expr = cx.expr_if(span, discriminant_test, all_match, Some(arm_expr));
             index_let_stmts.push(cx.stmt_expr(arm_expr));
-            cx.expr_block(cx.block(sp, index_let_stmts))
+            cx.expr_block(cx.block(span, index_let_stmts))
         } else if variants.is_empty() {
             // As an additional wrinkle, For a zero-variant enum A,
             // currently the compiler
@@ -1499,16 +1499,16 @@ impl<'a> MethodDef<'a> {
             // derive Debug on such a type could here generate code
             // that needs the feature gate enabled.)
 
-            deriving::call_unreachable(cx, sp)
+            deriving::call_unreachable(cx, span)
         } else {
             // Final wrinkle: the self_args are expressions that deref
             // down to desired places, but we cannot actually deref
             // them when they are fed as r-values into a tuple
             // expression; here add a layer of borrowing, turning
             // `(*self, *__arg_0, ...)` into `(&*self, &*__arg_0, ...)`.
-            self_args.map_in_place(|self_arg| cx.expr_addr_of(sp, self_arg));
-            let match_arg = cx.expr(sp, ast::ExprKind::Tup(self_args));
-            cx.expr_match(sp, match_arg, match_arms)
+            self_args.map_in_place(|self_arg| cx.expr_addr_of(span, self_arg));
+            let match_arg = cx.expr(span, ast::ExprKind::Tup(self_args));
+            cx.expr_match(span, match_arg, match_arms)
         }
     }
 
@@ -1556,11 +1556,9 @@ impl<'a> TraitDef<'a> {
 
         let is_tuple = matches!(struct_def, ast::VariantData::Tuple(..));
         match (just_spans.is_empty(), named_idents.is_empty()) {
-            (false, false) => cx.span_bug(
-                self.span,
-                "a struct with named and unnamed \
-                                          fields in generic `derive`",
-            ),
+            (false, false) => {
+                cx.span_bug(self.span, "a struct with named and unnamed fields in generic `derive`")
+            }
             // named fields
             (_, false) => Named(named_idents),
             // unnamed fields
diff --git a/compiler/rustc_builtin_macros/src/deriving/generic/ty.rs b/compiler/rustc_builtin_macros/src/deriving/generic/ty.rs
index 00d75be4399..7a418003250 100644
--- a/compiler/rustc_builtin_macros/src/deriving/generic/ty.rs
+++ b/compiler/rustc_builtin_macros/src/deriving/generic/ty.rs
@@ -211,14 +211,6 @@ fn mk_ty_param(
     cx.typaram(span, Ident::new(name, span), attrs.to_owned(), bounds, None)
 }
 
-fn mk_generics(params: Vec<ast::GenericParam>, span: Span) -> Generics {
-    Generics {
-        params,
-        where_clause: ast::WhereClause { has_where_token: false, predicates: Vec::new(), span },
-        span,
-    }
-}
-
 /// Bounds on type parameters.
 #[derive(Clone)]
 pub struct Bounds {
@@ -236,7 +228,7 @@ impl Bounds {
         self_ty: Ident,
         self_generics: &Generics,
     ) -> Generics {
-        let generic_params = self
+        let params = self
             .bounds
             .iter()
             .map(|t| {
@@ -245,7 +237,11 @@ impl Bounds {
             })
             .collect();
 
-        mk_generics(generic_params, span)
+        Generics {
+            params,
+            where_clause: ast::WhereClause { has_where_token: false, predicates: Vec::new(), span },
+            span,
+        }
     }
 }
 
diff --git a/compiler/rustc_codegen_cranelift/src/base.rs b/compiler/rustc_codegen_cranelift/src/base.rs
index 1b30edd2938..371c71de62f 100644
--- a/compiler/rustc_codegen_cranelift/src/base.rs
+++ b/compiler/rustc_codegen_cranelift/src/base.rs
@@ -1,6 +1,7 @@
 //! Codegen of a single function
 
 use cranelift_codegen::binemit::{NullStackMapSink, NullTrapSink};
+use rustc_ast::InlineAsmOptions;
 use rustc_index::vec::IndexVec;
 use rustc_middle::ty::adjustment::PointerCast;
 use rustc_middle::ty::layout::FnAbiOf;
@@ -239,7 +240,8 @@ fn codegen_fn_content(fx: &mut FunctionCx<'_, '_, '_>) {
             fx.add_comment(inst, terminator_head);
         }
 
-        fx.set_debug_loc(bb_data.terminator().source_info);
+        let source_info = bb_data.terminator().source_info;
+        fx.set_debug_loc(source_info);
 
         match &bb_data.terminator().kind {
             TerminatorKind::Goto { target } => {
@@ -295,19 +297,19 @@ fn codegen_fn_content(fx: &mut FunctionCx<'_, '_, '_>) {
                         let len = codegen_operand(fx, len).load_scalar(fx);
                         let index = codegen_operand(fx, index).load_scalar(fx);
                         let location = fx
-                            .get_caller_location(bb_data.terminator().source_info.span)
+                            .get_caller_location(source_info.span)
                             .load_scalar(fx);
 
                         codegen_panic_inner(
                             fx,
                             rustc_hir::LangItem::PanicBoundsCheck,
                             &[index, len, location],
-                            bb_data.terminator().source_info.span,
+                            source_info.span,
                         );
                     }
                     _ => {
                         let msg_str = msg.description();
-                        codegen_panic(fx, msg_str, bb_data.terminator().source_info.span);
+                        codegen_panic(fx, msg_str, source_info.span);
                     }
                 }
             }
@@ -378,10 +380,18 @@ fn codegen_fn_content(fx: &mut FunctionCx<'_, '_, '_>) {
                 options,
                 destination,
                 line_spans: _,
+                cleanup: _,
             } => {
+                if options.contains(InlineAsmOptions::MAY_UNWIND) {
+                    fx.tcx.sess.span_fatal(
+                        source_info.span,
+                        "cranelift doesn't support unwinding from inline assembly.",
+                    );
+                }
+
                 crate::inline_asm::codegen_inline_asm(
                     fx,
-                    bb_data.terminator().source_info.span,
+                    source_info.span,
                     template,
                     operands,
                     *options,
@@ -415,7 +425,7 @@ fn codegen_fn_content(fx: &mut FunctionCx<'_, '_, '_>) {
             }
             TerminatorKind::Drop { place, target, unwind: _ } => {
                 let drop_place = codegen_place(fx, *place);
-                crate::abi::codegen_drop(fx, bb_data.terminator().source_info.span, drop_place);
+                crate::abi::codegen_drop(fx, source_info.span, drop_place);
 
                 let target_block = fx.get_block(*target);
                 fx.bcx.ins().jump(target_block, &[]);
diff --git a/compiler/rustc_codegen_gcc/src/asm.rs b/compiler/rustc_codegen_gcc/src/asm.rs
index 7c3ed3c5ee9..6a3b94a0d70 100644
--- a/compiler/rustc_codegen_gcc/src/asm.rs
+++ b/compiler/rustc_codegen_gcc/src/asm.rs
@@ -118,7 +118,14 @@ impl<'a, 'gcc, 'tcx> AsmBuilderMethods<'tcx> for Builder<'a, 'gcc, 'tcx> {
         true
     }
 
-    fn codegen_inline_asm(&mut self, template: &[InlineAsmTemplatePiece], rust_operands: &[InlineAsmOperandRef<'tcx, Self>], options: InlineAsmOptions, _span: &[Span], _instance: Instance<'_>) {
+    fn codegen_inline_asm(&mut self, template: &[InlineAsmTemplatePiece], rust_operands: &[InlineAsmOperandRef<'tcx, Self>], options: InlineAsmOptions, span: &[Span], _instance: Instance<'_>, _dest_catch_funclet: Option<(Self::BasicBlock, Self::BasicBlock, Option<&Self::Funclet>)>) {
+        if options.contains(InlineAsmOptions::MAY_UNWIND) {
+            self.sess()
+                .struct_span_err(span[0], "GCC backend does not support unwinding from inline asm")
+                .emit();
+            return;
+        }
+
         let asm_arch = self.tcx.sess.asm_arch.unwrap();
         let is_x86 = matches!(asm_arch, InlineAsmArch::X86 | InlineAsmArch::X86_64);
         let att_dialect = is_x86 && options.contains(InlineAsmOptions::ATT_SYNTAX);
diff --git a/compiler/rustc_codegen_llvm/src/asm.rs b/compiler/rustc_codegen_llvm/src/asm.rs
index 02096f4abfa..83c5cb6f1cf 100644
--- a/compiler/rustc_codegen_llvm/src/asm.rs
+++ b/compiler/rustc_codegen_llvm/src/asm.rs
@@ -1,6 +1,8 @@
 use crate::builder::Builder;
+use crate::common::Funclet;
 use crate::context::CodegenCx;
 use crate::llvm;
+use crate::llvm_util;
 use crate::type_::Type;
 use crate::type_of::LayoutLlvmExt;
 use crate::value::Value;
@@ -98,6 +100,8 @@ impl AsmBuilderMethods<'tcx> for Builder<'a, 'll, 'tcx> {
             ia.alignstack,
             ia.dialect,
             &[span],
+            false,
+            None,
         );
         if r.is_none() {
             return false;
@@ -121,6 +125,7 @@ impl AsmBuilderMethods<'tcx> for Builder<'a, 'll, 'tcx> {
         options: InlineAsmOptions,
         line_spans: &[Span],
         instance: Instance<'_>,
+        dest_catch_funclet: Option<(Self::BasicBlock, Self::BasicBlock, Option<&Self::Funclet>)>,
     ) {
         let asm_arch = self.tcx.sess.asm_arch.unwrap();
 
@@ -355,6 +360,8 @@ impl AsmBuilderMethods<'tcx> for Builder<'a, 'll, 'tcx> {
             alignstack,
             dialect,
             line_spans,
+            options.contains(InlineAsmOptions::MAY_UNWIND),
+            dest_catch_funclet,
         )
         .unwrap_or_else(|| span_bug!(line_spans[0], "LLVM asm constraint validation failed"));
 
@@ -447,9 +454,16 @@ pub(crate) fn inline_asm_call(
     alignstack: bool,
     dia: LlvmAsmDialect,
     line_spans: &[Span],
+    unwind: bool,
+    dest_catch_funclet: Option<(
+        &'ll llvm::BasicBlock,
+        &'ll llvm::BasicBlock,
+        Option<&Funclet<'ll>>,
+    )>,
 ) -> Option<&'ll Value> {
     let volatile = if volatile { llvm::True } else { llvm::False };
     let alignstack = if alignstack { llvm::True } else { llvm::False };
+    let can_throw = if unwind { llvm::True } else { llvm::False };
 
     let argtys = inputs
         .iter()
@@ -466,6 +480,13 @@ pub(crate) fn inline_asm_call(
         let constraints_ok = llvm::LLVMRustInlineAsmVerify(fty, cons.as_ptr().cast(), cons.len());
         debug!("constraint verification result: {:?}", constraints_ok);
         if constraints_ok {
+            if unwind && llvm_util::get_version() < (13, 0, 0) {
+                bx.cx.sess().span_fatal(
+                    line_spans[0],
+                    "unwinding from inline assembly is only supported on llvm >= 13.",
+                );
+            }
+
             let v = llvm::LLVMRustInlineAsm(
                 fty,
                 asm.as_ptr().cast(),
@@ -475,8 +496,14 @@ pub(crate) fn inline_asm_call(
                 volatile,
                 alignstack,
                 llvm::AsmDialect::from_generic(dia),
+                can_throw,
             );
-            let call = bx.call(fty, v, inputs, None);
+
+            let call = if let Some((dest, catch, funclet)) = dest_catch_funclet {
+                bx.invoke(fty, v, inputs, dest, catch, funclet)
+            } else {
+                bx.call(fty, v, inputs, None)
+            };
 
             // Store mark in a metadata node so we can map LLVM errors
             // back to source locations.  See #17552.
diff --git a/compiler/rustc_codegen_llvm/src/intrinsic.rs b/compiler/rustc_codegen_llvm/src/intrinsic.rs
index a7e34b08059..5e7d7552daf 100644
--- a/compiler/rustc_codegen_llvm/src/intrinsic.rs
+++ b/compiler/rustc_codegen_llvm/src/intrinsic.rs
@@ -350,6 +350,8 @@ impl IntrinsicCallMethods<'tcx> for Builder<'a, 'll, 'tcx> {
                     false,
                     ast::LlvmAsmDialect::Att,
                     &[span],
+                    false,
+                    None,
                 )
                 .unwrap_or_else(|| bug!("failed to generate inline asm call for `black_box`"));
 
diff --git a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs
index 2ef4c871825..d9a6723fe27 100644
--- a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs
+++ b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs
@@ -1847,6 +1847,7 @@ extern "C" {
         SideEffects: Bool,
         AlignStack: Bool,
         Dialect: AsmDialect,
+        CanThrow: Bool,
     ) -> &Value;
     pub fn LLVMRustInlineAsmVerify(
         Ty: &Type,
diff --git a/compiler/rustc_codegen_ssa/src/mir/analyze.rs b/compiler/rustc_codegen_ssa/src/mir/analyze.rs
index 8d75b2e7a3d..0447c02fdec 100644
--- a/compiler/rustc_codegen_ssa/src/mir/analyze.rs
+++ b/compiler/rustc_codegen_ssa/src/mir/analyze.rs
@@ -211,6 +211,7 @@ impl<'mir, 'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> Visitor<'tcx>
 
             PlaceContext::MutatingUse(
                 MutatingUseContext::Store
+                | MutatingUseContext::LlvmAsmOutput
                 | MutatingUseContext::AsmOutput
                 | MutatingUseContext::Borrow
                 | MutatingUseContext::AddressOf
@@ -275,9 +276,9 @@ pub fn cleanup_kinds(mir: &mir::Body<'_>) -> IndexVec<mir::BasicBlock, CleanupKi
                 | TerminatorKind::SwitchInt { .. }
                 | TerminatorKind::Yield { .. }
                 | TerminatorKind::FalseEdge { .. }
-                | TerminatorKind::FalseUnwind { .. }
-                | TerminatorKind::InlineAsm { .. } => { /* nothing to do */ }
+                | TerminatorKind::FalseUnwind { .. } => { /* nothing to do */ }
                 TerminatorKind::Call { cleanup: unwind, .. }
+                | TerminatorKind::InlineAsm { cleanup: unwind, .. }
                 | TerminatorKind::Assert { cleanup: unwind, .. }
                 | TerminatorKind::DropAndReplace { unwind, .. }
                 | TerminatorKind::Drop { unwind, .. } => {
diff --git a/compiler/rustc_codegen_ssa/src/mir/block.rs b/compiler/rustc_codegen_ssa/src/mir/block.rs
index c8f388bfa1d..e914e493269 100644
--- a/compiler/rustc_codegen_ssa/src/mir/block.rs
+++ b/compiler/rustc_codegen_ssa/src/mir/block.rs
@@ -10,6 +10,7 @@ use crate::traits::*;
 use crate::MemFlags;
 
 use rustc_ast as ast;
+use rustc_ast::{InlineAsmOptions, InlineAsmTemplatePiece};
 use rustc_hir::lang_items::LangItem;
 use rustc_index::vec::Idx;
 use rustc_middle::mir::AssertKind;
@@ -174,6 +175,45 @@ impl<'a, 'tcx> TerminatorCodegenHelper<'tcx> {
             }
         }
     }
+
+    /// Generates inline assembly with optional `destination` and `cleanup`.
+    fn do_inlineasm<Bx: BuilderMethods<'a, 'tcx>>(
+        &self,
+        fx: &mut FunctionCx<'a, 'tcx, Bx>,
+        bx: &mut Bx,
+        template: &[InlineAsmTemplatePiece],
+        operands: &[InlineAsmOperandRef<'tcx, Bx>],
+        options: InlineAsmOptions,
+        line_spans: &[Span],
+        destination: Option<mir::BasicBlock>,
+        cleanup: Option<mir::BasicBlock>,
+        instance: Instance<'_>,
+    ) {
+        if let Some(cleanup) = cleanup {
+            let ret_llbb = if let Some(target) = destination {
+                fx.llbb(target)
+            } else {
+                fx.unreachable_block()
+            };
+
+            bx.codegen_inline_asm(
+                template,
+                &operands,
+                options,
+                line_spans,
+                instance,
+                Some((ret_llbb, self.llblock(fx, cleanup), self.funclet(fx))),
+            );
+        } else {
+            bx.codegen_inline_asm(template, &operands, options, line_spans, instance, None);
+
+            if let Some(target) = destination {
+                self.funclet_br(fx, bx, target);
+            } else {
+                bx.unreachable();
+            }
+        }
+    }
 }
 
 /// Codegen implementations for some terminator variants.
@@ -877,6 +917,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
         options: ast::InlineAsmOptions,
         line_spans: &[Span],
         destination: Option<mir::BasicBlock>,
+        cleanup: Option<mir::BasicBlock>,
         instance: Instance<'_>,
     ) {
         let span = terminator.source_info.span;
@@ -931,13 +972,17 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
             })
             .collect();
 
-        bx.codegen_inline_asm(template, &operands, options, line_spans, instance);
-
-        if let Some(target) = destination {
-            helper.funclet_br(self, &mut bx, target);
-        } else {
-            bx.unreachable();
-        }
+        helper.do_inlineasm(
+            self,
+            &mut bx,
+            template,
+            &operands,
+            options,
+            line_spans,
+            destination,
+            cleanup,
+            instance,
+        );
     }
 }
 
@@ -1041,6 +1086,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
                 options,
                 line_spans,
                 destination,
+                cleanup,
             } => {
                 self.codegen_asm_terminator(
                     helper,
@@ -1051,6 +1097,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
                     options,
                     line_spans,
                     destination,
+                    cleanup,
                     self.instance,
                 );
             }
diff --git a/compiler/rustc_codegen_ssa/src/traits/asm.rs b/compiler/rustc_codegen_ssa/src/traits/asm.rs
index 31f539e1b03..65f3c754d2d 100644
--- a/compiler/rustc_codegen_ssa/src/traits/asm.rs
+++ b/compiler/rustc_codegen_ssa/src/traits/asm.rs
@@ -59,6 +59,7 @@ pub trait AsmBuilderMethods<'tcx>: BackendTypes {
         options: InlineAsmOptions,
         line_spans: &[Span],
         instance: Instance<'_>,
+        dest_catch_funclet: Option<(Self::BasicBlock, Self::BasicBlock, Option<&Self::Funclet>)>,
     );
 }
 
diff --git a/compiler/rustc_const_eval/src/const_eval/eval_queries.rs b/compiler/rustc_const_eval/src/const_eval/eval_queries.rs
index c5412affafe..6d3a89c0a8a 100644
--- a/compiler/rustc_const_eval/src/const_eval/eval_queries.rs
+++ b/compiler/rustc_const_eval/src/const_eval/eval_queries.rs
@@ -7,7 +7,6 @@ use crate::interpret::{
 };
 
 use rustc_errors::ErrorReported;
-use rustc_hir as hir;
 use rustc_hir::def::DefKind;
 use rustc_middle::mir;
 use rustc_middle::mir::interpret::ErrorHandled;
@@ -216,7 +215,6 @@ pub fn eval_to_const_value_raw_provider<'tcx>(
     tcx: TyCtxt<'tcx>,
     key: ty::ParamEnvAnd<'tcx, GlobalId<'tcx>>,
 ) -> ::rustc_middle::mir::interpret::EvalToConstValueResult<'tcx> {
-    assert!(key.param_env.constness() == hir::Constness::Const);
     // see comment in eval_to_allocation_raw_provider for what we're doing here
     if key.param_env.reveal() == Reveal::All {
         let mut key = key;
@@ -251,7 +249,6 @@ pub fn eval_to_allocation_raw_provider<'tcx>(
     tcx: TyCtxt<'tcx>,
     key: ty::ParamEnvAnd<'tcx, GlobalId<'tcx>>,
 ) -> ::rustc_middle::mir::interpret::EvalToAllocationRawResult<'tcx> {
-    assert!(key.param_env.constness() == hir::Constness::Const);
     // Because the constant is computed twice (once per value of `Reveal`), we are at risk of
     // reporting the same error twice here. To resolve this, we check whether we can evaluate the
     // constant in the more restrictive `Reveal::UserFacing`, which most likely already was
diff --git a/compiler/rustc_const_eval/src/interpret/eval_context.rs b/compiler/rustc_const_eval/src/interpret/eval_context.rs
index 6206deb2115..cf084faade8 100644
--- a/compiler/rustc_const_eval/src/interpret/eval_context.rs
+++ b/compiler/rustc_const_eval/src/interpret/eval_context.rs
@@ -918,7 +918,6 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
         } else {
             self.param_env
         };
-        let param_env = param_env.with_const();
         let val = self.tcx.eval_to_allocation_raw(param_env.and(gid))?;
         self.raw_const_to_mplace(val)
     }
diff --git a/compiler/rustc_const_eval/src/transform/check_consts/check.rs b/compiler/rustc_const_eval/src/transform/check_consts/check.rs
index f9e65ea9075..274665ccd98 100644
--- a/compiler/rustc_const_eval/src/transform/check_consts/check.rs
+++ b/compiler/rustc_const_eval/src/transform/check_consts/check.rs
@@ -817,7 +817,8 @@ impl Visitor<'tcx> for Checker<'mir, 'tcx> {
                     );
 
                     let implsrc = tcx.infer_ctxt().enter(|infcx| {
-                        let mut selcx = SelectionContext::new(&infcx);
+                        let mut selcx =
+                            SelectionContext::with_constness(&infcx, hir::Constness::Const);
                         selcx.select(&obligation)
                     });
 
diff --git a/compiler/rustc_const_eval/src/transform/check_consts/qualifs.rs b/compiler/rustc_const_eval/src/transform/check_consts/qualifs.rs
index 43612292f52..abc5a3c6a52 100644
--- a/compiler/rustc_const_eval/src/transform/check_consts/qualifs.rs
+++ b/compiler/rustc_const_eval/src/transform/check_consts/qualifs.rs
@@ -3,6 +3,7 @@
 //! See the `Qualif` trait for more info.
 
 use rustc_errors::ErrorReported;
+use rustc_hir as hir;
 use rustc_infer::infer::TyCtxtInferExt;
 use rustc_middle::mir::*;
 use rustc_middle::ty::{self, subst::SubstsRef, AdtDef, Ty};
@@ -166,7 +167,7 @@ impl Qualif for NeedsNonConstDrop {
         );
 
         let implsrc = cx.tcx.infer_ctxt().enter(|infcx| {
-            let mut selcx = SelectionContext::new(&infcx);
+            let mut selcx = SelectionContext::with_constness(&infcx, hir::Constness::Const);
             selcx.select(&obligation)
         });
         !matches!(
diff --git a/compiler/rustc_const_eval/src/transform/check_consts/resolver.rs b/compiler/rustc_const_eval/src/transform/check_consts/resolver.rs
index b70b38754c9..249b4ea0602 100644
--- a/compiler/rustc_const_eval/src/transform/check_consts/resolver.rs
+++ b/compiler/rustc_const_eval/src/transform/check_consts/resolver.rs
@@ -7,6 +7,7 @@ use rustc_middle::mir::visit::Visitor;
 use rustc_middle::mir::{self, BasicBlock, Local, Location, Statement, StatementKind};
 use rustc_mir_dataflow::fmt::DebugWithContext;
 use rustc_mir_dataflow::JoinSemiLattice;
+use rustc_mir_dataflow::{Analysis, AnalysisDomain, CallReturnPlaces};
 use rustc_span::DUMMY_SP;
 
 use std::fmt;
@@ -80,18 +81,18 @@ where
     fn apply_call_return_effect(
         &mut self,
         _block: BasicBlock,
-        _func: &mir::Operand<'tcx>,
-        _args: &[mir::Operand<'tcx>],
-        return_place: mir::Place<'tcx>,
+        return_places: CallReturnPlaces<'_, 'tcx>,
     ) {
-        // We cannot reason about another function's internals, so use conservative type-based
-        // qualification for the result of a function call.
-        let return_ty = return_place.ty(self.ccx.body, self.ccx.tcx).ty;
-        let qualif = Q::in_any_value_of_ty(self.ccx, return_ty);
+        return_places.for_each(|place| {
+            // We cannot reason about another function's internals, so use conservative type-based
+            // qualification for the result of a function call.
+            let return_ty = place.ty(self.ccx.body, self.ccx.tcx).ty;
+            let qualif = Q::in_any_value_of_ty(self.ccx, return_ty);
 
-        if !return_place.is_indirect() {
-            self.assign_qualif_direct(&return_place, qualif);
-        }
+            if !place.is_indirect() {
+                self.assign_qualif_direct(&place, qualif);
+            }
+        });
     }
 
     fn address_of_allows_mutation(&self, _mt: mir::Mutability, _place: mir::Place<'tcx>) -> bool {
@@ -329,7 +330,7 @@ impl JoinSemiLattice for State {
     }
 }
 
-impl<Q> rustc_mir_dataflow::AnalysisDomain<'tcx> for FlowSensitiveAnalysis<'_, '_, 'tcx, Q>
+impl<Q> AnalysisDomain<'tcx> for FlowSensitiveAnalysis<'_, '_, 'tcx, Q>
 where
     Q: Qualif,
 {
@@ -349,7 +350,7 @@ where
     }
 }
 
-impl<Q> rustc_mir_dataflow::Analysis<'tcx> for FlowSensitiveAnalysis<'_, '_, 'tcx, Q>
+impl<Q> Analysis<'tcx> for FlowSensitiveAnalysis<'_, '_, 'tcx, Q>
 where
     Q: Qualif,
 {
@@ -375,10 +376,8 @@ where
         &self,
         state: &mut Self::Domain,
         block: BasicBlock,
-        func: &mir::Operand<'tcx>,
-        args: &[mir::Operand<'tcx>],
-        return_place: mir::Place<'tcx>,
+        return_places: CallReturnPlaces<'_, 'tcx>,
     ) {
-        self.transfer_function(state).apply_call_return_effect(block, func, args, return_place)
+        self.transfer_function(state).apply_call_return_effect(block, return_places)
     }
 }
diff --git a/compiler/rustc_const_eval/src/transform/promote_consts.rs b/compiler/rustc_const_eval/src/transform/promote_consts.rs
index 464155db89f..3c06074a1b3 100644
--- a/compiler/rustc_const_eval/src/transform/promote_consts.rs
+++ b/compiler/rustc_const_eval/src/transform/promote_consts.rs
@@ -41,6 +41,10 @@ pub struct PromoteTemps<'tcx> {
 }
 
 impl<'tcx> MirPass<'tcx> for PromoteTemps<'tcx> {
+    fn phase_change(&self) -> Option<MirPhase> {
+        Some(MirPhase::ConstPromotion)
+    }
+
     fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
         // There's not really any point in promoting errorful MIR.
         //
diff --git a/compiler/rustc_const_eval/src/transform/validate.rs b/compiler/rustc_const_eval/src/transform/validate.rs
index b4bb6390db4..448a04f76b1 100644
--- a/compiler/rustc_const_eval/src/transform/validate.rs
+++ b/compiler/rustc_const_eval/src/transform/validate.rs
@@ -495,10 +495,13 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> {
                     self.check_edge(location, *unwind, EdgeKind::Unwind);
                 }
             }
-            TerminatorKind::InlineAsm { destination, .. } => {
+            TerminatorKind::InlineAsm { destination, cleanup, .. } => {
                 if let Some(destination) = destination {
                     self.check_edge(location, *destination, EdgeKind::Normal);
                 }
+                if let Some(cleanup) = cleanup {
+                    self.check_edge(location, *cleanup, EdgeKind::Unwind);
+                }
             }
             // Nothing to validate for these.
             TerminatorKind::Resume
diff --git a/compiler/rustc_data_structures/src/functor.rs b/compiler/rustc_data_structures/src/functor.rs
index 9e1497961d9..71ff762c714 100644
--- a/compiler/rustc_data_structures/src/functor.rs
+++ b/compiler/rustc_data_structures/src/functor.rs
@@ -23,11 +23,9 @@ impl<T> IdFunctor for Box<T> {
             let value = raw.read();
             // SAFETY: Converts `Box<T>` to `Box<MaybeUninit<T>>` which is the
             // inverse of `Box::assume_init()` and should be safe.
-            let mut raw: Box<mem::MaybeUninit<T>> = Box::from_raw(raw.cast());
+            let raw: Box<mem::MaybeUninit<T>> = Box::from_raw(raw.cast());
             // SAFETY: Write the mapped value back into the `Box`.
-            raw.write(f(value)?);
-            // SAFETY: We just initialized `raw`.
-            raw.assume_init()
+            Box::write(raw, f(value)?)
         })
     }
 }
diff --git a/compiler/rustc_expand/src/mbe/macro_rules.rs b/compiler/rustc_expand/src/mbe/macro_rules.rs
index f8491654f39..537a10e98e5 100644
--- a/compiler/rustc_expand/src/mbe/macro_rules.rs
+++ b/compiler/rustc_expand/src/mbe/macro_rules.rs
@@ -1027,6 +1027,24 @@ fn check_matcher_core(
                                 ),
                             );
                             err.span_label(sp, format!("not allowed after `{}` fragments", kind));
+
+                            if kind == NonterminalKind::PatWithOr
+                                && sess.edition == Edition::Edition2021
+                                && next_token.is_token(&BinOp(token::BinOpToken::Or))
+                            {
+                                let suggestion = quoted_tt_to_string(&TokenTree::MetaVarDecl(
+                                    span,
+                                    name,
+                                    Some(NonterminalKind::PatParam { inferred: false }),
+                                ));
+                                err.span_suggestion(
+                                    span,
+                                    &format!("try a `pat_param` fragment specifier instead"),
+                                    suggestion,
+                                    Applicability::MaybeIncorrect,
+                                );
+                            }
+
                             let msg = "allowed there are: ";
                             match possible {
                                 &[] => {}
diff --git a/compiler/rustc_feature/src/active.rs b/compiler/rustc_feature/src/active.rs
index 7860f92f96f..640c4bba6da 100644
--- a/compiler/rustc_feature/src/active.rs
+++ b/compiler/rustc_feature/src/active.rs
@@ -290,6 +290,8 @@ declare_features! (
     (active, asm_experimental_arch, "1.58.0", Some(72016), None),
     /// Allows using `sym` operands in inline assembly.
     (active, asm_sym, "1.58.0", Some(72016), None),
+    /// Allows the `may_unwind` option in inline assembly.
+    (active, asm_unwind, "1.58.0", Some(72016), None),
     /// Allows the user of associated type bounds.
     (active, associated_type_bounds, "1.34.0", Some(52662), None),
     /// Allows associated type defaults.
diff --git a/compiler/rustc_hir/src/hir.rs b/compiler/rustc_hir/src/hir.rs
index 61a96564a4c..487ae87052b 100644
--- a/compiler/rustc_hir/src/hir.rs
+++ b/compiler/rustc_hir/src/hir.rs
@@ -17,8 +17,7 @@ use rustc_index::vec::IndexVec;
 use rustc_macros::HashStable_Generic;
 use rustc_span::source_map::Spanned;
 use rustc_span::symbol::{kw, sym, Ident, Symbol};
-use rustc_span::{def_id::LocalDefId, BytePos};
-use rustc_span::{MultiSpan, Span, DUMMY_SP};
+use rustc_span::{def_id::LocalDefId, BytePos, MultiSpan, Span, DUMMY_SP};
 use rustc_target::asm::InlineAsmRegOrRegClass;
 use rustc_target::spec::abi::Abi;
 
@@ -526,12 +525,20 @@ pub struct GenericParam<'hir> {
 }
 
 impl GenericParam<'hir> {
-    pub fn bounds_span(&self) -> Option<Span> {
-        self.bounds.iter().fold(None, |span, bound| {
-            let span = span.map(|s| s.to(bound.span())).unwrap_or_else(|| bound.span());
-
-            Some(span)
-        })
+    pub fn bounds_span_for_suggestions(&self) -> Option<Span> {
+        self.bounds
+            .iter()
+            .fold(None, |span: Option<Span>, bound| {
+                // We include bounds that come from a `#[derive(_)]` but point at the user's code,
+                // as we use this method to get a span appropriate for suggestions.
+                if !bound.span().can_be_used_for_suggestions() {
+                    None
+                } else {
+                    let span = span.map(|s| s.to(bound.span())).unwrap_or_else(|| bound.span());
+                    Some(span)
+                }
+            })
+            .map(|sp| sp.shrink_to_hi())
     }
 }
 
@@ -3230,6 +3237,31 @@ impl<'hir> Node<'hir> {
         }
     }
 
+    /// Returns `Constness::Const` when this node is a const fn/impl/item.
+    pub fn constness_for_typeck(&self) -> Constness {
+        match self {
+            Node::Item(Item {
+                kind: ItemKind::Fn(FnSig { header: FnHeader { constness, .. }, .. }, ..),
+                ..
+            })
+            | Node::TraitItem(TraitItem {
+                kind: TraitItemKind::Fn(FnSig { header: FnHeader { constness, .. }, .. }, ..),
+                ..
+            })
+            | Node::ImplItem(ImplItem {
+                kind: ImplItemKind::Fn(FnSig { header: FnHeader { constness, .. }, .. }, ..),
+                ..
+            })
+            | Node::Item(Item { kind: ItemKind::Impl(Impl { constness, .. }), .. }) => *constness,
+
+            Node::Item(Item { kind: ItemKind::Const(..), .. })
+            | Node::TraitItem(TraitItem { kind: TraitItemKind::Const(..), .. })
+            | Node::ImplItem(ImplItem { kind: ImplItemKind::Const(..), .. }) => Constness::Const,
+
+            _ => Constness::NotConst,
+        }
+    }
+
     pub fn as_owner(self) -> Option<OwnerNode<'hir>> {
         match self {
             Node::Item(i) => Some(OwnerNode::Item(i)),
diff --git a/compiler/rustc_hir/src/lang_items.rs b/compiler/rustc_hir/src/lang_items.rs
index 05659e976dd..a03c561861e 100644
--- a/compiler/rustc_hir/src/lang_items.rs
+++ b/compiler/rustc_hir/src/lang_items.rs
@@ -348,6 +348,7 @@ language_item_table! {
     ControlFlowContinue,     sym::Continue,            cf_continue_variant,        Target::Variant,        GenericRequirement::None;
     ControlFlowBreak,        sym::Break,               cf_break_variant,           Target::Variant,        GenericRequirement::None;
 
+    IntoFutureIntoFuture,    sym::into_future,         into_future_fn,             Target::Method(MethodKind::Trait { body: false }), GenericRequirement::None;
     IntoIterIntoIter,        sym::into_iter,           into_iter_fn,               Target::Method(MethodKind::Trait { body: false }), GenericRequirement::None;
     IteratorNext,            sym::next,                next_fn,                    Target::Method(MethodKind::Trait { body: false}), GenericRequirement::None;
 
diff --git a/compiler/rustc_hir_pretty/src/lib.rs b/compiler/rustc_hir_pretty/src/lib.rs
index 9c2927111a6..18bc5bb64d6 100644
--- a/compiler/rustc_hir_pretty/src/lib.rs
+++ b/compiler/rustc_hir_pretty/src/lib.rs
@@ -1433,6 +1433,9 @@ impl<'a> State<'a> {
                 if opts.contains(ast::InlineAsmOptions::RAW) {
                     options.push("raw");
                 }
+                if opts.contains(ast::InlineAsmOptions::MAY_UNWIND) {
+                    options.push("may_unwind");
+                }
                 s.commasep(Inconsistent, &options, |s, &opt| {
                     s.word(opt);
                 });
diff --git a/compiler/rustc_infer/src/infer/error_reporting/need_type_info.rs b/compiler/rustc_infer/src/infer/error_reporting/need_type_info.rs
index a7e019a53ee..32c02033dc9 100644
--- a/compiler/rustc_infer/src/infer/error_reporting/need_type_info.rs
+++ b/compiler/rustc_infer/src/infer/error_reporting/need_type_info.rs
@@ -1,5 +1,6 @@
 use crate::infer::type_variable::TypeVariableOriginKind;
 use crate::infer::InferCtxt;
+use crate::rustc_middle::ty::TypeFoldable;
 use rustc_errors::{pluralize, struct_span_err, Applicability, DiagnosticBuilder};
 use rustc_hir as hir;
 use rustc_hir::def::{DefKind, Namespace};
@@ -400,36 +401,75 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
                 }
             }
             GenericArgKind::Const(ct) => {
-                if let ty::ConstKind::Infer(InferConst::Var(vid)) = ct.val {
-                    let origin =
-                        self.inner.borrow_mut().const_unification_table().probe_value(vid).origin;
-                    if let ConstVariableOriginKind::ConstParameterDefinition(name, def_id) =
-                        origin.kind
-                    {
-                        return InferenceDiagnosticsData {
-                            name: name.to_string(),
+                match ct.val {
+                    ty::ConstKind::Infer(InferConst::Var(vid)) => {
+                        let origin = self
+                            .inner
+                            .borrow_mut()
+                            .const_unification_table()
+                            .probe_value(vid)
+                            .origin;
+                        if let ConstVariableOriginKind::ConstParameterDefinition(name, def_id) =
+                            origin.kind
+                        {
+                            return InferenceDiagnosticsData {
+                                name: name.to_string(),
+                                span: Some(origin.span),
+                                kind: UnderspecifiedArgKind::Const { is_parameter: true },
+                                parent: InferenceDiagnosticsParentData::for_def_id(
+                                    self.tcx, def_id,
+                                ),
+                            };
+                        }
+
+                        debug_assert!(!origin.span.is_dummy());
+                        let mut s = String::new();
+                        let mut printer =
+                            ty::print::FmtPrinter::new(self.tcx, &mut s, Namespace::ValueNS);
+                        if let Some(highlight) = highlight {
+                            printer.region_highlight_mode = highlight;
+                        }
+                        let _ = ct.print(printer);
+                        InferenceDiagnosticsData {
+                            name: s,
                             span: Some(origin.span),
-                            kind: UnderspecifiedArgKind::Const { is_parameter: true },
-                            parent: InferenceDiagnosticsParentData::for_def_id(self.tcx, def_id),
-                        };
+                            kind: UnderspecifiedArgKind::Const { is_parameter: false },
+                            parent: None,
+                        }
                     }
-
-                    debug_assert!(!origin.span.is_dummy());
-                    let mut s = String::new();
-                    let mut printer =
-                        ty::print::FmtPrinter::new(self.tcx, &mut s, Namespace::ValueNS);
-                    if let Some(highlight) = highlight {
-                        printer.region_highlight_mode = highlight;
+                    ty::ConstKind::Unevaluated(ty::Unevaluated {
+                        substs_: Some(substs), ..
+                    }) => {
+                        assert!(substs.has_infer_types_or_consts());
+
+                        // FIXME: We only use the first inference variable we encounter in
+                        // `substs` here, this gives insufficiently informative diagnostics
+                        // in case there are multiple inference variables
+                        for s in substs.iter() {
+                            match s.unpack() {
+                                GenericArgKind::Type(t) => match t.kind() {
+                                    ty::Infer(_) => {
+                                        return self.extract_inference_diagnostics_data(s, None);
+                                    }
+                                    _ => {}
+                                },
+                                GenericArgKind::Const(c) => match c.val {
+                                    ty::ConstKind::Infer(InferConst::Var(_)) => {
+                                        return self.extract_inference_diagnostics_data(s, None);
+                                    }
+                                    _ => {}
+                                },
+                                _ => {}
+                            }
+                        }
+                        bug!(
+                            "expected an inference variable in substs of unevaluated const {:?}",
+                            ct
+                        );
                     }
-                    let _ = ct.print(printer);
-                    InferenceDiagnosticsData {
-                        name: s,
-                        span: Some(origin.span),
-                        kind: UnderspecifiedArgKind::Const { is_parameter: false },
-                        parent: None,
+                    _ => {
+                        bug!("unexpect const: {:?}", ct);
                     }
-                } else {
-                    bug!("unexpect const: {:?}", ct);
                 }
             }
             GenericArgKind::Lifetime(_) => bug!("unexpected lifetime"),
diff --git a/compiler/rustc_infer/src/infer/mod.rs b/compiler/rustc_infer/src/infer/mod.rs
index 2fd01c2d595..48dfa0b6342 100644
--- a/compiler/rustc_infer/src/infer/mod.rs
+++ b/compiler/rustc_infer/src/infer/mod.rs
@@ -21,6 +21,7 @@ use rustc_hir::def_id::{DefId, LocalDefId};
 use rustc_middle::infer::canonical::{Canonical, CanonicalVarValues};
 use rustc_middle::infer::unify_key::{ConstVarValue, ConstVariableValue};
 use rustc_middle::infer::unify_key::{ConstVariableOrigin, ConstVariableOriginKind, ToType};
+use rustc_middle::mir::interpret::ErrorHandled;
 use rustc_middle::mir::interpret::EvalToConstValueResult;
 use rustc_middle::traits::select;
 use rustc_middle::ty::error::{ExpectedFound, TypeError};
@@ -1584,13 +1585,27 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
         unevaluated: ty::Unevaluated<'tcx>,
         span: Option<Span>,
     ) -> EvalToConstValueResult<'tcx> {
-        let mut original_values = OriginalQueryValues::default();
-        let canonical = self.canonicalize_query((param_env, unevaluated), &mut original_values);
+        let mut substs = unevaluated.substs(self.tcx);
+        substs = self.resolve_vars_if_possible(substs);
+
+        // Postpone the evaluation of constants whose substs depend on inference
+        // variables
+        if substs.has_infer_types_or_consts() {
+            return Err(ErrorHandled::TooGeneric);
+        }
+
+        let param_env_erased = self.tcx.erase_regions(param_env);
+        let substs_erased = self.tcx.erase_regions(substs);
+
+        let unevaluated = ty::Unevaluated {
+            def: unevaluated.def,
+            substs_: Some(substs_erased),
+            promoted: unevaluated.promoted,
+        };
 
-        let (param_env, unevaluated) = canonical.value;
         // The return value is the evaluated value which doesn't contain any reference to inference
         // variables, thus we don't need to substitute back the original values.
-        self.tcx.const_eval_resolve(param_env, unevaluated, span)
+        self.tcx.const_eval_resolve(param_env_erased, unevaluated, span)
     }
 
     /// If `typ` is a type variable of some kind, resolve it one level
diff --git a/compiler/rustc_infer/src/traits/engine.rs b/compiler/rustc_infer/src/traits/engine.rs
index 822f2365e02..152a395c871 100644
--- a/compiler/rustc_infer/src/traits/engine.rs
+++ b/compiler/rustc_infer/src/traits/engine.rs
@@ -1,8 +1,9 @@
 use crate::infer::InferCtxt;
 use crate::traits::Obligation;
 use rustc_data_structures::fx::FxHashMap;
+use rustc_hir as hir;
 use rustc_hir::def_id::DefId;
-use rustc_middle::ty::{self, ToPredicate, Ty};
+use rustc_middle::ty::{self, ToPredicate, Ty, WithConstness};
 
 use super::FulfillmentError;
 use super::{ObligationCause, PredicateObligation};
@@ -47,9 +48,26 @@ pub trait TraitEngine<'tcx>: 'tcx {
 
     fn select_all_or_error(&mut self, infcx: &InferCtxt<'_, 'tcx>) -> Vec<FulfillmentError<'tcx>>;
 
+    fn select_all_with_constness_or_error(
+        &mut self,
+        infcx: &InferCtxt<'_, 'tcx>,
+        _constness: hir::Constness,
+    ) -> Vec<FulfillmentError<'tcx>> {
+        self.select_all_or_error(infcx)
+    }
+
     fn select_where_possible(&mut self, infcx: &InferCtxt<'_, 'tcx>)
     -> Vec<FulfillmentError<'tcx>>;
 
+    // FIXME(fee1-dead) this should not provide a default body for chalk as chalk should be updated
+    fn select_with_constness_where_possible(
+        &mut self,
+        infcx: &InferCtxt<'_, 'tcx>,
+        _constness: hir::Constness,
+    ) -> Vec<FulfillmentError<'tcx>> {
+        self.select_where_possible(infcx)
+    }
+
     fn pending_obligations(&self) -> Vec<PredicateObligation<'tcx>>;
 
     fn relationships(&mut self) -> &mut FxHashMap<ty::TyVid, ty::FoundRelationships>;
diff --git a/compiler/rustc_infer/src/traits/mod.rs b/compiler/rustc_infer/src/traits/mod.rs
index 7e30f859dae..e8622b3c819 100644
--- a/compiler/rustc_infer/src/traits/mod.rs
+++ b/compiler/rustc_infer/src/traits/mod.rs
@@ -69,16 +69,6 @@ impl PredicateObligation<'tcx> {
     }
 }
 
-impl TraitObligation<'tcx> {
-    /// Returns `true` if the trait predicate is considered `const` in its ParamEnv.
-    pub fn is_const(&self) -> bool {
-        match (self.predicate.skip_binder().constness, self.param_env.constness()) {
-            (ty::BoundConstness::ConstIfConst, hir::Constness::Const) => true,
-            _ => false,
-        }
-    }
-}
-
 // `PredicateObligation` is used a lot. Make sure it doesn't unintentionally get bigger.
 #[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))]
 static_assert_size!(PredicateObligation<'_>, 32);
diff --git a/compiler/rustc_infer/src/traits/util.rs b/compiler/rustc_infer/src/traits/util.rs
index 61588147364..92f74af4eb3 100644
--- a/compiler/rustc_infer/src/traits/util.rs
+++ b/compiler/rustc_infer/src/traits/util.rs
@@ -3,7 +3,7 @@ use smallvec::smallvec;
 use crate::infer::outlives::components::{push_outlives_components, Component};
 use crate::traits::{Obligation, ObligationCause, PredicateObligation};
 use rustc_data_structures::fx::{FxHashSet, FxIndexSet};
-use rustc_middle::ty::{self, ToPredicate, TyCtxt};
+use rustc_middle::ty::{self, ToPredicate, TyCtxt, WithConstness};
 use rustc_span::symbol::Ident;
 use rustc_span::Span;
 
@@ -328,8 +328,8 @@ pub fn transitive_bounds_that_define_assoc_type<'tcx>(
                 ));
                 for (super_predicate, _) in super_predicates.predicates {
                     let subst_predicate = super_predicate.subst_supertrait(tcx, &trait_ref);
-                    if let Some(binder) = subst_predicate.to_opt_poly_trait_pred() {
-                        stack.push(binder.map_bound(|t| t.trait_ref));
+                    if let Some(binder) = subst_predicate.to_opt_poly_trait_ref() {
+                        stack.push(binder.value);
                     }
                 }
 
@@ -362,8 +362,8 @@ impl<'tcx, I: Iterator<Item = PredicateObligation<'tcx>>> Iterator for FilterToT
 
     fn next(&mut self) -> Option<ty::PolyTraitRef<'tcx>> {
         while let Some(obligation) = self.base_iterator.next() {
-            if let Some(data) = obligation.predicate.to_opt_poly_trait_pred() {
-                return Some(data.map_bound(|t| t.trait_ref));
+            if let Some(data) = obligation.predicate.to_opt_poly_trait_ref() {
+                return Some(data.value);
             }
         }
         None
diff --git a/compiler/rustc_lexer/src/cursor.rs b/compiler/rustc_lexer/src/cursor.rs
index 297f3d19ca1..0ba6c56dbb5 100644
--- a/compiler/rustc_lexer/src/cursor.rs
+++ b/compiler/rustc_lexer/src/cursor.rs
@@ -2,10 +2,11 @@ use std::str::Chars;
 
 /// Peekable iterator over a char sequence.
 ///
-/// Next characters can be peeked via `nth_char` method,
+/// Next characters can be peeked via `first` method,
 /// and position can be shifted forward via `bump` method.
 pub(crate) struct Cursor<'a> {
     initial_len: usize,
+    /// Iterator over chars. Slightly faster than a &str.
     chars: Chars<'a>,
     #[cfg(debug_assertions)]
     prev: char,
@@ -37,22 +38,21 @@ impl<'a> Cursor<'a> {
         }
     }
 
-    /// Returns nth character relative to the current cursor position.
+    /// Peeks the next symbol from the input stream without consuming it.
     /// If requested position doesn't exist, `EOF_CHAR` is returned.
     /// However, getting `EOF_CHAR` doesn't always mean actual end of file,
     /// it should be checked with `is_eof` method.
-    fn nth_char(&self, n: usize) -> char {
-        self.chars().nth(n).unwrap_or(EOF_CHAR)
-    }
-
-    /// Peeks the next symbol from the input stream without consuming it.
     pub(crate) fn first(&self) -> char {
-        self.nth_char(0)
+        // `.next()` optimizes better than `.nth(0)`
+        self.chars.clone().next().unwrap_or(EOF_CHAR)
     }
 
     /// Peeks the second symbol from the input stream without consuming it.
     pub(crate) fn second(&self) -> char {
-        self.nth_char(1)
+        // `.next()` optimizes better than `.nth(1)`
+        let mut iter = self.chars.clone();
+        iter.next();
+        iter.next().unwrap_or(EOF_CHAR)
     }
 
     /// Checks if there is nothing more to consume.
@@ -65,9 +65,9 @@ impl<'a> Cursor<'a> {
         self.initial_len - self.chars.as_str().len()
     }
 
-    /// Returns a `Chars` iterator over the remaining characters.
-    fn chars(&self) -> Chars<'a> {
-        self.chars.clone()
+    /// Resets the number of bytes consumed to 0.
+    pub(crate) fn reset_len_consumed(&mut self) {
+        self.initial_len = self.chars.as_str().len();
     }
 
     /// Moves to the next character.
@@ -81,4 +81,13 @@ impl<'a> Cursor<'a> {
 
         Some(c)
     }
+
+    /// Eats symbols while predicate returns true or until the end of file is reached.
+    pub(crate) fn eat_while(&mut self, mut predicate: impl FnMut(char) -> bool) {
+        // It was tried making optimized version of this for eg. line comments, but
+        // LLVM can inline all of this and compile it down to fast iteration over bytes.
+        while predicate(self.first()) && !self.is_eof() {
+            self.bump();
+        }
+    }
 }
diff --git a/compiler/rustc_lexer/src/lib.rs b/compiler/rustc_lexer/src/lib.rs
index 44b002fa93f..5b8300ab530 100644
--- a/compiler/rustc_lexer/src/lib.rs
+++ b/compiler/rustc_lexer/src/lib.rs
@@ -227,14 +227,15 @@ pub fn first_token(input: &str) -> Token {
 }
 
 /// Creates an iterator that produces tokens from the input string.
-pub fn tokenize(mut input: &str) -> impl Iterator<Item = Token> + '_ {
+pub fn tokenize(input: &str) -> impl Iterator<Item = Token> + '_ {
+    let mut cursor = Cursor::new(input);
     std::iter::from_fn(move || {
-        if input.is_empty() {
-            return None;
+        if cursor.is_eof() {
+            None
+        } else {
+            cursor.reset_len_consumed();
+            Some(cursor.advance_token())
         }
-        let token = first_token(input);
-        input = &input[token.len..];
-        Some(token)
     })
 }
 
@@ -832,11 +833,4 @@ impl Cursor<'_> {
 
         self.eat_while(is_id_continue);
     }
-
-    /// Eats symbols while predicate returns true or until the end of file is reached.
-    fn eat_while(&mut self, mut predicate: impl FnMut(char) -> bool) {
-        while predicate(self.first()) && !self.is_eof() {
-            self.bump();
-        }
-    }
 }
diff --git a/compiler/rustc_lint/src/array_into_iter.rs b/compiler/rustc_lint/src/array_into_iter.rs
index d8883b0e66d..4a24f803e84 100644
--- a/compiler/rustc_lint/src/array_into_iter.rs
+++ b/compiler/rustc_lint/src/array_into_iter.rs
@@ -79,9 +79,8 @@ impl<'tcx> LateLintPass<'tcx> for ArrayIntoIter {
             let receiver_ty = cx.typeck_results().expr_ty(receiver_arg);
             let adjustments = cx.typeck_results().expr_adjustments(receiver_arg);
 
-            let target = match adjustments.last() {
-                Some(Adjustment { kind: Adjust::Borrow(_), target }) => target,
-                _ => return,
+            let Some(Adjustment { kind: Adjust::Borrow(_), target }) = adjustments.last() else {
+                return
             };
 
             let types =
diff --git a/compiler/rustc_lint/src/builtin.rs b/compiler/rustc_lint/src/builtin.rs
index 077d3e1c820..5dbcc1655c9 100644
--- a/compiler/rustc_lint/src/builtin.rs
+++ b/compiler/rustc_lint/src/builtin.rs
@@ -609,14 +609,12 @@ impl<'tcx> LateLintPass<'tcx> for MissingDoc {
                 // If the trait is private, add the impl items to `private_traits` so they don't get
                 // reported for missing docs.
                 let real_trait = trait_ref.path.res.def_id();
-                if let Some(def_id) = real_trait.as_local() {
-                    let hir_id = cx.tcx.hir().local_def_id_to_hir_id(def_id);
-                    if let Some(Node::Item(item)) = cx.tcx.hir().find(hir_id) {
-                        if let hir::VisibilityKind::Inherited = item.vis.node {
-                            for impl_item_ref in items {
-                                self.private_traits.insert(impl_item_ref.id.hir_id());
-                            }
-                        }
+                let Some(def_id) = real_trait.as_local() else { return };
+                let hir_id = cx.tcx.hir().local_def_id_to_hir_id(def_id);
+                let Some(Node::Item(item)) = cx.tcx.hir().find(hir_id) else { return };
+                if let hir::VisibilityKind::Inherited = item.vis.node {
+                    for impl_item_ref in items {
+                        self.private_traits.insert(impl_item_ref.id.hir_id());
                     }
                 }
                 return;
@@ -829,9 +827,8 @@ impl<'tcx> LateLintPass<'tcx> for MissingDebugImplementations {
             _ => return,
         }
 
-        let debug = match cx.tcx.get_diagnostic_item(sym::Debug) {
-            Some(debug) => debug,
-            None => return,
+        let Some(debug) = cx.tcx.get_diagnostic_item(sym::Debug) else {
+            return
         };
 
         if self.impling_types.is_none() {
@@ -1509,9 +1506,8 @@ impl TypeAliasBounds {
 
 impl<'tcx> LateLintPass<'tcx> for TypeAliasBounds {
     fn check_item(&mut self, cx: &LateContext<'_>, item: &hir::Item<'_>) {
-        let (ty, type_alias_generics) = match item.kind {
-            hir::ItemKind::TyAlias(ref ty, ref generics) => (&*ty, generics),
-            _ => return,
+        let hir::ItemKind::TyAlias(ty, type_alias_generics) = &item.kind else {
+            return
         };
         if let hir::TyKind::OpaqueDef(..) = ty.kind {
             // Bounds are respected for `type X = impl Trait`
@@ -2266,16 +2262,15 @@ impl<'tcx> LateLintPass<'tcx> for ExplicitOutlivesRequirements {
                         // and should check for them here.
                         match predicate.bounded_ty.kind {
                             hir::TyKind::Path(hir::QPath::Resolved(None, ref path)) => {
-                                if let Res::Def(DefKind::TyParam, def_id) = path.res {
-                                    let index = ty_generics.param_def_id_to_index[&def_id];
-                                    (
-                                        Self::lifetimes_outliving_type(inferred_outlives, index),
-                                        &predicate.bounds,
-                                        predicate.span,
-                                    )
-                                } else {
-                                    continue;
-                                }
+                                let Res::Def(DefKind::TyParam, def_id) = path.res else {
+                                    continue
+                                };
+                                let index = ty_generics.param_def_id_to_index[&def_id];
+                                (
+                                    Self::lifetimes_outliving_type(inferred_outlives, index),
+                                    &predicate.bounds,
+                                    predicate.span,
+                                )
                             }
                             _ => {
                                 continue;
@@ -3216,18 +3211,17 @@ impl<'tcx> LateLintPass<'tcx> for NamedAsmLabels {
                     for (idx, _) in statement.match_indices(':') {
                         let possible_label = statement[start_idx..idx].trim();
                         let mut chars = possible_label.chars();
-                        if let Some(c) = chars.next() {
-                            // A label starts with an alphabetic character or . or _ and continues with alphanumeric characters, _, or $
-                            if (c.is_alphabetic() || matches!(c, '.' | '_'))
-                                && chars.all(|c| c.is_alphanumeric() || matches!(c, '_' | '$'))
-                            {
-                                found_labels.push(possible_label);
-                            } else {
-                                // If we encounter a non-label, there cannot be any further labels, so stop checking
-                                break;
-                            }
-                        } else {
+                        let Some(c) = chars.next() else {
                             // Empty string means a leading ':' in this section, which is not a label
+                            break
+                        };
+                        // A label starts with an alphabetic character or . or _ and continues with alphanumeric characters, _, or $
+                        if (c.is_alphabetic() || matches!(c, '.' | '_'))
+                            && chars.all(|c| c.is_alphanumeric() || matches!(c, '_' | '$'))
+                        {
+                            found_labels.push(possible_label);
+                        } else {
+                            // If we encounter a non-label, there cannot be any further labels, so stop checking
                             break;
                         }
 
diff --git a/compiler/rustc_lint/src/levels.rs b/compiler/rustc_lint/src/levels.rs
index b6d66eb12d0..485728cbfd3 100644
--- a/compiler/rustc_lint/src/levels.rs
+++ b/compiler/rustc_lint/src/levels.rs
@@ -227,14 +227,12 @@ impl<'s> LintLevelsBuilder<'s> {
         let sess = self.sess;
         let bad_attr = |span| struct_span_err!(sess, span, E0452, "malformed lint attribute input");
         for attr in attrs {
-            let level = match Level::from_symbol(attr.name_or_empty()) {
-                None => continue,
-                Some(lvl) => lvl,
+            let Some(level) = Level::from_symbol(attr.name_or_empty()) else {
+                continue
             };
 
-            let mut metas = match attr.meta_item_list() {
-                Some(x) => x,
-                None => continue,
+            let Some(mut metas) = attr.meta_item_list() else {
+                continue
             };
 
             if metas.is_empty() {
@@ -481,9 +479,8 @@ impl<'s> LintLevelsBuilder<'s> {
                     continue;
                 }
 
-                let (lint_attr_name, lint_attr_span) = match *src {
-                    LintLevelSource::Node(name, span, _) => (name, span),
-                    _ => continue,
+                let LintLevelSource::Node(lint_attr_name, lint_attr_span, _) = *src else {
+                    continue
                 };
 
                 let lint = builtin::UNUSED_ATTRIBUTES;
diff --git a/compiler/rustc_lint/src/noop_method_call.rs b/compiler/rustc_lint/src/noop_method_call.rs
index a3a3cd0077d..600504f7c12 100644
--- a/compiler/rustc_lint/src/noop_method_call.rs
+++ b/compiler/rustc_lint/src/noop_method_call.rs
@@ -40,9 +40,8 @@ declare_lint_pass!(NoopMethodCall => [NOOP_METHOD_CALL]);
 impl<'tcx> LateLintPass<'tcx> for NoopMethodCall {
     fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
         // We only care about method calls.
-        let (call, elements) = match expr.kind {
-            ExprKind::MethodCall(call, _, elements, _) => (call, elements),
-            _ => return,
+        let ExprKind::MethodCall(call, _, elements, _) = &expr.kind else {
+            return
         };
         // We only care about method calls corresponding to the `Clone`, `Deref` and `Borrow`
         // traits and ignore any other method call.
@@ -70,9 +69,8 @@ impl<'tcx> LateLintPass<'tcx> for NoopMethodCall {
         }
         let param_env = cx.tcx.param_env(trait_id);
         // Resolve the trait method instance.
-        let i = match ty::Instance::resolve(cx.tcx, param_env, did, substs) {
-            Ok(Some(i)) => i,
-            _ => return,
+        let Ok(Some(i)) = ty::Instance::resolve(cx.tcx, param_env, did, substs) else {
+            return
         };
         // (Re)check that it implements the noop diagnostic.
         let Some(name) = cx.tcx.get_diagnostic_name(i.def_id()) else { return };
diff --git a/compiler/rustc_lint/src/traits.rs b/compiler/rustc_lint/src/traits.rs
index 5435ff1396d..dafff640b36 100644
--- a/compiler/rustc_lint/src/traits.rs
+++ b/compiler/rustc_lint/src/traits.rs
@@ -91,9 +91,8 @@ impl<'tcx> LateLintPass<'tcx> for DropTraitConstraints {
 
         let predicates = cx.tcx.explicit_predicates_of(item.def_id);
         for &(predicate, span) in predicates.predicates {
-            let trait_predicate = match predicate.kind().skip_binder() {
-                Trait(trait_predicate) => trait_predicate,
-                _ => continue,
+            let Trait(trait_predicate) = predicate.kind().skip_binder() else {
+                continue
             };
             if trait_predicate.constness == ty::BoundConstness::ConstIfConst {
                 // `~const Drop` definitely have meanings so avoid linting here.
@@ -106,9 +105,8 @@ impl<'tcx> LateLintPass<'tcx> for DropTraitConstraints {
                     continue;
                 }
                 cx.struct_span_lint(DROP_BOUNDS, span, |lint| {
-                    let needs_drop = match cx.tcx.get_diagnostic_item(sym::needs_drop) {
-                        Some(needs_drop) => needs_drop,
-                        None => return,
+                    let Some(needs_drop) = cx.tcx.get_diagnostic_item(sym::needs_drop) else {
+                        return
                     };
                     let msg = format!(
                         "bounds on `{}` are most likely incorrect, consider instead \
@@ -123,17 +121,15 @@ impl<'tcx> LateLintPass<'tcx> for DropTraitConstraints {
     }
 
     fn check_ty(&mut self, cx: &LateContext<'_>, ty: &'tcx hir::Ty<'tcx>) {
-        let bounds = match &ty.kind {
-            hir::TyKind::TraitObject(bounds, _lifetime, _syntax) => bounds,
-            _ => return,
+        let hir::TyKind::TraitObject(bounds, _lifetime, _syntax) = &ty.kind else {
+            return
         };
         for bound in &bounds[..] {
             let def_id = bound.trait_ref.trait_def_id();
             if cx.tcx.lang_items().drop_trait() == def_id {
                 cx.struct_span_lint(DYN_DROP, bound.span, |lint| {
-                    let needs_drop = match cx.tcx.get_diagnostic_item(sym::needs_drop) {
-                        Some(needs_drop) => needs_drop,
-                        None => return,
+                    let Some(needs_drop) = cx.tcx.get_diagnostic_item(sym::needs_drop) else {
+                        return
                     };
                     let msg = format!(
                         "types that do not implement `Drop` can still have drop glue, consider \
diff --git a/compiler/rustc_lint/src/types.rs b/compiler/rustc_lint/src/types.rs
index b20f7357b35..32ed6dad7f8 100644
--- a/compiler/rustc_lint/src/types.rs
+++ b/compiler/rustc_lint/src/types.rs
@@ -1342,11 +1342,10 @@ impl<'tcx> LateLintPass<'tcx> for VariantSizeDifferences {
                     | ty::layout::LayoutError::NormalizationFailure(_, _),
                 ) => return,
             };
-            let (variants, tag) = match layout.variants {
-                Variants::Multiple {
+            let Variants::Multiple {
                     tag_encoding: TagEncoding::Direct, tag, ref variants, ..
-                } => (variants, tag),
-                _ => return,
+                } = &layout.variants else {
+                return
             };
 
             let tag_size = tag.value.size(&cx.tcx).bytes();
diff --git a/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp b/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp
index 94d2a4b8e4c..3fbf020c552 100644
--- a/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp
+++ b/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp
@@ -445,11 +445,20 @@ extern "C" LLVMValueRef
 LLVMRustInlineAsm(LLVMTypeRef Ty, char *AsmString, size_t AsmStringLen,
                   char *Constraints, size_t ConstraintsLen,
                   LLVMBool HasSideEffects, LLVMBool IsAlignStack,
-                  LLVMRustAsmDialect Dialect) {
+                  LLVMRustAsmDialect Dialect, LLVMBool CanThrow) {
+#if LLVM_VERSION_GE(13, 0)
+  return wrap(InlineAsm::get(unwrap<FunctionType>(Ty),
+                             StringRef(AsmString, AsmStringLen),
+                             StringRef(Constraints, ConstraintsLen),
+                             HasSideEffects, IsAlignStack,
+                             fromRust(Dialect), CanThrow));
+#else
   return wrap(InlineAsm::get(unwrap<FunctionType>(Ty),
                              StringRef(AsmString, AsmStringLen),
                              StringRef(Constraints, ConstraintsLen),
-                             HasSideEffects, IsAlignStack, fromRust(Dialect)));
+                             HasSideEffects, IsAlignStack,
+                             fromRust(Dialect)));
+#endif
 }
 
 extern "C" bool LLVMRustInlineAsmVerify(LLVMTypeRef Ty, char *Constraints,
diff --git a/compiler/rustc_middle/src/hir/map/mod.rs b/compiler/rustc_middle/src/hir/map/mod.rs
index 394a1fc2270..5c4c2eee21f 100644
--- a/compiler/rustc_middle/src/hir/map/mod.rs
+++ b/compiler/rustc_middle/src/hir/map/mod.rs
@@ -474,8 +474,7 @@ impl<'hir> Map<'hir> {
     /// Panics if `LocalDefId` does not have an associated body.
     ///
     /// This should only be used for determining the context of a body, a return
-    /// value of `Some` does not always suggest that the owner of the body is `const`,
-    /// just that it has to be checked as if it were.
+    /// value of `Some` does not always suggest that the owner of the body is `const`.
     pub fn body_const_context(&self, did: LocalDefId) -> Option<ConstContext> {
         let hir_id = self.local_def_id_to_hir_id(did);
         let ccx = match self.body_owner_kind(hir_id) {
diff --git a/compiler/rustc_middle/src/lib.rs b/compiler/rustc_middle/src/lib.rs
index b67ad8b770e..66d1ae1420a 100644
--- a/compiler/rustc_middle/src/lib.rs
+++ b/compiler/rustc_middle/src/lib.rs
@@ -51,7 +51,6 @@
 #![feature(control_flow_enum)]
 #![feature(associated_type_defaults)]
 #![feature(iter_zip)]
-#![feature(thread_local_const_init)]
 #![feature(trusted_step)]
 #![feature(try_blocks)]
 #![feature(try_reserve_kind)]
diff --git a/compiler/rustc_middle/src/mir/interpret/queries.rs b/compiler/rustc_middle/src/mir/interpret/queries.rs
index f9831855633..c63613ae3af 100644
--- a/compiler/rustc_middle/src/mir/interpret/queries.rs
+++ b/compiler/rustc_middle/src/mir/interpret/queries.rs
@@ -64,7 +64,6 @@ impl<'tcx> TyCtxt<'tcx> {
         cid: GlobalId<'tcx>,
         span: Option<Span>,
     ) -> EvalToConstValueResult<'tcx> {
-        let param_env = param_env.with_const();
         // Const-eval shouldn't depend on lifetimes at all, so we can erase them, which should
         // improve caching of queries.
         let inputs = self.erase_regions(param_env.and(cid));
@@ -93,7 +92,6 @@ impl<'tcx> TyCtxt<'tcx> {
         gid: GlobalId<'tcx>,
         param_env: ty::ParamEnv<'tcx>,
     ) -> Result<&'tcx mir::Allocation, ErrorHandled> {
-        let param_env = param_env.with_const();
         trace!("eval_to_allocation: Need to compute {:?}", gid);
         let raw_const = self.eval_to_allocation_raw(param_env.and(gid))?;
         Ok(self.global_alloc(raw_const.alloc_id).unwrap_memory())
diff --git a/compiler/rustc_middle/src/mir/mod.rs b/compiler/rustc_middle/src/mir/mod.rs
index df36b2e4e0b..75edcaadfdf 100644
--- a/compiler/rustc_middle/src/mir/mod.rs
+++ b/compiler/rustc_middle/src/mir/mod.rs
@@ -16,6 +16,7 @@ use rustc_hir::def::{CtorKind, Namespace};
 use rustc_hir::def_id::{DefId, CRATE_DEF_INDEX};
 use rustc_hir::{self, GeneratorKind};
 use rustc_hir::{self as hir, HirId};
+use rustc_session::Session;
 use rustc_target::abi::{Size, VariantIdx};
 
 use polonius_engine::Atom;
@@ -99,7 +100,21 @@ pub trait MirPass<'tcx> {
         }
     }
 
+    /// Returns `true` if this pass is enabled with the current combination of compiler flags.
+    fn is_enabled(&self, _sess: &Session) -> bool {
+        true
+    }
+
     fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>);
+
+    /// If this pass causes the MIR to enter a new phase, return that phase.
+    fn phase_change(&self) -> Option<MirPhase> {
+        None
+    }
+
+    fn is_mir_dump_enabled(&self) -> bool {
+        true
+    }
 }
 
 /// The various "big phases" that MIR goes through.
diff --git a/compiler/rustc_middle/src/mir/terminator.rs b/compiler/rustc_middle/src/mir/terminator.rs
index e78b6fd092d..a82f98d28e7 100644
--- a/compiler/rustc_middle/src/mir/terminator.rs
+++ b/compiler/rustc_middle/src/mir/terminator.rs
@@ -260,6 +260,10 @@ pub enum TerminatorKind<'tcx> {
         /// Destination block after the inline assembly returns, unless it is
         /// diverging (InlineAsmOptions::NORETURN).
         destination: Option<BasicBlock>,
+
+        /// Cleanup to be done if the inline assembly unwinds. This is present
+        /// if and only if InlineAsmOptions::MAY_UNWIND is set.
+        cleanup: Option<BasicBlock>,
     },
 }
 #[derive(Clone, Debug, TyEncodable, TyDecodable, HashStable)]
@@ -309,7 +313,7 @@ impl<'tcx> TerminatorKind<'tcx> {
             | Return
             | Unreachable
             | Call { destination: None, cleanup: None, .. }
-            | InlineAsm { destination: None, .. } => None.into_iter().chain(&[]),
+            | InlineAsm { destination: None, cleanup: None, .. } => None.into_iter().chain(&[]),
             Goto { target: ref t }
             | Call { destination: None, cleanup: Some(ref t), .. }
             | Call { destination: Some((_, ref t)), cleanup: None, .. }
@@ -318,13 +322,17 @@ impl<'tcx> TerminatorKind<'tcx> {
             | Drop { target: ref t, unwind: None, .. }
             | Assert { target: ref t, cleanup: None, .. }
             | FalseUnwind { real_target: ref t, unwind: None }
-            | InlineAsm { destination: Some(ref t), .. } => Some(t).into_iter().chain(&[]),
+            | InlineAsm { destination: Some(ref t), cleanup: None, .. }
+            | InlineAsm { destination: None, cleanup: Some(ref t), .. } => {
+                Some(t).into_iter().chain(&[])
+            }
             Call { destination: Some((_, ref t)), cleanup: Some(ref u), .. }
             | Yield { resume: ref t, drop: Some(ref u), .. }
             | DropAndReplace { target: ref t, unwind: Some(ref u), .. }
             | Drop { target: ref t, unwind: Some(ref u), .. }
             | Assert { target: ref t, cleanup: Some(ref u), .. }
-            | FalseUnwind { real_target: ref t, unwind: Some(ref u) } => {
+            | FalseUnwind { real_target: ref t, unwind: Some(ref u) }
+            | InlineAsm { destination: Some(ref t), cleanup: Some(ref u), .. } => {
                 Some(t).into_iter().chain(slice::from_ref(u))
             }
             SwitchInt { ref targets, .. } => None.into_iter().chain(&targets.targets[..]),
@@ -343,7 +351,7 @@ impl<'tcx> TerminatorKind<'tcx> {
             | Return
             | Unreachable
             | Call { destination: None, cleanup: None, .. }
-            | InlineAsm { destination: None, .. } => None.into_iter().chain(&mut []),
+            | InlineAsm { destination: None, cleanup: None, .. } => None.into_iter().chain(&mut []),
             Goto { target: ref mut t }
             | Call { destination: None, cleanup: Some(ref mut t), .. }
             | Call { destination: Some((_, ref mut t)), cleanup: None, .. }
@@ -352,13 +360,17 @@ impl<'tcx> TerminatorKind<'tcx> {
             | Drop { target: ref mut t, unwind: None, .. }
             | Assert { target: ref mut t, cleanup: None, .. }
             | FalseUnwind { real_target: ref mut t, unwind: None }
-            | InlineAsm { destination: Some(ref mut t), .. } => Some(t).into_iter().chain(&mut []),
+            | InlineAsm { destination: Some(ref mut t), cleanup: None, .. }
+            | InlineAsm { destination: None, cleanup: Some(ref mut t), .. } => {
+                Some(t).into_iter().chain(&mut [])
+            }
             Call { destination: Some((_, ref mut t)), cleanup: Some(ref mut u), .. }
             | Yield { resume: ref mut t, drop: Some(ref mut u), .. }
             | DropAndReplace { target: ref mut t, unwind: Some(ref mut u), .. }
             | Drop { target: ref mut t, unwind: Some(ref mut u), .. }
             | Assert { target: ref mut t, cleanup: Some(ref mut u), .. }
-            | FalseUnwind { real_target: ref mut t, unwind: Some(ref mut u) } => {
+            | FalseUnwind { real_target: ref mut t, unwind: Some(ref mut u) }
+            | InlineAsm { destination: Some(ref mut t), cleanup: Some(ref mut u), .. } => {
                 Some(t).into_iter().chain(slice::from_mut(u))
             }
             SwitchInt { ref mut targets, .. } => None.into_iter().chain(&mut targets.targets[..]),
@@ -378,13 +390,13 @@ impl<'tcx> TerminatorKind<'tcx> {
             | TerminatorKind::GeneratorDrop
             | TerminatorKind::Yield { .. }
             | TerminatorKind::SwitchInt { .. }
-            | TerminatorKind::FalseEdge { .. }
-            | TerminatorKind::InlineAsm { .. } => None,
+            | TerminatorKind::FalseEdge { .. } => None,
             TerminatorKind::Call { cleanup: ref unwind, .. }
             | TerminatorKind::Assert { cleanup: ref unwind, .. }
             | TerminatorKind::DropAndReplace { ref unwind, .. }
             | TerminatorKind::Drop { ref unwind, .. }
-            | TerminatorKind::FalseUnwind { ref unwind, .. } => Some(unwind),
+            | TerminatorKind::FalseUnwind { ref unwind, .. }
+            | TerminatorKind::InlineAsm { cleanup: ref unwind, .. } => Some(unwind),
         }
     }
 
@@ -398,13 +410,13 @@ impl<'tcx> TerminatorKind<'tcx> {
             | TerminatorKind::GeneratorDrop
             | TerminatorKind::Yield { .. }
             | TerminatorKind::SwitchInt { .. }
-            | TerminatorKind::FalseEdge { .. }
-            | TerminatorKind::InlineAsm { .. } => None,
+            | TerminatorKind::FalseEdge { .. } => None,
             TerminatorKind::Call { cleanup: ref mut unwind, .. }
             | TerminatorKind::Assert { cleanup: ref mut unwind, .. }
             | TerminatorKind::DropAndReplace { ref mut unwind, .. }
             | TerminatorKind::Drop { ref mut unwind, .. }
-            | TerminatorKind::FalseUnwind { ref mut unwind, .. } => Some(unwind),
+            | TerminatorKind::FalseUnwind { ref mut unwind, .. }
+            | TerminatorKind::InlineAsm { cleanup: ref mut unwind, .. } => Some(unwind),
         }
     }
 
@@ -583,8 +595,12 @@ impl<'tcx> TerminatorKind<'tcx> {
             FalseEdge { .. } => vec!["real".into(), "imaginary".into()],
             FalseUnwind { unwind: Some(_), .. } => vec!["real".into(), "cleanup".into()],
             FalseUnwind { unwind: None, .. } => vec!["real".into()],
-            InlineAsm { destination: Some(_), .. } => vec!["".into()],
-            InlineAsm { destination: None, .. } => vec![],
+            InlineAsm { destination: Some(_), cleanup: Some(_), .. } => {
+                vec!["return".into(), "unwind".into()]
+            }
+            InlineAsm { destination: Some(_), cleanup: None, .. } => vec!["return".into()],
+            InlineAsm { destination: None, cleanup: Some(_), .. } => vec!["unwind".into()],
+            InlineAsm { destination: None, cleanup: None, .. } => vec![],
         }
     }
 }
diff --git a/compiler/rustc_middle/src/mir/type_foldable.rs b/compiler/rustc_middle/src/mir/type_foldable.rs
index ad8b9d323ee..901f3bf4f7d 100644
--- a/compiler/rustc_middle/src/mir/type_foldable.rs
+++ b/compiler/rustc_middle/src/mir/type_foldable.rs
@@ -84,13 +84,16 @@ impl<'tcx> TypeFoldable<'tcx> for Terminator<'tcx> {
                 FalseEdge { real_target, imaginary_target }
             }
             FalseUnwind { real_target, unwind } => FalseUnwind { real_target, unwind },
-            InlineAsm { template, operands, options, line_spans, destination } => InlineAsm {
-                template,
-                operands: operands.try_fold_with(folder)?,
-                options,
-                line_spans,
-                destination,
-            },
+            InlineAsm { template, operands, options, line_spans, destination, cleanup } => {
+                InlineAsm {
+                    template,
+                    operands: operands.try_fold_with(folder)?,
+                    options,
+                    line_spans,
+                    destination,
+                    cleanup,
+                }
+            }
         };
         Ok(Terminator { source_info: self.source_info, kind })
     }
diff --git a/compiler/rustc_middle/src/mir/visit.rs b/compiler/rustc_middle/src/mir/visit.rs
index 4c23ab49fa2..d783b6330e8 100644
--- a/compiler/rustc_middle/src/mir/visit.rs
+++ b/compiler/rustc_middle/src/mir/visit.rs
@@ -412,7 +412,7 @@ macro_rules! make_mir_visitor {
                         for output in & $($mutability)? asm.outputs[..] {
                             self.visit_place(
                                 output,
-                                PlaceContext::MutatingUse(MutatingUseContext::AsmOutput),
+                                PlaceContext::MutatingUse(MutatingUseContext::LlvmAsmOutput),
                                 location
                             );
                         }
@@ -581,6 +581,7 @@ macro_rules! make_mir_visitor {
                         options: _,
                         line_spans: _,
                         destination: _,
+                        cleanup: _,
                     } => {
                         for op in operands {
                             match op {
@@ -590,7 +591,7 @@ macro_rules! make_mir_visitor {
                                 InlineAsmOperand::Out { place: Some(place), .. } => {
                                     self.visit_place(
                                         place,
-                                        PlaceContext::MutatingUse(MutatingUseContext::Store),
+                                        PlaceContext::MutatingUse(MutatingUseContext::AsmOutput),
                                         location,
                                     );
                                 }
@@ -599,7 +600,7 @@ macro_rules! make_mir_visitor {
                                     if let Some(out_place) = out_place {
                                         self.visit_place(
                                             out_place,
-                                            PlaceContext::MutatingUse(MutatingUseContext::Store),
+                                            PlaceContext::MutatingUse(MutatingUseContext::AsmOutput),
                                             location,
                                         );
                                     }
@@ -1178,8 +1179,10 @@ pub enum MutatingUseContext {
     /// Appears as LHS of an assignment.
     Store,
     /// Can often be treated as a `Store`, but needs to be separate because
-    /// ASM is allowed to read outputs as well, so a `Store`-`AsmOutput` sequence
+    /// ASM is allowed to read outputs as well, so a `Store`-`LlvmAsmOutput` sequence
     /// cannot be simplified the way a `Store`-`Store` can be.
+    LlvmAsmOutput,
+    /// Output operand of an inline assembly block.
     AsmOutput,
     /// Destination of a call.
     Call,
@@ -1268,6 +1271,7 @@ impl PlaceContext {
             PlaceContext::MutatingUse(
                 MutatingUseContext::Store
                     | MutatingUseContext::Call
+                    | MutatingUseContext::LlvmAsmOutput
                     | MutatingUseContext::AsmOutput,
             )
         )
diff --git a/compiler/rustc_middle/src/traits/select.rs b/compiler/rustc_middle/src/traits/select.rs
index 71ee00c602a..560660517f3 100644
--- a/compiler/rustc_middle/src/traits/select.rs
+++ b/compiler/rustc_middle/src/traits/select.rs
@@ -12,12 +12,14 @@ use rustc_hir::def_id::DefId;
 use rustc_query_system::cache::Cache;
 
 pub type SelectionCache<'tcx> = Cache<
-    ty::ParamEnvAnd<'tcx, ty::TraitPredicate<'tcx>>,
+    (ty::ConstnessAnd<ty::ParamEnvAnd<'tcx, ty::TraitRef<'tcx>>>, ty::ImplPolarity),
     SelectionResult<'tcx, SelectionCandidate<'tcx>>,
 >;
 
-pub type EvaluationCache<'tcx> =
-    Cache<ty::ParamEnvAnd<'tcx, ty::PolyTraitPredicate<'tcx>>, EvaluationResult>;
+pub type EvaluationCache<'tcx> = Cache<
+    (ty::ParamEnvAnd<'tcx, ty::ConstnessAnd<ty::PolyTraitRef<'tcx>>>, ty::ImplPolarity),
+    EvaluationResult,
+>;
 
 /// The selection process begins by considering all impls, where
 /// clauses, and so forth that might resolve an obligation. Sometimes
@@ -101,7 +103,7 @@ pub enum SelectionCandidate<'tcx> {
         /// `false` if there are no *further* obligations.
         has_nested: bool,
     },
-    ParamCandidate(ty::PolyTraitPredicate<'tcx>),
+    ParamCandidate((ty::ConstnessAnd<ty::PolyTraitRef<'tcx>>, ty::ImplPolarity)),
     ImplCandidate(DefId),
     AutoImplCandidate(DefId),
 
diff --git a/compiler/rustc_middle/src/traits/util.rs b/compiler/rustc_middle/src/traits/util.rs
index 815f4824bc1..3490c688170 100644
--- a/compiler/rustc_middle/src/traits/util.rs
+++ b/compiler/rustc_middle/src/traits/util.rs
@@ -26,9 +26,9 @@ impl<'tcx> Elaborator<'tcx> {
             .predicates
             .into_iter()
             .flat_map(|(pred, _)| {
-                pred.subst_supertrait(self.tcx, &trait_ref).to_opt_poly_trait_pred()
+                pred.subst_supertrait(self.tcx, &trait_ref).to_opt_poly_trait_ref()
             })
-            .map(|t| t.map_bound(|pred| pred.trait_ref))
+            .map(|t| t.value)
             .filter(|supertrait_ref| self.visited.insert(*supertrait_ref));
 
         self.stack.extend(supertrait_refs);
diff --git a/compiler/rustc_middle/src/ty/adt.rs b/compiler/rustc_middle/src/ty/adt.rs
index 69eb73b4255..771ce2eb884 100644
--- a/compiler/rustc_middle/src/ty/adt.rs
+++ b/compiler/rustc_middle/src/ty/adt.rs
@@ -64,6 +64,30 @@ bitflags! {
 /// Moreover, Rust only allows recursive data types through indirection.
 ///
 /// [adt]: https://en.wikipedia.org/wiki/Algebraic_data_type
+///
+/// # Recursive types
+///
+/// It may seem impossible to represent recursive types using [`Ty`],
+/// since [`TyKind::Adt`] includes [`AdtDef`], which includes its fields,
+/// creating a cycle. However, `AdtDef` does not actually include the *types*
+/// of its fields; it includes just their [`DefId`]s.
+///
+/// [`TyKind::Adt`]: ty::TyKind::Adt
+///
+/// For example, the following type:
+///
+/// ```
+/// struct S { x: Box<S> }
+/// ```
+///
+/// is essentially represented with [`Ty`] as the following pseudocode:
+///
+/// ```
+/// struct S { x }
+/// ```
+///
+/// where `x` here represents the `DefId` of `S.x`. Then, the `DefId`
+/// can be used with [`TyCtxt::type_of()`] to get the type of the field.
 pub struct AdtDef {
     /// The `DefId` of the struct, enum or union item.
     pub did: DefId,
diff --git a/compiler/rustc_middle/src/ty/diagnostics.rs b/compiler/rustc_middle/src/ty/diagnostics.rs
index 1b32c8a6698..8803370251b 100644
--- a/compiler/rustc_middle/src/ty/diagnostics.rs
+++ b/compiler/rustc_middle/src/ty/diagnostics.rs
@@ -270,7 +270,7 @@ pub fn suggest_constraining_type_param(
         // `where` clause instead of `trait Base<T: Copy = String>: Super<T>`.
         && !matches!(param.kind, hir::GenericParamKind::Type { default: Some(_), .. })
     {
-        if let Some(bounds_span) = param.bounds_span() {
+        if let Some(span) = param.bounds_span_for_suggestions() {
             // If user has provided some bounds, suggest restricting them:
             //
             //   fn foo<T: Foo>(t: T) { ... }
@@ -284,7 +284,7 @@ pub fn suggest_constraining_type_param(
             //          --
             //          |
             //          replace with: `T: Bar +`
-            suggest_restrict(bounds_span.shrink_to_hi());
+            suggest_restrict(span);
         } else {
             // If user hasn't provided any bounds, suggest adding a new one:
             //
diff --git a/compiler/rustc_middle/src/ty/layout.rs b/compiler/rustc_middle/src/ty/layout.rs
index 57506bc6834..02811b2491c 100644
--- a/compiler/rustc_middle/src/ty/layout.rs
+++ b/compiler/rustc_middle/src/ty/layout.rs
@@ -533,7 +533,7 @@ impl<'tcx> LayoutCx<'tcx, TyCtxt<'tcx>> {
             }
         }
 
-        if sized && fields.iter().any(|f| f.abi.is_uninhabited()) {
+        if fields.iter().any(|f| f.abi.is_uninhabited()) {
             abi = Abi::Uninhabited;
         }
 
diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs
index 584303413fb..7e1804673df 100644
--- a/compiler/rustc_middle/src/ty/mod.rs
+++ b/compiler/rustc_middle/src/ty/mod.rs
@@ -230,19 +230,6 @@ pub enum BoundConstness {
     ConstIfConst,
 }
 
-impl BoundConstness {
-    /// Reduce `self` and `constness` to two possible combined states instead of four.
-    pub fn and(&mut self, constness: hir::Constness) -> hir::Constness {
-        match (constness, self) {
-            (hir::Constness::Const, BoundConstness::ConstIfConst) => hir::Constness::Const,
-            (_, this) => {
-                *this = BoundConstness::NotConst;
-                hir::Constness::NotConst
-            }
-        }
-    }
-}
-
 impl fmt::Display for BoundConstness {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
         match self {
@@ -859,6 +846,20 @@ impl ToPredicate<'tcx> for Binder<'tcx, PredicateKind<'tcx>> {
     }
 }
 
+impl<'tcx> ToPredicate<'tcx> for ConstnessAnd<PolyTraitRef<'tcx>> {
+    fn to_predicate(self, tcx: TyCtxt<'tcx>) -> Predicate<'tcx> {
+        self.value
+            .map_bound(|trait_ref| {
+                PredicateKind::Trait(ty::TraitPredicate {
+                    trait_ref,
+                    constness: self.constness,
+                    polarity: ty::ImplPolarity::Positive,
+                })
+            })
+            .to_predicate(tcx)
+    }
+}
+
 impl<'tcx> ToPredicate<'tcx> for PolyTraitPredicate<'tcx> {
     fn to_predicate(self, tcx: TyCtxt<'tcx>) -> Predicate<'tcx> {
         self.map_bound(PredicateKind::Trait).to_predicate(tcx)
@@ -884,10 +885,12 @@ impl<'tcx> ToPredicate<'tcx> for PolyProjectionPredicate<'tcx> {
 }
 
 impl<'tcx> Predicate<'tcx> {
-    pub fn to_opt_poly_trait_pred(self) -> Option<PolyTraitPredicate<'tcx>> {
+    pub fn to_opt_poly_trait_ref(self) -> Option<ConstnessAnd<PolyTraitRef<'tcx>>> {
         let predicate = self.kind();
         match predicate.skip_binder() {
-            PredicateKind::Trait(t) => Some(predicate.rebind(t)),
+            PredicateKind::Trait(t) => {
+                Some(ConstnessAnd { constness: t.constness, value: predicate.rebind(t.trait_ref) })
+            }
             PredicateKind::Projection(..)
             | PredicateKind::Subtype(..)
             | PredicateKind::Coerce(..)
@@ -1218,33 +1221,23 @@ pub struct ParamEnv<'tcx> {
     /// want `Reveal::All`.
     ///
     /// Note: This is packed, use the reveal() method to access it.
-    packed: CopyTaggedPtr<&'tcx List<Predicate<'tcx>>, ParamTag, true>,
+    packed: CopyTaggedPtr<&'tcx List<Predicate<'tcx>>, traits::Reveal, true>,
 }
 
-#[derive(Copy, Clone)]
-struct ParamTag {
-    reveal: traits::Reveal,
-    constness: hir::Constness,
-}
-
-unsafe impl rustc_data_structures::tagged_ptr::Tag for ParamTag {
-    const BITS: usize = 2;
+unsafe impl rustc_data_structures::tagged_ptr::Tag for traits::Reveal {
+    const BITS: usize = 1;
     #[inline]
     fn into_usize(self) -> usize {
         match self {
-            Self { reveal: traits::Reveal::UserFacing, constness: hir::Constness::NotConst } => 0,
-            Self { reveal: traits::Reveal::All, constness: hir::Constness::NotConst } => 1,
-            Self { reveal: traits::Reveal::UserFacing, constness: hir::Constness::Const } => 2,
-            Self { reveal: traits::Reveal::All, constness: hir::Constness::Const } => 3,
+            traits::Reveal::UserFacing => 0,
+            traits::Reveal::All => 1,
         }
     }
     #[inline]
     unsafe fn from_usize(ptr: usize) -> Self {
         match ptr {
-            0 => Self { reveal: traits::Reveal::UserFacing, constness: hir::Constness::NotConst },
-            1 => Self { reveal: traits::Reveal::All, constness: hir::Constness::NotConst },
-            2 => Self { reveal: traits::Reveal::UserFacing, constness: hir::Constness::Const },
-            3 => Self { reveal: traits::Reveal::All, constness: hir::Constness::Const },
+            0 => traits::Reveal::UserFacing,
+            1 => traits::Reveal::All,
             _ => std::hint::unreachable_unchecked(),
         }
     }
@@ -1255,7 +1248,6 @@ impl<'tcx> fmt::Debug for ParamEnv<'tcx> {
         f.debug_struct("ParamEnv")
             .field("caller_bounds", &self.caller_bounds())
             .field("reveal", &self.reveal())
-            .field("constness", &self.constness())
             .finish()
     }
 }
@@ -1264,7 +1256,6 @@ impl<'a, 'tcx> HashStable<StableHashingContext<'a>> for ParamEnv<'tcx> {
     fn hash_stable(&self, hcx: &mut StableHashingContext<'a>, hasher: &mut StableHasher) {
         self.caller_bounds().hash_stable(hcx, hasher);
         self.reveal().hash_stable(hcx, hasher);
-        self.constness().hash_stable(hcx, hasher);
     }
 }
 
@@ -1276,14 +1267,12 @@ impl<'tcx> TypeFoldable<'tcx> for ParamEnv<'tcx> {
         Ok(ParamEnv::new(
             self.caller_bounds().try_fold_with(folder)?,
             self.reveal().try_fold_with(folder)?,
-            self.constness().try_fold_with(folder)?,
         ))
     }
 
     fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> {
         self.caller_bounds().visit_with(visitor)?;
-        self.reveal().visit_with(visitor)?;
-        self.constness().visit_with(visitor)
+        self.reveal().visit_with(visitor)
     }
 }
 
@@ -1294,7 +1283,7 @@ impl<'tcx> ParamEnv<'tcx> {
     /// type-checking.
     #[inline]
     pub fn empty() -> Self {
-        Self::new(List::empty(), Reveal::UserFacing, hir::Constness::NotConst)
+        Self::new(List::empty(), Reveal::UserFacing)
     }
 
     #[inline]
@@ -1304,12 +1293,7 @@ impl<'tcx> ParamEnv<'tcx> {
 
     #[inline]
     pub fn reveal(self) -> traits::Reveal {
-        self.packed.tag().reveal
-    }
-
-    #[inline]
-    pub fn constness(self) -> hir::Constness {
-        self.packed.tag().constness
+        self.packed.tag()
     }
 
     /// Construct a trait environment with no where-clauses in scope
@@ -1321,31 +1305,17 @@ impl<'tcx> ParamEnv<'tcx> {
     /// or invoke `param_env.with_reveal_all()`.
     #[inline]
     pub fn reveal_all() -> Self {
-        Self::new(List::empty(), Reveal::All, hir::Constness::NotConst)
+        Self::new(List::empty(), Reveal::All)
     }
 
     /// Construct a trait environment with the given set of predicates.
     #[inline]
-    pub fn new(
-        caller_bounds: &'tcx List<Predicate<'tcx>>,
-        reveal: Reveal,
-        constness: hir::Constness,
-    ) -> Self {
-        ty::ParamEnv { packed: CopyTaggedPtr::new(caller_bounds, ParamTag { reveal, constness }) }
+    pub fn new(caller_bounds: &'tcx List<Predicate<'tcx>>, reveal: Reveal) -> Self {
+        ty::ParamEnv { packed: CopyTaggedPtr::new(caller_bounds, reveal) }
     }
 
     pub fn with_user_facing(mut self) -> Self {
-        self.packed.set_tag(ParamTag { reveal: Reveal::UserFacing, ..self.packed.tag() });
-        self
-    }
-
-    pub fn with_constness(mut self, constness: hir::Constness) -> Self {
-        self.packed.set_tag(ParamTag { constness, ..self.packed.tag() });
-        self
-    }
-
-    pub fn with_const(mut self) -> Self {
-        self.packed.set_tag(ParamTag { constness: hir::Constness::Const, ..self.packed.tag() });
+        self.packed.set_tag(Reveal::UserFacing);
         self
     }
 
@@ -1359,21 +1329,17 @@ impl<'tcx> ParamEnv<'tcx> {
     /// will be normalized to their underlying types.
     /// See PR #65989 and issue #65918 for more details
     pub fn with_reveal_all_normalized(self, tcx: TyCtxt<'tcx>) -> Self {
-        if self.packed.tag().reveal == traits::Reveal::All {
+        if self.packed.tag() == traits::Reveal::All {
             return self;
         }
 
-        ParamEnv::new(
-            tcx.normalize_opaque_types(self.caller_bounds()),
-            Reveal::All,
-            self.constness(),
-        )
+        ParamEnv::new(tcx.normalize_opaque_types(self.caller_bounds()), Reveal::All)
     }
 
     /// Returns this same environment but with no caller bounds.
     #[inline]
     pub fn without_caller_bounds(self) -> Self {
-        Self::new(List::empty(), self.reveal(), self.constness())
+        Self::new(List::empty(), self.reveal())
     }
 
     /// Creates a suitable environment in which to perform trait
@@ -1403,23 +1369,33 @@ impl<'tcx> ParamEnv<'tcx> {
     }
 }
 
+#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, TypeFoldable)]
+pub struct ConstnessAnd<T> {
+    pub constness: BoundConstness,
+    pub value: T,
+}
+
 // FIXME(ecstaticmorse): Audit all occurrences of `without_const().to_predicate(tcx)` to ensure that
 // the constness of trait bounds is being propagated correctly.
-impl PolyTraitRef<'tcx> {
+pub trait WithConstness: Sized {
     #[inline]
-    pub fn with_constness(self, constness: BoundConstness) -> PolyTraitPredicate<'tcx> {
-        self.map_bound(|trait_ref| ty::TraitPredicate {
-            trait_ref,
-            constness,
-            polarity: ty::ImplPolarity::Positive,
-        })
+    fn with_constness(self, constness: BoundConstness) -> ConstnessAnd<Self> {
+        ConstnessAnd { constness, value: self }
+    }
+
+    #[inline]
+    fn with_const_if_const(self) -> ConstnessAnd<Self> {
+        self.with_constness(BoundConstness::ConstIfConst)
     }
+
     #[inline]
-    pub fn without_const(self) -> PolyTraitPredicate<'tcx> {
+    fn without_const(self) -> ConstnessAnd<Self> {
         self.with_constness(BoundConstness::NotConst)
     }
 }
 
+impl<T> WithConstness for T {}
+
 #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, TypeFoldable)]
 pub struct ParamEnvAnd<'tcx, T> {
     pub param_env: ParamEnv<'tcx>,
@@ -1735,7 +1711,7 @@ impl ReprOptions {
 
 impl<'tcx> FieldDef {
     /// Returns the type of this field. The resulting type is not normalized. The `subst` is
-    /// typically obtained via the second field of `TyKind::AdtDef`.
+    /// typically obtained via the second field of [`TyKind::Adt`].
     pub fn ty(&self, tcx: TyCtxt<'tcx>, subst: SubstsRef<'tcx>) -> Ty<'tcx> {
         tcx.type_of(self.did).subst(tcx, subst)
     }
diff --git a/compiler/rustc_middle/src/ty/relate.rs b/compiler/rustc_middle/src/ty/relate.rs
index b6aadf27bb0..c7d8bec506f 100644
--- a/compiler/rustc_middle/src/ty/relate.rs
+++ b/compiler/rustc_middle/src/ty/relate.rs
@@ -218,6 +218,19 @@ impl<'tcx> Relate<'tcx> for ty::BoundConstness {
     }
 }
 
+impl<'tcx, T: Relate<'tcx>> Relate<'tcx> for ty::ConstnessAnd<T> {
+    fn relate<R: TypeRelation<'tcx>>(
+        relation: &mut R,
+        a: ty::ConstnessAnd<T>,
+        b: ty::ConstnessAnd<T>,
+    ) -> RelateResult<'tcx, ty::ConstnessAnd<T>> {
+        Ok(ty::ConstnessAnd {
+            constness: relation.relate(a.constness, b.constness)?,
+            value: relation.relate(a.value, b.value)?,
+        })
+    }
+}
+
 impl<'tcx> Relate<'tcx> for ast::Unsafety {
     fn relate<R: TypeRelation<'tcx>>(
         relation: &mut R,
diff --git a/compiler/rustc_middle/src/ty/structural_impls.rs b/compiler/rustc_middle/src/ty/structural_impls.rs
index 30ed008a5de..16a6c586358 100644
--- a/compiler/rustc_middle/src/ty/structural_impls.rs
+++ b/compiler/rustc_middle/src/ty/structural_impls.rs
@@ -480,7 +480,7 @@ impl<'a, 'tcx> Lift<'tcx> for ty::ParamEnv<'a> {
     type Lifted = ty::ParamEnv<'tcx>;
     fn lift_to_tcx(self, tcx: TyCtxt<'tcx>) -> Option<Self::Lifted> {
         tcx.lift(self.caller_bounds())
-            .map(|caller_bounds| ty::ParamEnv::new(caller_bounds, self.reveal(), self.constness()))
+            .map(|caller_bounds| ty::ParamEnv::new(caller_bounds, self.reveal()))
     }
 }
 
diff --git a/compiler/rustc_middle/src/ty/sty.rs b/compiler/rustc_middle/src/ty/sty.rs
index a80fe6a3362..6bd761d61e2 100644
--- a/compiler/rustc_middle/src/ty/sty.rs
+++ b/compiler/rustc_middle/src/ty/sty.rs
@@ -8,7 +8,9 @@ use crate::infer::canonical::Canonical;
 use crate::ty::fold::ValidateBoundVars;
 use crate::ty::subst::{GenericArg, InternalSubsts, Subst, SubstsRef};
 use crate::ty::InferTy::{self, *};
-use crate::ty::{self, AdtDef, DefIdTree, Discr, Ty, TyCtxt, TypeFlags, TypeFoldable};
+use crate::ty::{
+    self, AdtDef, DefIdTree, Discr, Ty, TyCtxt, TypeFlags, TypeFoldable, WithConstness,
+};
 use crate::ty::{DelaySpanBugEmitted, List, ParamEnv, TyS};
 use polonius_engine::Atom;
 use rustc_data_structures::captures::Captures;
diff --git a/compiler/rustc_middle/src/ty/util.rs b/compiler/rustc_middle/src/ty/util.rs
index 25eb56456e1..ba9b2eae2c8 100644
--- a/compiler/rustc_middle/src/ty/util.rs
+++ b/compiler/rustc_middle/src/ty/util.rs
@@ -788,10 +788,14 @@ impl<'tcx> ty::TyS<'tcx> {
                     [component_ty] => component_ty,
                     _ => self,
                 };
+
                 // This doesn't depend on regions, so try to minimize distinct
                 // query keys used.
-                let erased = tcx.normalize_erasing_regions(param_env, query_ty);
-                tcx.needs_drop_raw(param_env.and(erased))
+                // If normalization fails, we just use `query_ty`.
+                let query_ty =
+                    tcx.try_normalize_erasing_regions(param_env, query_ty).unwrap_or(query_ty);
+
+                tcx.needs_drop_raw(param_env.and(query_ty))
             }
         }
     }
diff --git a/compiler/rustc_mir_build/src/build/expr/into.rs b/compiler/rustc_mir_build/src/build/expr/into.rs
index 53868f28557..abec67af08b 100644
--- a/compiler/rustc_mir_build/src/build/expr/into.rs
+++ b/compiler/rustc_mir_build/src/build/expr/into.rs
@@ -467,8 +467,12 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
                         } else {
                             Some(destination_block)
                         },
+                        cleanup: None,
                     },
                 );
+                if options.contains(InlineAsmOptions::MAY_UNWIND) {
+                    this.diverge_from(block);
+                }
                 destination_block.unit()
             }
 
diff --git a/compiler/rustc_mir_build/src/build/scope.rs b/compiler/rustc_mir_build/src/build/scope.rs
index 8dadbf5f02b..fc46c54c2fc 100644
--- a/compiler/rustc_mir_build/src/build/scope.rs
+++ b/compiler/rustc_mir_build/src/build/scope.rs
@@ -1034,6 +1034,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
                     | TerminatorKind::Call { .. }
                     | TerminatorKind::DropAndReplace { .. }
                     | TerminatorKind::FalseUnwind { .. }
+                    | TerminatorKind::InlineAsm { .. }
             ),
             "diverge_from called on block with terminator that cannot unwind."
         );
@@ -1373,7 +1374,8 @@ impl<'tcx> DropTreeBuilder<'tcx> for Unwind {
             | TerminatorKind::DropAndReplace { unwind, .. }
             | TerminatorKind::FalseUnwind { unwind, .. }
             | TerminatorKind::Call { cleanup: unwind, .. }
-            | TerminatorKind::Assert { cleanup: unwind, .. } => {
+            | TerminatorKind::Assert { cleanup: unwind, .. }
+            | TerminatorKind::InlineAsm { cleanup: unwind, .. } => {
                 *unwind = Some(to);
             }
             TerminatorKind::Goto { .. }
@@ -1384,8 +1386,7 @@ impl<'tcx> DropTreeBuilder<'tcx> for Unwind {
             | TerminatorKind::Unreachable
             | TerminatorKind::Yield { .. }
             | TerminatorKind::GeneratorDrop
-            | TerminatorKind::FalseEdge { .. }
-            | TerminatorKind::InlineAsm { .. } => {
+            | TerminatorKind::FalseEdge { .. } => {
                 span_bug!(term.source_info.span, "cannot unwind from {:?}", term.kind)
             }
         }
diff --git a/compiler/rustc_mir_dataflow/src/framework/direction.rs b/compiler/rustc_mir_dataflow/src/framework/direction.rs
index 8a9ced91eb3..6131ee79818 100644
--- a/compiler/rustc_mir_dataflow/src/framework/direction.rs
+++ b/compiler/rustc_mir_dataflow/src/framework/direction.rs
@@ -4,7 +4,9 @@ use rustc_middle::ty::TyCtxt;
 use std::ops::RangeInclusive;
 
 use super::visitor::{ResultsVisitable, ResultsVisitor};
-use super::{Analysis, Effect, EffectIndex, GenKillAnalysis, GenKillSet, SwitchIntTarget};
+use super::{
+    Analysis, CallReturnPlaces, Effect, EffectIndex, GenKillAnalysis, GenKillSet, SwitchIntTarget,
+};
 
 pub trait Direction {
     fn is_forward() -> bool;
@@ -235,14 +237,26 @@ impl Direction for Backward {
                 // Apply terminator-specific edge effects.
                 //
                 // FIXME(ecstaticmorse): Avoid cloning the exit state unconditionally.
-                mir::TerminatorKind::Call {
-                    destination: Some((return_place, dest)),
-                    ref func,
-                    ref args,
-                    ..
+                mir::TerminatorKind::Call { destination: Some((return_place, dest)), .. }
+                    if dest == bb =>
+                {
+                    let mut tmp = exit_state.clone();
+                    analysis.apply_call_return_effect(
+                        &mut tmp,
+                        pred,
+                        CallReturnPlaces::Call(return_place),
+                    );
+                    propagate(pred, &tmp);
+                }
+                mir::TerminatorKind::InlineAsm {
+                    destination: Some(dest), ref operands, ..
                 } if dest == bb => {
                     let mut tmp = exit_state.clone();
-                    analysis.apply_call_return_effect(&mut tmp, pred, func, args, return_place);
+                    analysis.apply_call_return_effect(
+                        &mut tmp,
+                        pred,
+                        CallReturnPlaces::InlineAsm(operands),
+                    );
                     propagate(pred, &tmp);
                 }
 
@@ -258,6 +272,7 @@ impl Direction for Backward {
                 | mir::TerminatorKind::Drop { unwind: Some(unwind), .. }
                 | mir::TerminatorKind::DropAndReplace { unwind: Some(unwind), .. }
                 | mir::TerminatorKind::FalseUnwind { unwind: Some(unwind), .. }
+                | mir::TerminatorKind::InlineAsm { cleanup: Some(unwind), .. }
                     if unwind == bb =>
                 {
                     if dead_unwinds.map_or(true, |dead| !dead.contains(bb)) {
@@ -467,7 +482,7 @@ impl Direction for Forward {
                 propagate(target, exit_state);
             }
 
-            Call { cleanup, destination, ref func, ref args, from_hir_call: _, fn_span: _ } => {
+            Call { cleanup, destination, func: _, args: _, from_hir_call: _, fn_span: _ } => {
                 if let Some(unwind) = cleanup {
                     if dead_unwinds.map_or(true, |dead| !dead.contains(bb)) {
                         propagate(unwind, exit_state);
@@ -477,13 +492,37 @@ impl Direction for Forward {
                 if let Some((dest_place, target)) = destination {
                     // N.B.: This must be done *last*, otherwise the unwind path will see the call
                     // return effect.
-                    analysis.apply_call_return_effect(exit_state, bb, func, args, dest_place);
+                    analysis.apply_call_return_effect(
+                        exit_state,
+                        bb,
+                        CallReturnPlaces::Call(dest_place),
+                    );
                     propagate(target, exit_state);
                 }
             }
 
-            InlineAsm { template: _, operands: _, options: _, line_spans: _, destination } => {
+            InlineAsm {
+                template: _,
+                ref operands,
+                options: _,
+                line_spans: _,
+                destination,
+                cleanup,
+            } => {
+                if let Some(unwind) = cleanup {
+                    if dead_unwinds.map_or(true, |dead| !dead.contains(bb)) {
+                        propagate(unwind, exit_state);
+                    }
+                }
+
                 if let Some(target) = destination {
+                    // N.B.: This must be done *last*, otherwise the unwind path will see the call
+                    // return effect.
+                    analysis.apply_call_return_effect(
+                        exit_state,
+                        bb,
+                        CallReturnPlaces::InlineAsm(operands),
+                    );
                     propagate(target, exit_state);
                 }
             }
diff --git a/compiler/rustc_mir_dataflow/src/framework/graphviz.rs b/compiler/rustc_mir_dataflow/src/framework/graphviz.rs
index a370f8e40f9..517bc086ef6 100644
--- a/compiler/rustc_mir_dataflow/src/framework/graphviz.rs
+++ b/compiler/rustc_mir_dataflow/src/framework/graphviz.rs
@@ -10,7 +10,7 @@ use rustc_middle::mir::graphviz_safe_def_name;
 use rustc_middle::mir::{self, BasicBlock, Body, Location};
 
 use super::fmt::{DebugDiffWithAdapter, DebugWithAdapter, DebugWithContext};
-use super::{Analysis, Direction, Results, ResultsRefCursor, ResultsVisitor};
+use super::{Analysis, CallReturnPlaces, Direction, Results, ResultsRefCursor, ResultsVisitor};
 
 #[derive(Clone, Copy, Debug, PartialEq, Eq)]
 pub enum OutputStyle {
@@ -231,16 +231,15 @@ where
         // for the basic block itself. That way, we could display terminator-specific effects for
         // backward dataflow analyses as well as effects for `SwitchInt` terminators.
         match terminator.kind {
-            mir::TerminatorKind::Call {
-                destination: Some((return_place, _)),
-                ref func,
-                ref args,
-                ..
-            } => {
+            mir::TerminatorKind::Call { destination: Some((return_place, _)), .. } => {
                 self.write_row(w, "", "(on successful return)", |this, w, fmt| {
                     let state_on_unwind = this.results.get().clone();
                     this.results.apply_custom_effect(|analysis, state| {
-                        analysis.apply_call_return_effect(state, block, func, args, return_place);
+                        analysis.apply_call_return_effect(
+                            state,
+                            block,
+                            CallReturnPlaces::Call(return_place),
+                        );
                     });
 
                     write!(
@@ -278,6 +277,31 @@ where
                 })?;
             }
 
+            mir::TerminatorKind::InlineAsm { destination: Some(_), ref operands, .. } => {
+                self.write_row(w, "", "(on successful return)", |this, w, fmt| {
+                    let state_on_unwind = this.results.get().clone();
+                    this.results.apply_custom_effect(|analysis, state| {
+                        analysis.apply_call_return_effect(
+                            state,
+                            block,
+                            CallReturnPlaces::InlineAsm(operands),
+                        );
+                    });
+
+                    write!(
+                        w,
+                        r#"<td balign="left" colspan="{colspan}" {fmt} align="left">{diff}</td>"#,
+                        colspan = this.style.num_state_columns(),
+                        fmt = fmt,
+                        diff = diff_pretty(
+                            this.results.get(),
+                            &state_on_unwind,
+                            this.results.analysis()
+                        ),
+                    )
+                })?;
+            }
+
             _ => {}
         };
 
diff --git a/compiler/rustc_mir_dataflow/src/framework/mod.rs b/compiler/rustc_mir_dataflow/src/framework/mod.rs
index f0c9ac4c504..500fba8b114 100644
--- a/compiler/rustc_mir_dataflow/src/framework/mod.rs
+++ b/compiler/rustc_mir_dataflow/src/framework/mod.rs
@@ -160,9 +160,7 @@ pub trait Analysis<'tcx>: AnalysisDomain<'tcx> {
         &self,
         state: &mut Self::Domain,
         block: BasicBlock,
-        func: &mir::Operand<'tcx>,
-        args: &[mir::Operand<'tcx>],
-        return_place: mir::Place<'tcx>,
+        return_places: CallReturnPlaces<'_, 'tcx>,
     );
 
     /// Updates the current dataflow state with the effect of resuming from a `Yield` terminator.
@@ -276,9 +274,7 @@ pub trait GenKillAnalysis<'tcx>: Analysis<'tcx> {
         &self,
         trans: &mut impl GenKill<Self::Idx>,
         block: BasicBlock,
-        func: &mir::Operand<'tcx>,
-        args: &[mir::Operand<'tcx>],
-        return_place: mir::Place<'tcx>,
+        return_places: CallReturnPlaces<'_, 'tcx>,
     );
 
     /// See `Analysis::apply_yield_resume_effect`.
@@ -347,11 +343,9 @@ where
         &self,
         state: &mut A::Domain,
         block: BasicBlock,
-        func: &mir::Operand<'tcx>,
-        args: &[mir::Operand<'tcx>],
-        return_place: mir::Place<'tcx>,
+        return_places: CallReturnPlaces<'_, 'tcx>,
     ) {
-        self.call_return_effect(state, block, func, args, return_place);
+        self.call_return_effect(state, block, return_places);
     }
 
     fn apply_yield_resume_effect(
@@ -542,5 +536,29 @@ pub trait SwitchIntEdgeEffects<D> {
     fn apply(&mut self, apply_edge_effect: impl FnMut(&mut D, SwitchIntTarget));
 }
 
+/// List of places that are written to after a successful (non-unwind) return
+/// from a `Call` or `InlineAsm`.
+pub enum CallReturnPlaces<'a, 'tcx> {
+    Call(mir::Place<'tcx>),
+    InlineAsm(&'a [mir::InlineAsmOperand<'tcx>]),
+}
+
+impl<'tcx> CallReturnPlaces<'_, 'tcx> {
+    pub fn for_each(&self, mut f: impl FnMut(mir::Place<'tcx>)) {
+        match *self {
+            Self::Call(place) => f(place),
+            Self::InlineAsm(operands) => {
+                for op in operands {
+                    match *op {
+                        mir::InlineAsmOperand::Out { place: Some(place), .. }
+                        | mir::InlineAsmOperand::InOut { out_place: Some(place), .. } => f(place),
+                        _ => {}
+                    }
+                }
+            }
+        }
+    }
+}
+
 #[cfg(test)]
 mod tests;
diff --git a/compiler/rustc_mir_dataflow/src/framework/tests.rs b/compiler/rustc_mir_dataflow/src/framework/tests.rs
index 6efa8daec48..01ca8ca9258 100644
--- a/compiler/rustc_mir_dataflow/src/framework/tests.rs
+++ b/compiler/rustc_mir_dataflow/src/framework/tests.rs
@@ -220,9 +220,7 @@ impl<D: Direction> Analysis<'tcx> for MockAnalysis<'tcx, D> {
         &self,
         _state: &mut Self::Domain,
         _block: BasicBlock,
-        _func: &mir::Operand<'tcx>,
-        _args: &[mir::Operand<'tcx>],
-        _return_place: mir::Place<'tcx>,
+        _return_places: CallReturnPlaces<'_, 'tcx>,
     ) {
     }
 }
diff --git a/compiler/rustc_mir_dataflow/src/impls/borrowed_locals.rs b/compiler/rustc_mir_dataflow/src/impls/borrowed_locals.rs
index d38b567a958..6df2c8df3ce 100644
--- a/compiler/rustc_mir_dataflow/src/impls/borrowed_locals.rs
+++ b/compiler/rustc_mir_dataflow/src/impls/borrowed_locals.rs
@@ -1,6 +1,6 @@
 use super::*;
 
-use crate::{AnalysisDomain, GenKill, GenKillAnalysis};
+use crate::{AnalysisDomain, CallReturnPlaces, GenKill, GenKillAnalysis};
 use rustc_middle::mir::visit::Visitor;
 use rustc_middle::mir::*;
 
@@ -84,9 +84,7 @@ impl GenKillAnalysis<'tcx> for MaybeBorrowedLocals {
         &self,
         _trans: &mut impl GenKill<Self::Idx>,
         _block: mir::BasicBlock,
-        _func: &mir::Operand<'tcx>,
-        _args: &[mir::Operand<'tcx>],
-        _dest_place: mir::Place<'tcx>,
+        _return_places: CallReturnPlaces<'_, 'tcx>,
     ) {
     }
 }
diff --git a/compiler/rustc_mir_dataflow/src/impls/init_locals.rs b/compiler/rustc_mir_dataflow/src/impls/init_locals.rs
index 07570e764f5..df13b5c3394 100644
--- a/compiler/rustc_mir_dataflow/src/impls/init_locals.rs
+++ b/compiler/rustc_mir_dataflow/src/impls/init_locals.rs
@@ -2,7 +2,7 @@
 //!
 //! A local will be maybe initialized if *any* projections of that local might be initialized.
 
-use crate::GenKill;
+use crate::{CallReturnPlaces, GenKill};
 
 use rustc_index::bit_set::BitSet;
 use rustc_middle::mir::visit::{PlaceContext, Visitor};
@@ -53,11 +53,9 @@ impl crate::GenKillAnalysis<'tcx> for MaybeInitializedLocals {
         &self,
         trans: &mut impl GenKill<Self::Idx>,
         _block: BasicBlock,
-        _func: &mir::Operand<'tcx>,
-        _args: &[mir::Operand<'tcx>],
-        return_place: mir::Place<'tcx>,
+        return_places: CallReturnPlaces<'_, 'tcx>,
     ) {
-        trans.gen(return_place.local)
+        return_places.for_each(|place| trans.gen(place.local));
     }
 
     /// See `Analysis::apply_yield_resume_effect`.
@@ -83,7 +81,11 @@ where
         use rustc_middle::mir::visit::{MutatingUseContext, NonMutatingUseContext, NonUseContext};
         match context {
             // These are handled specially in `call_return_effect` and `yield_resume_effect`.
-            PlaceContext::MutatingUse(MutatingUseContext::Call | MutatingUseContext::Yield) => {}
+            PlaceContext::MutatingUse(
+                MutatingUseContext::Call
+                | MutatingUseContext::AsmOutput
+                | MutatingUseContext::Yield,
+            ) => {}
 
             // Otherwise, when a place is mutated, we must consider it possibly initialized.
             PlaceContext::MutatingUse(_) => self.trans.gen(local),
diff --git a/compiler/rustc_mir_dataflow/src/impls/liveness.rs b/compiler/rustc_mir_dataflow/src/impls/liveness.rs
index 3e2548845e2..5be9df6c452 100644
--- a/compiler/rustc_mir_dataflow/src/impls/liveness.rs
+++ b/compiler/rustc_mir_dataflow/src/impls/liveness.rs
@@ -2,7 +2,7 @@ use rustc_index::bit_set::BitSet;
 use rustc_middle::mir::visit::{MutatingUseContext, NonMutatingUseContext, PlaceContext, Visitor};
 use rustc_middle::mir::{self, Local, Location};
 
-use crate::{AnalysisDomain, Backward, GenKill, GenKillAnalysis};
+use crate::{AnalysisDomain, Backward, CallReturnPlaces, GenKill, GenKillAnalysis};
 
 /// A [live-variable dataflow analysis][liveness].
 ///
@@ -94,13 +94,13 @@ impl GenKillAnalysis<'tcx> for MaybeLiveLocals {
         &self,
         trans: &mut impl GenKill<Self::Idx>,
         _block: mir::BasicBlock,
-        _func: &mir::Operand<'tcx>,
-        _args: &[mir::Operand<'tcx>],
-        dest_place: mir::Place<'tcx>,
+        return_places: CallReturnPlaces<'_, 'tcx>,
     ) {
-        if let Some(local) = dest_place.as_local() {
-            trans.kill(local);
-        }
+        return_places.for_each(|place| {
+            if let Some(local) = place.as_local() {
+                trans.kill(local);
+            }
+        });
     }
 
     fn yield_resume_effect(
@@ -167,12 +167,16 @@ impl DefUse {
             // destination place for a `Call` return or `Yield` resume respectively. Since this is
             // only a `Def` when the function returns successfully, we handle this case separately
             // in `call_return_effect` above.
-            PlaceContext::MutatingUse(MutatingUseContext::Call | MutatingUseContext::Yield) => None,
+            PlaceContext::MutatingUse(
+                MutatingUseContext::Call
+                | MutatingUseContext::AsmOutput
+                | MutatingUseContext::Yield,
+            ) => None,
 
             // All other contexts are uses...
             PlaceContext::MutatingUse(
                 MutatingUseContext::AddressOf
-                | MutatingUseContext::AsmOutput
+                | MutatingUseContext::LlvmAsmOutput
                 | MutatingUseContext::Borrow
                 | MutatingUseContext::Drop
                 | MutatingUseContext::Retag,
diff --git a/compiler/rustc_mir_dataflow/src/impls/mod.rs b/compiler/rustc_mir_dataflow/src/impls/mod.rs
index 2585701f60c..5659fd2dc70 100644
--- a/compiler/rustc_mir_dataflow/src/impls/mod.rs
+++ b/compiler/rustc_mir_dataflow/src/impls/mod.rs
@@ -11,7 +11,7 @@ use rustc_middle::ty::{self, TyCtxt};
 use crate::drop_flag_effects_for_function_entry;
 use crate::drop_flag_effects_for_location;
 use crate::elaborate_drops::DropFlagState;
-use crate::framework::SwitchIntEdgeEffects;
+use crate::framework::{CallReturnPlaces, SwitchIntEdgeEffects};
 use crate::move_paths::{HasMoveData, InitIndex, InitKind, LookupResult, MoveData, MovePathIndex};
 use crate::on_lookup_result_bits;
 use crate::MoveDataParamEnv;
@@ -354,21 +354,21 @@ impl<'tcx> GenKillAnalysis<'tcx> for MaybeInitializedPlaces<'_, 'tcx> {
         &self,
         trans: &mut impl GenKill<Self::Idx>,
         _block: mir::BasicBlock,
-        _func: &mir::Operand<'tcx>,
-        _args: &[mir::Operand<'tcx>],
-        dest_place: mir::Place<'tcx>,
+        return_places: CallReturnPlaces<'_, 'tcx>,
     ) {
-        // when a call returns successfully, that means we need to set
-        // the bits for that dest_place to 1 (initialized).
-        on_lookup_result_bits(
-            self.tcx,
-            self.body,
-            self.move_data(),
-            self.move_data().rev_lookup.find(dest_place.as_ref()),
-            |mpi| {
-                trans.gen(mpi);
-            },
-        );
+        return_places.for_each(|place| {
+            // when a call returns successfully, that means we need to set
+            // the bits for that dest_place to 1 (initialized).
+            on_lookup_result_bits(
+                self.tcx,
+                self.body,
+                self.move_data(),
+                self.move_data().rev_lookup.find(place.as_ref()),
+                |mpi| {
+                    trans.gen(mpi);
+                },
+            );
+        });
     }
 
     fn switch_int_edge_effects<G: GenKill<Self::Idx>>(
@@ -472,21 +472,21 @@ impl<'tcx> GenKillAnalysis<'tcx> for MaybeUninitializedPlaces<'_, 'tcx> {
         &self,
         trans: &mut impl GenKill<Self::Idx>,
         _block: mir::BasicBlock,
-        _func: &mir::Operand<'tcx>,
-        _args: &[mir::Operand<'tcx>],
-        dest_place: mir::Place<'tcx>,
+        return_places: CallReturnPlaces<'_, 'tcx>,
     ) {
-        // when a call returns successfully, that means we need to set
-        // the bits for that dest_place to 0 (initialized).
-        on_lookup_result_bits(
-            self.tcx,
-            self.body,
-            self.move_data(),
-            self.move_data().rev_lookup.find(dest_place.as_ref()),
-            |mpi| {
-                trans.kill(mpi);
-            },
-        );
+        return_places.for_each(|place| {
+            // when a call returns successfully, that means we need to set
+            // the bits for that dest_place to 0 (initialized).
+            on_lookup_result_bits(
+                self.tcx,
+                self.body,
+                self.move_data(),
+                self.move_data().rev_lookup.find(place.as_ref()),
+                |mpi| {
+                    trans.kill(mpi);
+                },
+            );
+        });
     }
 
     fn switch_int_edge_effects<G: GenKill<Self::Idx>>(
@@ -591,21 +591,21 @@ impl<'tcx> GenKillAnalysis<'tcx> for DefinitelyInitializedPlaces<'_, 'tcx> {
         &self,
         trans: &mut impl GenKill<Self::Idx>,
         _block: mir::BasicBlock,
-        _func: &mir::Operand<'tcx>,
-        _args: &[mir::Operand<'tcx>],
-        dest_place: mir::Place<'tcx>,
+        return_places: CallReturnPlaces<'_, 'tcx>,
     ) {
-        // when a call returns successfully, that means we need to set
-        // the bits for that dest_place to 1 (initialized).
-        on_lookup_result_bits(
-            self.tcx,
-            self.body,
-            self.move_data(),
-            self.move_data().rev_lookup.find(dest_place.as_ref()),
-            |mpi| {
-                trans.gen(mpi);
-            },
-        );
+        return_places.for_each(|place| {
+            // when a call returns successfully, that means we need to set
+            // the bits for that dest_place to 1 (initialized).
+            on_lookup_result_bits(
+                self.tcx,
+                self.body,
+                self.move_data(),
+                self.move_data().rev_lookup.find(place.as_ref()),
+                |mpi| {
+                    trans.gen(mpi);
+                },
+            );
+        });
     }
 }
 
@@ -679,9 +679,7 @@ impl<'tcx> GenKillAnalysis<'tcx> for EverInitializedPlaces<'_, 'tcx> {
         &self,
         trans: &mut impl GenKill<Self::Idx>,
         block: mir::BasicBlock,
-        _func: &mir::Operand<'tcx>,
-        _args: &[mir::Operand<'tcx>],
-        _dest_place: mir::Place<'tcx>,
+        _return_places: CallReturnPlaces<'_, 'tcx>,
     ) {
         let move_data = self.move_data();
         let init_loc_map = &move_data.init_loc_map;
diff --git a/compiler/rustc_mir_dataflow/src/impls/storage_liveness.rs b/compiler/rustc_mir_dataflow/src/impls/storage_liveness.rs
index b468e50b391..108357abc0d 100644
--- a/compiler/rustc_mir_dataflow/src/impls/storage_liveness.rs
+++ b/compiler/rustc_mir_dataflow/src/impls/storage_liveness.rs
@@ -1,7 +1,7 @@
 pub use super::*;
 
 use crate::storage::AlwaysLiveLocals;
-use crate::{GenKill, Results, ResultsRefCursor};
+use crate::{CallReturnPlaces, GenKill, Results, ResultsRefCursor};
 use rustc_middle::mir::visit::{NonMutatingUseContext, PlaceContext, Visitor};
 use rustc_middle::mir::*;
 use std::cell::RefCell;
@@ -68,9 +68,7 @@ impl crate::GenKillAnalysis<'tcx> for MaybeStorageLive {
         &self,
         _trans: &mut impl GenKill<Self::Idx>,
         _block: BasicBlock,
-        _func: &mir::Operand<'tcx>,
-        _args: &[mir::Operand<'tcx>],
-        _return_place: mir::Place<'tcx>,
+        _return_places: CallReturnPlaces<'_, 'tcx>,
     ) {
         // Nothing to do when a call returns successfully
     }
@@ -226,7 +224,7 @@ impl<'mir, 'tcx> crate::GenKillAnalysis<'tcx> for MaybeRequiresStorage<'mir, 'tc
         terminator: &mir::Terminator<'tcx>,
         loc: Location,
     ) {
-        match &terminator.kind {
+        match terminator.kind {
             // For call terminators the destination requires storage for the call
             // and after the call returns successfully, but not after a panic.
             // Since `propagate_call_unwind` doesn't exist, we have to kill the
@@ -235,6 +233,11 @@ impl<'mir, 'tcx> crate::GenKillAnalysis<'tcx> for MaybeRequiresStorage<'mir, 'tc
                 trans.kill(place.local);
             }
 
+            // The same applies to InlineAsm outputs.
+            TerminatorKind::InlineAsm { ref operands, .. } => {
+                CallReturnPlaces::InlineAsm(operands).for_each(|place| trans.kill(place.local));
+            }
+
             // Nothing to do for these. Match exhaustively so this fails to compile when new
             // variants are added.
             TerminatorKind::Call { destination: None, .. }
@@ -247,7 +250,6 @@ impl<'mir, 'tcx> crate::GenKillAnalysis<'tcx> for MaybeRequiresStorage<'mir, 'tc
             | TerminatorKind::FalseUnwind { .. }
             | TerminatorKind::GeneratorDrop
             | TerminatorKind::Goto { .. }
-            | TerminatorKind::InlineAsm { .. }
             | TerminatorKind::Resume
             | TerminatorKind::Return
             | TerminatorKind::SwitchInt { .. }
@@ -261,11 +263,9 @@ impl<'mir, 'tcx> crate::GenKillAnalysis<'tcx> for MaybeRequiresStorage<'mir, 'tc
         &self,
         trans: &mut impl GenKill<Self::Idx>,
         _block: BasicBlock,
-        _func: &mir::Operand<'tcx>,
-        _args: &[mir::Operand<'tcx>],
-        return_place: mir::Place<'tcx>,
+        return_places: CallReturnPlaces<'_, 'tcx>,
     ) {
-        trans.gen(return_place.local);
+        return_places.for_each(|place| trans.gen(place.local));
     }
 
     fn yield_resume_effect(
diff --git a/compiler/rustc_mir_dataflow/src/lib.rs b/compiler/rustc_mir_dataflow/src/lib.rs
index 77a72ce63ce..10d2cf6eba0 100644
--- a/compiler/rustc_mir_dataflow/src/lib.rs
+++ b/compiler/rustc_mir_dataflow/src/lib.rs
@@ -28,9 +28,9 @@ pub use self::drop_flag_effects::{
     on_lookup_result_bits,
 };
 pub use self::framework::{
-    fmt, graphviz, lattice, visit_results, Analysis, AnalysisDomain, Backward, Direction, Engine,
-    Forward, GenKill, GenKillAnalysis, JoinSemiLattice, Results, ResultsCursor, ResultsRefCursor,
-    ResultsVisitable, ResultsVisitor,
+    fmt, graphviz, lattice, visit_results, Analysis, AnalysisDomain, Backward, CallReturnPlaces,
+    Direction, Engine, Forward, GenKill, GenKillAnalysis, JoinSemiLattice, Results, ResultsCursor,
+    ResultsRefCursor, ResultsVisitable, ResultsVisitor,
 };
 
 use self::move_paths::MoveData;
diff --git a/compiler/rustc_mir_dataflow/src/move_paths/builder.rs b/compiler/rustc_mir_dataflow/src/move_paths/builder.rs
index e404b49ecb9..feb85d4ffdf 100644
--- a/compiler/rustc_mir_dataflow/src/move_paths/builder.rs
+++ b/compiler/rustc_mir_dataflow/src/move_paths/builder.rs
@@ -419,6 +419,7 @@ impl<'b, 'a, 'tcx> Gatherer<'b, 'a, 'tcx> {
                 options: _,
                 line_spans: _,
                 destination: _,
+                cleanup: _,
             } => {
                 for op in operands {
                     match *op {
diff --git a/compiler/rustc_mir_dataflow/src/rustc_peek.rs b/compiler/rustc_mir_dataflow/src/rustc_peek.rs
index 28e5d76783a..1746d5ee38b 100644
--- a/compiler/rustc_mir_dataflow/src/rustc_peek.rs
+++ b/compiler/rustc_mir_dataflow/src/rustc_peek.rs
@@ -20,6 +20,7 @@ use crate::{Analysis, JoinSemiLattice, Results, ResultsCursor};
 
 pub struct SanityCheck;
 
+// FIXME: This should be a `MirLint`, but it needs to be moved back to `rustc_mir_transform` first.
 impl<'tcx> MirPass<'tcx> for SanityCheck {
     fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
         use crate::has_rustc_mir_with;
diff --git a/compiler/rustc_mir_transform/src/add_retag.rs b/compiler/rustc_mir_transform/src/add_retag.rs
index 7a8dee09c29..84ae2a2fbd0 100644
--- a/compiler/rustc_mir_transform/src/add_retag.rs
+++ b/compiler/rustc_mir_transform/src/add_retag.rs
@@ -58,11 +58,11 @@ fn may_be_reference(ty: Ty<'tcx>) -> bool {
 }
 
 impl<'tcx> MirPass<'tcx> for AddRetag {
-    fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
-        if !tcx.sess.opts.debugging_opts.mir_emit_retag {
-            return;
-        }
+    fn is_enabled(&self, sess: &rustc_session::Session) -> bool {
+        sess.opts.debugging_opts.mir_emit_retag
+    }
 
+    fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
         // We need an `AllCallEdges` pass before we can do any work.
         super::add_call_guards::AllCallEdges.run_pass(tcx, body);
 
diff --git a/compiler/rustc_mir_transform/src/check_const_item_mutation.rs b/compiler/rustc_mir_transform/src/check_const_item_mutation.rs
index 27fe80a456f..6f0d03068f5 100644
--- a/compiler/rustc_mir_transform/src/check_const_item_mutation.rs
+++ b/compiler/rustc_mir_transform/src/check_const_item_mutation.rs
@@ -6,12 +6,12 @@ use rustc_middle::ty::TyCtxt;
 use rustc_session::lint::builtin::CONST_ITEM_MUTATION;
 use rustc_span::def_id::DefId;
 
-use crate::MirPass;
+use crate::MirLint;
 
 pub struct CheckConstItemMutation;
 
-impl<'tcx> MirPass<'tcx> for CheckConstItemMutation {
-    fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
+impl<'tcx> MirLint<'tcx> for CheckConstItemMutation {
+    fn run_lint(&self, tcx: TyCtxt<'tcx>, body: &Body<'tcx>) {
         let mut checker = ConstMutationChecker { body, tcx, target_local: None };
         checker.visit_body(&body);
     }
diff --git a/compiler/rustc_mir_transform/src/check_packed_ref.rs b/compiler/rustc_mir_transform/src/check_packed_ref.rs
index 49be34c7a28..31d54710309 100644
--- a/compiler/rustc_mir_transform/src/check_packed_ref.rs
+++ b/compiler/rustc_mir_transform/src/check_packed_ref.rs
@@ -7,7 +7,7 @@ use rustc_session::lint::builtin::UNALIGNED_REFERENCES;
 use rustc_span::symbol::sym;
 
 use crate::util;
-use crate::MirPass;
+use crate::MirLint;
 
 pub(crate) fn provide(providers: &mut Providers) {
     *providers = Providers { unsafe_derive_on_repr_packed, ..*providers };
@@ -15,8 +15,8 @@ pub(crate) fn provide(providers: &mut Providers) {
 
 pub struct CheckPackedRef;
 
-impl<'tcx> MirPass<'tcx> for CheckPackedRef {
-    fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
+impl<'tcx> MirLint<'tcx> for CheckPackedRef {
+    fn run_lint(&self, tcx: TyCtxt<'tcx>, body: &Body<'tcx>) {
         let param_env = tcx.param_env(body.source.def_id());
         let source_info = SourceInfo::outermost(body.span);
         let mut checker = PackedRefChecker { body, tcx, param_env, source_info };
diff --git a/compiler/rustc_mir_transform/src/check_unsafety.rs b/compiler/rustc_mir_transform/src/check_unsafety.rs
index 1ff9bd15721..cdfeb957df9 100644
--- a/compiler/rustc_mir_transform/src/check_unsafety.rs
+++ b/compiler/rustc_mir_transform/src/check_unsafety.rs
@@ -208,6 +208,7 @@ impl<'a, 'tcx> Visitor<'tcx> for UnsafetyChecker<'a, 'tcx> {
                             MutatingUseContext::Store
                                 | MutatingUseContext::Drop
                                 | MutatingUseContext::AsmOutput
+                                | MutatingUseContext::LlvmAsmOutput
                         )
                     );
                 // If this is just an assignment, determine if the assigned type needs dropping.
diff --git a/compiler/rustc_mir_transform/src/const_debuginfo.rs b/compiler/rustc_mir_transform/src/const_debuginfo.rs
index b613634560f..3613fa4560d 100644
--- a/compiler/rustc_mir_transform/src/const_debuginfo.rs
+++ b/compiler/rustc_mir_transform/src/const_debuginfo.rs
@@ -15,11 +15,11 @@ use rustc_index::{bit_set::BitSet, vec::IndexVec};
 pub struct ConstDebugInfo;
 
 impl<'tcx> MirPass<'tcx> for ConstDebugInfo {
-    fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
-        if !tcx.sess.opts.debugging_opts.unsound_mir_opts {
-            return;
-        }
+    fn is_enabled(&self, sess: &rustc_session::Session) -> bool {
+        sess.opts.debugging_opts.unsound_mir_opts && sess.mir_opt_level() > 0
+    }
 
+    fn run_pass(&self, _: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
         trace!("running ConstDebugInfo on {:?}", body.source);
 
         for (local, constant) in find_optimization_oportunities(body) {
diff --git a/compiler/rustc_mir_transform/src/const_goto.rs b/compiler/rustc_mir_transform/src/const_goto.rs
index d319fdcaa6b..beb158dd258 100644
--- a/compiler/rustc_mir_transform/src/const_goto.rs
+++ b/compiler/rustc_mir_transform/src/const_goto.rs
@@ -27,10 +27,11 @@ use super::simplify::{simplify_cfg, simplify_locals};
 pub struct ConstGoto;
 
 impl<'tcx> MirPass<'tcx> for ConstGoto {
+    fn is_enabled(&self, sess: &rustc_session::Session) -> bool {
+        sess.mir_opt_level() >= 4
+    }
+
     fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
-        if tcx.sess.mir_opt_level() < 4 {
-            return;
-        }
         trace!("Running ConstGoto on {:?}", body.source);
         let param_env = tcx.param_env_reveal_all_normalized(body.source.def_id());
         let mut opt_finder =
diff --git a/compiler/rustc_mir_transform/src/const_prop.rs b/compiler/rustc_mir_transform/src/const_prop.rs
index 63c637af5c2..e3377f5953a 100644
--- a/compiler/rustc_mir_transform/src/const_prop.rs
+++ b/compiler/rustc_mir_transform/src/const_prop.rs
@@ -62,6 +62,13 @@ macro_rules! throw_machine_stop_str {
 pub struct ConstProp;
 
 impl<'tcx> MirPass<'tcx> for ConstProp {
+    fn is_enabled(&self, _sess: &rustc_session::Session) -> bool {
+        // FIXME(#70073): Unlike the other passes in "optimizations", this one emits errors, so it
+        // runs even when MIR optimizations are disabled. We should separate the lint out from the
+        // transform and move the lint as early in the pipeline as possible.
+        true
+    }
+
     fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
         // will be evaluated by miri and produce its errors there
         if body.source.promoted.is_some() {
@@ -1022,6 +1029,7 @@ impl<'tcx> Visitor<'tcx> for CanConstProp {
             // These are just stores, where the storing is not propagatable, but there may be later
             // mutations of the same local via `Store`
             | MutatingUse(MutatingUseContext::Call)
+            | MutatingUse(MutatingUseContext::AsmOutput)
             // Actual store that can possibly even propagate a value
             | MutatingUse(MutatingUseContext::Store) => {
                 if !self.found_assignment.insert(local) {
@@ -1052,7 +1060,7 @@ impl<'tcx> Visitor<'tcx> for CanConstProp {
 
             // These could be propagated with a smarter analysis or just some careful thinking about
             // whether they'd be fine right now.
-            MutatingUse(MutatingUseContext::AsmOutput)
+            MutatingUse(MutatingUseContext::LlvmAsmOutput)
             | MutatingUse(MutatingUseContext::Yield)
             | MutatingUse(MutatingUseContext::Drop)
             | MutatingUse(MutatingUseContext::Retag)
diff --git a/compiler/rustc_mir_transform/src/coverage/mod.rs b/compiler/rustc_mir_transform/src/coverage/mod.rs
index 6807d02519e..bba188bd393 100644
--- a/compiler/rustc_mir_transform/src/coverage/mod.rs
+++ b/compiler/rustc_mir_transform/src/coverage/mod.rs
@@ -49,6 +49,10 @@ impl Error {
 pub struct InstrumentCoverage;
 
 impl<'tcx> MirPass<'tcx> for InstrumentCoverage {
+    fn is_enabled(&self, sess: &rustc_session::Session) -> bool {
+        sess.instrument_coverage()
+    }
+
     fn run_pass(&self, tcx: TyCtxt<'tcx>, mir_body: &mut mir::Body<'tcx>) {
         let mir_source = mir_body.source;
 
diff --git a/compiler/rustc_mir_transform/src/deduplicate_blocks.rs b/compiler/rustc_mir_transform/src/deduplicate_blocks.rs
index 8d2413433a9..993c8eef711 100644
--- a/compiler/rustc_mir_transform/src/deduplicate_blocks.rs
+++ b/compiler/rustc_mir_transform/src/deduplicate_blocks.rs
@@ -15,10 +15,11 @@ use super::simplify::simplify_cfg;
 pub struct DeduplicateBlocks;
 
 impl<'tcx> MirPass<'tcx> for DeduplicateBlocks {
+    fn is_enabled(&self, sess: &rustc_session::Session) -> bool {
+        sess.mir_opt_level() >= 4
+    }
+
     fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
-        if tcx.sess.mir_opt_level() < 4 {
-            return;
-        }
         debug!("Running DeduplicateBlocks on `{:?}`", body.source);
         let duplicates = find_duplicates(body);
         let has_opts_to_apply = !duplicates.is_empty();
diff --git a/compiler/rustc_mir_transform/src/dest_prop.rs b/compiler/rustc_mir_transform/src/dest_prop.rs
index c45946a9e2a..256f7fbd759 100644
--- a/compiler/rustc_mir_transform/src/dest_prop.rs
+++ b/compiler/rustc_mir_transform/src/dest_prop.rs
@@ -124,18 +124,15 @@ const MAX_BLOCKS: usize = 250;
 pub struct DestinationPropagation;
 
 impl<'tcx> MirPass<'tcx> for DestinationPropagation {
-    fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
-        //  FIXME(#79191, #82678)
-        if !tcx.sess.opts.debugging_opts.unsound_mir_opts {
-            return;
-        }
-
+    fn is_enabled(&self, sess: &rustc_session::Session) -> bool {
+        //  FIXME(#79191, #82678): This is unsound.
+        //
         // Only run at mir-opt-level=3 or higher for now (we don't fix up debuginfo and remove
         // storage statements at the moment).
-        if tcx.sess.mir_opt_level() < 3 {
-            return;
-        }
+        sess.opts.debugging_opts.unsound_mir_opts && sess.mir_opt_level() >= 3
+    }
 
+    fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
         let def_id = body.source.def_id();
 
         let candidates = find_candidates(tcx, body);
@@ -624,6 +621,7 @@ impl Conflicts<'a> {
                 options: _,
                 line_spans: _,
                 destination: _,
+                cleanup: _,
             } => {
                 // The intended semantics here aren't documented, we just assume that nothing that
                 // could be written to by the assembly may overlap with any other operands.
diff --git a/compiler/rustc_mir_transform/src/early_otherwise_branch.rs b/compiler/rustc_mir_transform/src/early_otherwise_branch.rs
index f191911a6c7..62e82aca262 100644
--- a/compiler/rustc_mir_transform/src/early_otherwise_branch.rs
+++ b/compiler/rustc_mir_transform/src/early_otherwise_branch.rs
@@ -25,16 +25,14 @@ use super::simplify::simplify_cfg;
 pub struct EarlyOtherwiseBranch;
 
 impl<'tcx> MirPass<'tcx> for EarlyOtherwiseBranch {
-    fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
+    fn is_enabled(&self, sess: &rustc_session::Session) -> bool {
         //  FIXME(#78496)
-        if !tcx.sess.opts.debugging_opts.unsound_mir_opts {
-            return;
-        }
+        sess.opts.debugging_opts.unsound_mir_opts && sess.mir_opt_level() >= 3
+    }
 
-        if tcx.sess.mir_opt_level() < 3 {
-            return;
-        }
+    fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
         trace!("running EarlyOtherwiseBranch on {:?}", body.source);
+
         // we are only interested in this bb if the terminator is a switchInt
         let bbs_with_switch =
             body.basic_blocks().iter_enumerated().filter(|(_, bb)| is_switch(bb.terminator()));
diff --git a/compiler/rustc_mir_transform/src/elaborate_drops.rs b/compiler/rustc_mir_transform/src/elaborate_drops.rs
index b9a48197a35..af13c734e5b 100644
--- a/compiler/rustc_mir_transform/src/elaborate_drops.rs
+++ b/compiler/rustc_mir_transform/src/elaborate_drops.rs
@@ -19,6 +19,10 @@ use std::fmt;
 pub struct ElaborateDrops;
 
 impl<'tcx> MirPass<'tcx> for ElaborateDrops {
+    fn phase_change(&self) -> Option<MirPhase> {
+        Some(MirPhase::DropLowering)
+    }
+
     fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
         debug!("elaborate_drops({:?} @ {:?})", body.source, body.span);
 
diff --git a/compiler/rustc_mir_transform/src/function_item_references.rs b/compiler/rustc_mir_transform/src/function_item_references.rs
index 996c158c062..c05dc39afc4 100644
--- a/compiler/rustc_mir_transform/src/function_item_references.rs
+++ b/compiler/rustc_mir_transform/src/function_item_references.rs
@@ -11,12 +11,12 @@ use rustc_session::lint::builtin::FUNCTION_ITEM_REFERENCES;
 use rustc_span::{symbol::sym, Span};
 use rustc_target::spec::abi::Abi;
 
-use crate::MirPass;
+use crate::MirLint;
 
 pub struct FunctionItemReferences;
 
-impl<'tcx> MirPass<'tcx> for FunctionItemReferences {
-    fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
+impl<'tcx> MirLint<'tcx> for FunctionItemReferences {
+    fn run_lint(&self, tcx: TyCtxt<'tcx>, body: &Body<'tcx>) {
         let mut checker = FunctionItemRefChecker { tcx, body };
         checker.visit_body(&body);
     }
diff --git a/compiler/rustc_mir_transform/src/generator.rs b/compiler/rustc_mir_transform/src/generator.rs
index bc72e9d94a9..5376855035e 100644
--- a/compiler/rustc_mir_transform/src/generator.rs
+++ b/compiler/rustc_mir_transform/src/generator.rs
@@ -1232,6 +1232,10 @@ fn create_cases<'tcx>(
 }
 
 impl<'tcx> MirPass<'tcx> for StateTransform {
+    fn phase_change(&self) -> Option<MirPhase> {
+        Some(MirPhase::GeneratorLowering)
+    }
+
     fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
         let yield_ty = if let Some(yield_ty) = body.yield_ty() {
             yield_ty
diff --git a/compiler/rustc_mir_transform/src/inline.rs b/compiler/rustc_mir_transform/src/inline.rs
index 84a1e3fb600..81454cc4070 100644
--- a/compiler/rustc_mir_transform/src/inline.rs
+++ b/compiler/rustc_mir_transform/src/inline.rs
@@ -37,21 +37,16 @@ struct CallSite<'tcx> {
     source_info: SourceInfo,
 }
 
-/// Returns true if MIR inlining is enabled in the current compilation session.
-crate fn is_enabled(tcx: TyCtxt<'_>) -> bool {
-    if let Some(enabled) = tcx.sess.opts.debugging_opts.inline_mir {
-        return enabled;
-    }
-
-    tcx.sess.mir_opt_level() >= 3
-}
-
 impl<'tcx> MirPass<'tcx> for Inline {
-    fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
-        if !is_enabled(tcx) {
-            return;
+    fn is_enabled(&self, sess: &rustc_session::Session) -> bool {
+        if let Some(enabled) = sess.opts.debugging_opts.inline_mir {
+            return enabled;
         }
 
+        sess.opts.mir_opt_level() >= 3
+    }
+
+    fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
         let span = trace_span!("inline", body = %tcx.def_path_str(body.source.def_id()));
         let _guard = span.enter();
         if inline(tcx, body) {
@@ -441,6 +436,13 @@ impl Inliner<'tcx> {
                     }
                 }
                 TerminatorKind::Resume => cost += RESUME_PENALTY,
+                TerminatorKind::InlineAsm { cleanup, .. } => {
+                    cost += INSTR_COST;
+
+                    if cleanup.is_some() {
+                        cost += LANDINGPAD_PENALTY;
+                    }
+                }
                 _ => cost += INSTR_COST,
             }
 
@@ -954,9 +956,13 @@ impl<'a, 'tcx> MutVisitor<'tcx> for Integrator<'a, 'tcx> {
             {
                 bug!("False unwinds should have been removed before inlining")
             }
-            TerminatorKind::InlineAsm { ref mut destination, .. } => {
+            TerminatorKind::InlineAsm { ref mut destination, ref mut cleanup, .. } => {
                 if let Some(ref mut tgt) = *destination {
                     *tgt = self.map_block(*tgt);
+                } else if !self.in_cleanup_block {
+                    // Unless this inline asm is in a cleanup block, add an unwind edge to
+                    // the original call's cleanup block
+                    *cleanup = self.cleanup_block;
                 }
             }
         }
diff --git a/compiler/rustc_mir_transform/src/instcombine.rs b/compiler/rustc_mir_transform/src/instcombine.rs
index e15a69c95ae..c5adc241664 100644
--- a/compiler/rustc_mir_transform/src/instcombine.rs
+++ b/compiler/rustc_mir_transform/src/instcombine.rs
@@ -11,6 +11,10 @@ use rustc_middle::ty::{self, TyCtxt};
 pub struct InstCombine;
 
 impl<'tcx> MirPass<'tcx> for InstCombine {
+    fn is_enabled(&self, sess: &rustc_session::Session) -> bool {
+        sess.mir_opt_level() > 0
+    }
+
     fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
         let (basic_blocks, local_decls) = body.basic_blocks_and_local_decls_mut();
         let ctx = InstCombineContext { tcx, local_decls };
diff --git a/compiler/rustc_mir_transform/src/lib.rs b/compiler/rustc_mir_transform/src/lib.rs
index acbea9bda11..a7e003a55b4 100644
--- a/compiler/rustc_mir_transform/src/lib.rs
+++ b/compiler/rustc_mir_transform/src/lib.rs
@@ -27,11 +27,16 @@ use rustc_hir::def_id::{DefId, LocalDefId};
 use rustc_hir::intravisit::{self, NestedVisitorMap, Visitor};
 use rustc_index::vec::IndexVec;
 use rustc_middle::mir::visit::Visitor as _;
-use rustc_middle::mir::{dump_mir, traversal, Body, ConstQualifs, MirPass, MirPhase, Promoted};
+use rustc_middle::mir::{traversal, Body, ConstQualifs, MirPass, MirPhase, Promoted};
 use rustc_middle::ty::query::Providers;
 use rustc_middle::ty::{self, TyCtxt, TypeFoldable};
 use rustc_span::{Span, Symbol};
 
+#[macro_use]
+mod pass_manager;
+
+use pass_manager::{self as pm, Lint, MirLint, WithMinOptLevel};
+
 mod abort_unwinding_calls;
 mod add_call_guards;
 mod add_moves_for_packed_drops;
@@ -56,6 +61,7 @@ mod inline;
 mod instcombine;
 mod lower_intrinsics;
 mod lower_slice_len;
+mod marker;
 mod match_branches;
 mod multiple_return_terminators;
 mod normalize_array_len;
@@ -168,66 +174,6 @@ fn mir_keys(tcx: TyCtxt<'_>, (): ()) -> FxHashSet<LocalDefId> {
     set
 }
 
-fn run_passes(
-    tcx: TyCtxt<'tcx>,
-    body: &mut Body<'tcx>,
-    mir_phase: MirPhase,
-    passes: &[&[&dyn MirPass<'tcx>]],
-) {
-    let phase_index = mir_phase.phase_index();
-    let validate = tcx.sess.opts.debugging_opts.validate_mir;
-
-    if body.phase >= mir_phase {
-        return;
-    }
-
-    if validate {
-        validate::Validator { when: format!("input to phase {:?}", mir_phase), mir_phase }
-            .run_pass(tcx, body);
-    }
-
-    let mut index = 0;
-    let mut run_pass = |pass: &dyn MirPass<'tcx>| {
-        let run_hooks = |body: &_, index, is_after| {
-            let disambiguator = if is_after { "after" } else { "before" };
-            dump_mir(
-                tcx,
-                Some(&format_args!("{:03}-{:03}", phase_index, index)),
-                &pass.name(),
-                &disambiguator,
-                body,
-                |_, _| Ok(()),
-            );
-        };
-        run_hooks(body, index, false);
-        pass.run_pass(tcx, body);
-        run_hooks(body, index, true);
-
-        if validate {
-            validate::Validator {
-                when: format!("after {} in phase {:?}", pass.name(), mir_phase),
-                mir_phase,
-            }
-            .run_pass(tcx, body);
-        }
-
-        index += 1;
-    };
-
-    for pass_group in passes {
-        for pass in *pass_group {
-            run_pass(*pass);
-        }
-    }
-
-    body.phase = mir_phase;
-
-    if mir_phase == MirPhase::Optimization {
-        validate::Validator { when: format!("end of phase {:?}", mir_phase), mir_phase }
-            .run_pass(tcx, body);
-    }
-}
-
 fn mir_const_qualif(tcx: TyCtxt<'_>, def: ty::WithOptConstParam<LocalDefId>) -> ConstQualifs {
     let const_kind = tcx.hir().body_const_context(def.did);
 
@@ -279,19 +225,19 @@ fn mir_const<'tcx>(
 
     rustc_middle::mir::dump_mir(tcx, None, "mir_map", &0, &body, |_, _| Ok(()));
 
-    run_passes(
+    pm::run_passes(
         tcx,
         &mut body,
-        MirPhase::Const,
-        &[&[
+        &[
             // MIR-level lints.
-            &check_packed_ref::CheckPackedRef,
-            &check_const_item_mutation::CheckConstItemMutation,
-            &function_item_references::FunctionItemReferences,
+            &Lint(check_packed_ref::CheckPackedRef),
+            &Lint(check_const_item_mutation::CheckConstItemMutation),
+            &Lint(function_item_references::FunctionItemReferences),
             // What we need to do constant evaluation.
             &simplify::SimplifyCfg::new("initial"),
-            &rustc_peek::SanityCheck,
-        ]],
+            &rustc_peek::SanityCheck, // Just a lint
+            &marker::PhaseChange(MirPhase::Const),
+        ],
     );
     tcx.alloc_steal_mir(body)
 }
@@ -318,17 +264,17 @@ fn mir_promoted(
     }
     body.required_consts = required_consts;
 
+    // What we need to run borrowck etc.
     let promote_pass = promote_consts::PromoteTemps::default();
-    let promote: &[&dyn MirPass<'tcx>] = &[
-        // What we need to run borrowck etc.
-        &promote_pass,
-        &simplify::SimplifyCfg::new("promote-consts"),
-    ];
-
-    let opt_coverage: &[&dyn MirPass<'tcx>] =
-        if tcx.sess.instrument_coverage() { &[&coverage::InstrumentCoverage] } else { &[] };
-
-    run_passes(tcx, &mut body, MirPhase::ConstPromotion, &[promote, opt_coverage]);
+    pm::run_passes(
+        tcx,
+        &mut body,
+        &[
+            &promote_pass,
+            &simplify::SimplifyCfg::new("promote-consts"),
+            &coverage::InstrumentCoverage,
+        ],
+    );
 
     let promoted = promote_pass.promoted_fragments.into_inner();
     (tcx.alloc_steal_mir(body), tcx.alloc_steal_promoted(promoted))
@@ -390,19 +336,10 @@ fn inner_mir_for_ctfe(tcx: TyCtxt<'_>, def: ty::WithOptConstParam<LocalDefId>) -
         // Technically we want to not run on regular const items, but oli-obk doesn't know how to
         // conveniently detect that at this point without looking at the HIR.
         hir::ConstContext::Const => {
-            #[rustfmt::skip]
-            let optimizations: &[&dyn MirPass<'_>] = &[
-                &const_prop::ConstProp,
-            ];
-
-            #[rustfmt::skip]
-            run_passes(
+            pm::run_passes(
                 tcx,
                 &mut body,
-                MirPhase::Optimization,
-                &[
-                    optimizations,
-                ],
+                &[&const_prop::ConstProp, &marker::PhaseChange(MirPhase::Optimization)],
             );
         }
     }
@@ -438,7 +375,7 @@ fn mir_drops_elaborated_and_const_checked<'tcx>(
         let def = ty::WithOptConstParam::unknown(did);
 
         // Do not compute the mir call graph without said call graph actually being used.
-        if inline::is_enabled(tcx) {
+        if inline::Inline.is_enabled(&tcx.sess) {
             let _ = tcx.mir_inliner_callees(ty::InstanceDef::Item(def));
         }
     }
@@ -447,19 +384,23 @@ fn mir_drops_elaborated_and_const_checked<'tcx>(
     let mut body = body.steal();
 
     // IMPORTANT
-    remove_false_edges::RemoveFalseEdges.run_pass(tcx, &mut body);
+    pm::run_passes(tcx, &mut body, &[&remove_false_edges::RemoveFalseEdges]);
 
     // Do a little drop elaboration before const-checking if `const_precise_live_drops` is enabled.
-    //
-    // FIXME: Can't use `run_passes` for these, since `run_passes` SILENTLY DOES NOTHING IF THE MIR
-    // PHASE DOESN'T CHANGE.
     if check_consts::post_drop_elaboration::checking_enabled(&ConstCx::new(tcx, &body)) {
-        simplify::SimplifyCfg::new("remove-false-edges").run_pass(tcx, &mut body);
-        remove_uninit_drops::RemoveUninitDrops.run_pass(tcx, &mut body);
-        check_consts::post_drop_elaboration::check_live_drops(tcx, &body);
+        pm::run_passes(
+            tcx,
+            &mut body,
+            &[
+                &simplify::SimplifyCfg::new("remove-false-edges"),
+                &remove_uninit_drops::RemoveUninitDrops,
+            ],
+        );
+        check_consts::post_drop_elaboration::check_live_drops(tcx, &body); // FIXME: make this a MIR lint
     }
 
     run_post_borrowck_cleanup_passes(tcx, &mut body);
+    assert!(body.phase == MirPhase::DropLowering);
     tcx.alloc_steal_mir(body)
 }
 
@@ -493,95 +434,73 @@ fn run_post_borrowck_cleanup_passes<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tc
         &deaggregator::Deaggregator,
     ];
 
-    run_passes(tcx, body, MirPhase::DropLowering, &[post_borrowck_cleanup]);
+    pm::run_passes(tcx, body, post_borrowck_cleanup);
 }
 
 fn run_optimization_passes<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
-    let mir_opt_level = tcx.sess.mir_opt_level();
+    fn o1<T>(x: T) -> WithMinOptLevel<T> {
+        WithMinOptLevel(1, x)
+    }
 
     // Lowering generator control-flow and variables has to happen before we do anything else
     // to them. We run some optimizations before that, because they may be harder to do on the state
     // machine than on MIR with async primitives.
-    let optimizations_with_generators: &[&dyn MirPass<'tcx>] = &[
-        &reveal_all::RevealAll, // has to be done before inlining, since inlined code is in RevealAll mode.
-        &lower_slice_len::LowerSliceLenCalls, // has to be done before inlining, otherwise actual call will be almost always inlined. Also simple, so can just do first
-        &normalize_array_len::NormalizeArrayLen, // has to run after `slice::len` lowering
-        &unreachable_prop::UnreachablePropagation,
-        &uninhabited_enum_branching::UninhabitedEnumBranching,
-        &simplify::SimplifyCfg::new("after-uninhabited-enum-branching"),
-        &inline::Inline,
-        &generator::StateTransform,
-    ];
-
-    // Even if we don't do optimizations, we still have to lower generators for codegen.
-    let no_optimizations_with_generators: &[&dyn MirPass<'tcx>] = &[&generator::StateTransform];
-
-    // The main optimizations that we do on MIR.
-    let optimizations: &[&dyn MirPass<'tcx>] = &[
-        &remove_storage_markers::RemoveStorageMarkers,
-        &remove_zsts::RemoveZsts,
-        &const_goto::ConstGoto,
-        &remove_unneeded_drops::RemoveUnneededDrops,
-        &match_branches::MatchBranchSimplification,
-        // inst combine is after MatchBranchSimplification to clean up Ne(_1, false)
-        &multiple_return_terminators::MultipleReturnTerminators,
-        &instcombine::InstCombine,
-        &separate_const_switch::SeparateConstSwitch,
-        &const_prop::ConstProp,
-        &simplify_branches::SimplifyConstCondition::new("after-const-prop"),
-        &early_otherwise_branch::EarlyOtherwiseBranch,
-        &simplify_comparison_integral::SimplifyComparisonIntegral,
-        &simplify_try::SimplifyArmIdentity,
-        &simplify_try::SimplifyBranchSame,
-        &dest_prop::DestinationPropagation,
-        &simplify_branches::SimplifyConstCondition::new("final"),
-        &remove_noop_landing_pads::RemoveNoopLandingPads,
-        &simplify::SimplifyCfg::new("final"),
-        &nrvo::RenameReturnPlace,
-        &const_debuginfo::ConstDebugInfo,
-        &simplify::SimplifyLocals,
-        &multiple_return_terminators::MultipleReturnTerminators,
-        &deduplicate_blocks::DeduplicateBlocks,
-    ];
-
-    // Optimizations to run even if mir optimizations have been disabled.
-    let no_optimizations: &[&dyn MirPass<'tcx>] = &[
-        // FIXME(#70073): This pass is responsible for both optimization as well as some lints.
-        &const_prop::ConstProp,
-    ];
-
-    // Some cleanup necessary at least for LLVM and potentially other codegen backends.
-    let pre_codegen_cleanup: &[&dyn MirPass<'tcx>] = &[
-        &add_call_guards::CriticalCallEdges,
-        // Dump the end result for testing and debugging purposes.
-        &dump_mir::Marker("PreCodegen"),
-    ];
-
-    // End of pass declarations, now actually run the passes.
-    // Generator Lowering
-    #[rustfmt::skip]
-    run_passes(
+    pm::run_passes(
         tcx,
         body,
-        MirPhase::GeneratorLowering,
         &[
-            if mir_opt_level > 0 {
-                optimizations_with_generators
-            } else {
-                no_optimizations_with_generators
-            }
+            &reveal_all::RevealAll, // has to be done before inlining, since inlined code is in RevealAll mode.
+            &lower_slice_len::LowerSliceLenCalls, // has to be done before inlining, otherwise actual call will be almost always inlined. Also simple, so can just do first
+            &normalize_array_len::NormalizeArrayLen, // has to run after `slice::len` lowering
+            &unreachable_prop::UnreachablePropagation,
+            &uninhabited_enum_branching::UninhabitedEnumBranching,
+            &o1(simplify::SimplifyCfg::new("after-uninhabited-enum-branching")),
+            &inline::Inline,
+            &generator::StateTransform,
         ],
     );
 
-    // Main optimization passes
-    #[rustfmt::skip]
-    run_passes(
+    assert!(body.phase == MirPhase::GeneratorLowering);
+
+    // The main optimizations that we do on MIR.
+    pm::run_passes(
         tcx,
         body,
-        MirPhase::Optimization,
         &[
-            if mir_opt_level > 0 { optimizations } else { no_optimizations },
-            pre_codegen_cleanup,
+            &remove_storage_markers::RemoveStorageMarkers,
+            &remove_zsts::RemoveZsts,
+            &const_goto::ConstGoto,
+            &remove_unneeded_drops::RemoveUnneededDrops,
+            &match_branches::MatchBranchSimplification,
+            // inst combine is after MatchBranchSimplification to clean up Ne(_1, false)
+            &multiple_return_terminators::MultipleReturnTerminators,
+            &instcombine::InstCombine,
+            &separate_const_switch::SeparateConstSwitch,
+            //
+            // FIXME(#70073): This pass is responsible for both optimization as well as some lints.
+            &const_prop::ConstProp,
+            //
+            // FIXME: The old pass manager ran this only at mir-opt-level >= 1, but
+            // const-prop runs unconditionally. Should this run unconditionally as well?
+            &o1(simplify_branches::SimplifyConstCondition::new("after-const-prop")),
+            &early_otherwise_branch::EarlyOtherwiseBranch,
+            &simplify_comparison_integral::SimplifyComparisonIntegral,
+            &simplify_try::SimplifyArmIdentity,
+            &simplify_try::SimplifyBranchSame,
+            &dest_prop::DestinationPropagation,
+            &o1(simplify_branches::SimplifyConstCondition::new("final")),
+            &o1(remove_noop_landing_pads::RemoveNoopLandingPads),
+            &o1(simplify::SimplifyCfg::new("final")),
+            &nrvo::RenameReturnPlace,
+            &const_debuginfo::ConstDebugInfo,
+            &simplify::SimplifyLocals,
+            &multiple_return_terminators::MultipleReturnTerminators,
+            &deduplicate_blocks::DeduplicateBlocks,
+            // Some cleanup necessary at least for LLVM and potentially other codegen backends.
+            &add_call_guards::CriticalCallEdges,
+            &marker::PhaseChange(MirPhase::Optimization),
+            // Dump the end result for testing and debugging purposes.
+            &dump_mir::Marker("PreCodegen"),
         ],
     );
 }
diff --git a/compiler/rustc_mir_transform/src/lower_slice_len.rs b/compiler/rustc_mir_transform/src/lower_slice_len.rs
index 822a372d8ce..c8297744873 100644
--- a/compiler/rustc_mir_transform/src/lower_slice_len.rs
+++ b/compiler/rustc_mir_transform/src/lower_slice_len.rs
@@ -10,6 +10,10 @@ use rustc_middle::ty::{self, TyCtxt};
 pub struct LowerSliceLenCalls;
 
 impl<'tcx> MirPass<'tcx> for LowerSliceLenCalls {
+    fn is_enabled(&self, sess: &rustc_session::Session) -> bool {
+        sess.opts.mir_opt_level() > 0
+    }
+
     fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
         lower_slice_len_calls(tcx, body)
     }
diff --git a/compiler/rustc_mir_transform/src/marker.rs b/compiler/rustc_mir_transform/src/marker.rs
new file mode 100644
index 00000000000..06819fc1d37
--- /dev/null
+++ b/compiler/rustc_mir_transform/src/marker.rs
@@ -0,0 +1,20 @@
+use std::borrow::Cow;
+
+use crate::MirPass;
+use rustc_middle::mir::{Body, MirPhase};
+use rustc_middle::ty::TyCtxt;
+
+/// Changes the MIR phase without changing the MIR itself.
+pub struct PhaseChange(pub MirPhase);
+
+impl<'tcx> MirPass<'tcx> for PhaseChange {
+    fn phase_change(&self) -> Option<MirPhase> {
+        Some(self.0)
+    }
+
+    fn name(&self) -> Cow<'_, str> {
+        Cow::from(format!("PhaseChange-{:?}", self.0))
+    }
+
+    fn run_pass(&self, _: TyCtxt<'tcx>, _body: &mut Body<'tcx>) {}
+}
diff --git a/compiler/rustc_mir_transform/src/match_branches.rs b/compiler/rustc_mir_transform/src/match_branches.rs
index c618abe9d05..3c14a324c36 100644
--- a/compiler/rustc_mir_transform/src/match_branches.rs
+++ b/compiler/rustc_mir_transform/src/match_branches.rs
@@ -40,11 +40,11 @@ pub struct MatchBranchSimplification;
 /// ```
 
 impl<'tcx> MirPass<'tcx> for MatchBranchSimplification {
-    fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
-        if tcx.sess.mir_opt_level() < 3 {
-            return;
-        }
+    fn is_enabled(&self, sess: &rustc_session::Session) -> bool {
+        sess.mir_opt_level() >= 3
+    }
 
+    fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
         let def_id = body.source.def_id();
         let param_env = tcx.param_env(def_id);
 
diff --git a/compiler/rustc_mir_transform/src/multiple_return_terminators.rs b/compiler/rustc_mir_transform/src/multiple_return_terminators.rs
index b614917a883..22b6dead99c 100644
--- a/compiler/rustc_mir_transform/src/multiple_return_terminators.rs
+++ b/compiler/rustc_mir_transform/src/multiple_return_terminators.rs
@@ -9,11 +9,11 @@ use rustc_middle::ty::TyCtxt;
 pub struct MultipleReturnTerminators;
 
 impl<'tcx> MirPass<'tcx> for MultipleReturnTerminators {
-    fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
-        if tcx.sess.mir_opt_level() < 4 {
-            return;
-        }
+    fn is_enabled(&self, sess: &rustc_session::Session) -> bool {
+        sess.mir_opt_level() >= 4
+    }
 
+    fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
         // find basic blocks with no statement and a return terminator
         let mut bbs_simple_returns = BitSet::new_empty(body.basic_blocks().len());
         let def_id = body.source.def_id();
diff --git a/compiler/rustc_mir_transform/src/normalize_array_len.rs b/compiler/rustc_mir_transform/src/normalize_array_len.rs
index a04a0b51531..0fd9e0352a2 100644
--- a/compiler/rustc_mir_transform/src/normalize_array_len.rs
+++ b/compiler/rustc_mir_transform/src/normalize_array_len.rs
@@ -14,11 +14,11 @@ const MAX_NUM_LOCALS: usize = 3000;
 pub struct NormalizeArrayLen;
 
 impl<'tcx> MirPass<'tcx> for NormalizeArrayLen {
-    fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
-        if tcx.sess.mir_opt_level() < 4 {
-            return;
-        }
+    fn is_enabled(&self, sess: &rustc_session::Session) -> bool {
+        sess.mir_opt_level() >= 4
+    }
 
+    fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
         // early returns for edge cases of highly unrolled functions
         if body.basic_blocks().len() > MAX_NUM_BLOCKS {
             return;
diff --git a/compiler/rustc_mir_transform/src/nrvo.rs b/compiler/rustc_mir_transform/src/nrvo.rs
index 3ac4e77cf9a..88ec34b73ec 100644
--- a/compiler/rustc_mir_transform/src/nrvo.rs
+++ b/compiler/rustc_mir_transform/src/nrvo.rs
@@ -33,11 +33,11 @@ use crate::MirPass;
 pub struct RenameReturnPlace;
 
 impl<'tcx> MirPass<'tcx> for RenameReturnPlace {
-    fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut mir::Body<'tcx>) {
-        if tcx.sess.mir_opt_level() == 0 {
-            return;
-        }
+    fn is_enabled(&self, sess: &rustc_session::Session) -> bool {
+        sess.mir_opt_level() > 0
+    }
 
+    fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut mir::Body<'tcx>) {
         let def_id = body.source.def_id();
         let returned_local = match local_eligible_for_nrvo(body) {
             Some(l) => l,
diff --git a/compiler/rustc_mir_transform/src/pass_manager.rs b/compiler/rustc_mir_transform/src/pass_manager.rs
new file mode 100644
index 00000000000..729b8cae5e4
--- /dev/null
+++ b/compiler/rustc_mir_transform/src/pass_manager.rs
@@ -0,0 +1,144 @@
+use std::borrow::Cow;
+
+use rustc_middle::mir::{self, Body, MirPhase};
+use rustc_middle::ty::TyCtxt;
+use rustc_session::Session;
+
+use crate::{validate, MirPass};
+
+/// Just like `MirPass`, except it cannot mutate `Body`.
+pub trait MirLint<'tcx> {
+    fn name(&self) -> Cow<'_, str> {
+        let name = std::any::type_name::<Self>();
+        if let Some(tail) = name.rfind(':') {
+            Cow::from(&name[tail + 1..])
+        } else {
+            Cow::from(name)
+        }
+    }
+
+    fn is_enabled(&self, _sess: &Session) -> bool {
+        true
+    }
+
+    fn run_lint(&self, tcx: TyCtxt<'tcx>, body: &Body<'tcx>);
+}
+
+/// An adapter for `MirLint`s that implements `MirPass`.
+#[derive(Debug, Clone)]
+pub struct Lint<T>(pub T);
+
+impl<T> MirPass<'tcx> for Lint<T>
+where
+    T: MirLint<'tcx>,
+{
+    fn name(&self) -> Cow<'_, str> {
+        self.0.name()
+    }
+
+    fn is_enabled(&self, sess: &Session) -> bool {
+        self.0.is_enabled(sess)
+    }
+
+    fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
+        self.0.run_lint(tcx, body)
+    }
+
+    fn is_mir_dump_enabled(&self) -> bool {
+        false
+    }
+}
+
+pub struct WithMinOptLevel<T>(pub u32, pub T);
+
+impl<T> MirPass<'tcx> for WithMinOptLevel<T>
+where
+    T: MirPass<'tcx>,
+{
+    fn name(&self) -> Cow<'_, str> {
+        self.1.name()
+    }
+
+    fn is_enabled(&self, sess: &Session) -> bool {
+        sess.mir_opt_level() >= self.0 as usize
+    }
+
+    fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
+        self.1.run_pass(tcx, body)
+    }
+
+    fn phase_change(&self) -> Option<MirPhase> {
+        self.1.phase_change()
+    }
+}
+
+pub fn run_passes(tcx: TyCtxt<'tcx>, body: &'mir mut Body<'tcx>, passes: &[&dyn MirPass<'tcx>]) {
+    let start_phase = body.phase;
+    let mut cnt = 0;
+
+    let validate = tcx.sess.opts.debugging_opts.validate_mir;
+
+    if validate {
+        validate_body(tcx, body, format!("start of phase transition from {:?}", start_phase));
+    }
+
+    for pass in passes {
+        if !pass.is_enabled(&tcx.sess) {
+            continue;
+        }
+
+        let name = pass.name();
+        let dump_enabled = pass.is_mir_dump_enabled();
+
+        if dump_enabled {
+            dump_mir(tcx, body, start_phase, &name, cnt, false);
+        }
+
+        pass.run_pass(tcx, body);
+
+        if dump_enabled {
+            dump_mir(tcx, body, start_phase, &name, cnt, true);
+            cnt += 1;
+        }
+
+        if let Some(new_phase) = pass.phase_change() {
+            if body.phase >= new_phase {
+                panic!("Invalid MIR phase transition from {:?} to {:?}", body.phase, new_phase);
+            }
+
+            body.phase = new_phase;
+        }
+
+        if validate {
+            validate_body(tcx, body, format!("after pass {}", pass.name()));
+        }
+    }
+
+    if validate || body.phase == MirPhase::Optimization {
+        validate_body(tcx, body, format!("end of phase transition to {:?}", body.phase));
+    }
+}
+
+pub fn validate_body(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>, when: String) {
+    validate::Validator { when, mir_phase: body.phase }.run_pass(tcx, body);
+}
+
+pub fn dump_mir(
+    tcx: TyCtxt<'tcx>,
+    body: &Body<'tcx>,
+    phase: MirPhase,
+    pass_name: &str,
+    cnt: usize,
+    is_after: bool,
+) {
+    let phase_index = phase as u32;
+
+    mir::dump_mir(
+        tcx,
+        Some(&format_args!("{:03}-{:03}", phase_index, cnt)),
+        pass_name,
+        if is_after { &"after" } else { &"before" },
+        body,
+        |_, _| Ok(()),
+    );
+}
diff --git a/compiler/rustc_mir_transform/src/remove_noop_landing_pads.rs b/compiler/rustc_mir_transform/src/remove_noop_landing_pads.rs
index 298bcd9dc24..2a73e341f16 100644
--- a/compiler/rustc_mir_transform/src/remove_noop_landing_pads.rs
+++ b/compiler/rustc_mir_transform/src/remove_noop_landing_pads.rs
@@ -10,18 +10,14 @@ use rustc_target::spec::PanicStrategy;
 /// code for these.
 pub struct RemoveNoopLandingPads;
 
-pub fn remove_noop_landing_pads<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
-    if tcx.sess.panic_strategy() == PanicStrategy::Abort {
-        return;
+impl<'tcx> MirPass<'tcx> for RemoveNoopLandingPads {
+    fn is_enabled(&self, sess: &rustc_session::Session) -> bool {
+        sess.panic_strategy() != PanicStrategy::Abort
     }
-    debug!("remove_noop_landing_pads({:?})", body);
-
-    RemoveNoopLandingPads.remove_nop_landing_pads(body)
-}
 
-impl<'tcx> MirPass<'tcx> for RemoveNoopLandingPads {
-    fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
-        remove_noop_landing_pads(tcx, body);
+    fn run_pass(&self, _: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
+        debug!("remove_noop_landing_pads({:?})", body);
+        self.remove_nop_landing_pads(body)
     }
 }
 
diff --git a/compiler/rustc_mir_transform/src/remove_storage_markers.rs b/compiler/rustc_mir_transform/src/remove_storage_markers.rs
index 0c7323cbac5..c9b6e1459d3 100644
--- a/compiler/rustc_mir_transform/src/remove_storage_markers.rs
+++ b/compiler/rustc_mir_transform/src/remove_storage_markers.rs
@@ -7,6 +7,10 @@ use rustc_middle::ty::TyCtxt;
 pub struct RemoveStorageMarkers;
 
 impl<'tcx> MirPass<'tcx> for RemoveStorageMarkers {
+    fn is_enabled(&self, sess: &rustc_session::Session) -> bool {
+        sess.mir_opt_level() > 0
+    }
+
     fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
         if tcx.sess.emit_lifetime_markers() {
             return;
diff --git a/compiler/rustc_mir_transform/src/remove_zsts.rs b/compiler/rustc_mir_transform/src/remove_zsts.rs
index d93ffa38c69..1d912e61409 100644
--- a/compiler/rustc_mir_transform/src/remove_zsts.rs
+++ b/compiler/rustc_mir_transform/src/remove_zsts.rs
@@ -8,6 +8,10 @@ use rustc_middle::ty::{self, Ty, TyCtxt};
 pub struct RemoveZsts;
 
 impl<'tcx> MirPass<'tcx> for RemoveZsts {
+    fn is_enabled(&self, sess: &rustc_session::Session) -> bool {
+        sess.mir_opt_level() > 0
+    }
+
     fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
         // Avoid query cycles (generators require optimized MIR for layout).
         if tcx.type_of(body.source.def_id()).is_generator() {
diff --git a/compiler/rustc_mir_transform/src/reveal_all.rs b/compiler/rustc_mir_transform/src/reveal_all.rs
index 3bcb71b64f4..a717dd3e0cd 100644
--- a/compiler/rustc_mir_transform/src/reveal_all.rs
+++ b/compiler/rustc_mir_transform/src/reveal_all.rs
@@ -8,15 +8,18 @@ use rustc_middle::ty::{self, Ty, TyCtxt};
 pub struct RevealAll;
 
 impl<'tcx> MirPass<'tcx> for RevealAll {
+    fn is_enabled(&self, sess: &rustc_session::Session) -> bool {
+        sess.opts.mir_opt_level() >= 3 || super::inline::Inline.is_enabled(sess)
+    }
+
     fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
-        // This pass must run before inlining, since we insert callee bodies in RevealAll mode.
         // Do not apply this transformation to generators.
-        if (tcx.sess.mir_opt_level() >= 3 || super::inline::is_enabled(tcx))
-            && body.generator.is_none()
-        {
-            let param_env = tcx.param_env_reveal_all_normalized(body.source.def_id());
-            RevealAllVisitor { tcx, param_env }.visit_body(body);
+        if body.generator.is_some() {
+            return;
         }
+
+        let param_env = tcx.param_env_reveal_all_normalized(body.source.def_id());
+        RevealAllVisitor { tcx, param_env }.visit_body(body);
     }
 }
 
diff --git a/compiler/rustc_mir_transform/src/separate_const_switch.rs b/compiler/rustc_mir_transform/src/separate_const_switch.rs
index 3002e7041b0..7450d53ba71 100644
--- a/compiler/rustc_mir_transform/src/separate_const_switch.rs
+++ b/compiler/rustc_mir_transform/src/separate_const_switch.rs
@@ -45,11 +45,11 @@ use smallvec::SmallVec;
 pub struct SeparateConstSwitch;
 
 impl<'tcx> MirPass<'tcx> for SeparateConstSwitch {
-    fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
-        if tcx.sess.mir_opt_level() < 4 {
-            return;
-        }
+    fn is_enabled(&self, sess: &rustc_session::Session) -> bool {
+        sess.mir_opt_level() >= 4
+    }
 
+    fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
         // If execution did something, applying a simplification layer
         // helps later passes optimize the copy away.
         if separate_const_switch(body) > 0 {
diff --git a/compiler/rustc_mir_transform/src/shim.rs b/compiler/rustc_mir_transform/src/shim.rs
index f59aaa664f3..193a9e6ad29 100644
--- a/compiler/rustc_mir_transform/src/shim.rs
+++ b/compiler/rustc_mir_transform/src/shim.rs
@@ -17,8 +17,8 @@ use std::iter;
 
 use crate::util::expand_aggregate;
 use crate::{
-    abort_unwinding_calls, add_call_guards, add_moves_for_packed_drops, remove_noop_landing_pads,
-    run_passes, simplify,
+    abort_unwinding_calls, add_call_guards, add_moves_for_packed_drops, marker, pass_manager as pm,
+    remove_noop_landing_pads, simplify,
 };
 use rustc_middle::mir::patch::MirPatch;
 use rustc_mir_dataflow::elaborate_drops::{self, DropElaborator, DropFlagMode, DropStyle};
@@ -75,17 +75,25 @@ fn make_shim<'tcx>(tcx: TyCtxt<'tcx>, instance: ty::InstanceDef<'tcx>) -> Body<'
     };
     debug!("make_shim({:?}) = untransformed {:?}", instance, result);
 
-    run_passes(
+    // In some of the above cases, we seem to be invoking the passes for non-shim MIR bodies.
+    // If that happens, there's no need to run them again.
+    //
+    // FIXME: Is this intentional?
+    if result.phase >= MirPhase::Const {
+        return result;
+    }
+
+    pm::run_passes(
         tcx,
         &mut result,
-        MirPhase::Const,
-        &[&[
+        &[
             &add_moves_for_packed_drops::AddMovesForPackedDrops,
             &remove_noop_landing_pads::RemoveNoopLandingPads,
             &simplify::SimplifyCfg::new("make_shim"),
             &add_call_guards::CriticalCallEdges,
             &abort_unwinding_calls::AbortUnwindingCalls,
-        ]],
+            &marker::PhaseChange(MirPhase::Const),
+        ],
     );
 
     debug!("make_shim({:?}) = {:?}", instance, result);
diff --git a/compiler/rustc_mir_transform/src/simplify.rs b/compiler/rustc_mir_transform/src/simplify.rs
index d6cd505cbb5..677869a0bdb 100644
--- a/compiler/rustc_mir_transform/src/simplify.rs
+++ b/compiler/rustc_mir_transform/src/simplify.rs
@@ -368,6 +368,10 @@ fn save_unreachable_coverage(
 pub struct SimplifyLocals;
 
 impl<'tcx> MirPass<'tcx> for SimplifyLocals {
+    fn is_enabled(&self, sess: &rustc_session::Session) -> bool {
+        sess.mir_opt_level() > 0
+    }
+
     fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
         trace!("running SimplifyLocals on {:?}", body.source);
         simplify_locals(body, tcx);
diff --git a/compiler/rustc_mir_transform/src/simplify_comparison_integral.rs b/compiler/rustc_mir_transform/src/simplify_comparison_integral.rs
index 948fcd9f455..3bd68e8210d 100644
--- a/compiler/rustc_mir_transform/src/simplify_comparison_integral.rs
+++ b/compiler/rustc_mir_transform/src/simplify_comparison_integral.rs
@@ -26,6 +26,10 @@ use rustc_middle::{
 pub struct SimplifyComparisonIntegral;
 
 impl<'tcx> MirPass<'tcx> for SimplifyComparisonIntegral {
+    fn is_enabled(&self, sess: &rustc_session::Session) -> bool {
+        sess.mir_opt_level() > 0
+    }
+
     fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
         trace!("Running SimplifyComparisonIntegral on {:?}", body.source);
 
diff --git a/compiler/rustc_mir_transform/src/uninhabited_enum_branching.rs b/compiler/rustc_mir_transform/src/uninhabited_enum_branching.rs
index 2aa50611290..77bc209539b 100644
--- a/compiler/rustc_mir_transform/src/uninhabited_enum_branching.rs
+++ b/compiler/rustc_mir_transform/src/uninhabited_enum_branching.rs
@@ -70,6 +70,10 @@ fn variant_discriminants<'tcx>(
 }
 
 impl<'tcx> MirPass<'tcx> for UninhabitedEnumBranching {
+    fn is_enabled(&self, sess: &rustc_session::Session) -> bool {
+        sess.mir_opt_level() > 0
+    }
+
     fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
         if body.source.promoted.is_some() {
             return;
diff --git a/compiler/rustc_mir_transform/src/unreachable_prop.rs b/compiler/rustc_mir_transform/src/unreachable_prop.rs
index 64cd6f56a9f..37071ba6117 100644
--- a/compiler/rustc_mir_transform/src/unreachable_prop.rs
+++ b/compiler/rustc_mir_transform/src/unreachable_prop.rs
@@ -11,13 +11,13 @@ use rustc_middle::ty::TyCtxt;
 pub struct UnreachablePropagation;
 
 impl MirPass<'_> for UnreachablePropagation {
-    fn run_pass<'tcx>(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
-        if tcx.sess.mir_opt_level() < 4 {
-            // Enable only under -Zmir-opt-level=4 as in some cases (check the deeply-nested-opt
-            // perf benchmark) LLVM may spend quite a lot of time optimizing the generated code.
-            return;
-        }
+    fn is_enabled(&self, sess: &rustc_session::Session) -> bool {
+        // Enable only under -Zmir-opt-level=4 as in some cases (check the deeply-nested-opt
+        // perf benchmark) LLVM may spend quite a lot of time optimizing the generated code.
+        sess.mir_opt_level() >= 4
+    }
 
+    fn run_pass<'tcx>(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
         let mut unreachable_blocks = FxHashSet::default();
         let mut replacements = FxHashMap::default();
 
diff --git a/compiler/rustc_parse/src/parser/generics.rs b/compiler/rustc_parse/src/parser/generics.rs
index a9ab2cd3f68..07887a7a59c 100644
--- a/compiler/rustc_parse/src/parser/generics.rs
+++ b/compiler/rustc_parse/src/parser/generics.rs
@@ -92,6 +92,19 @@ impl<'a> Parser<'a> {
             let attrs = self.parse_outer_attributes()?;
             let param =
                 self.collect_tokens_trailing_token(attrs, ForceCollect::No, |this, attrs| {
+                    if this.eat_keyword_noexpect(kw::SelfUpper) {
+                        // `Self` as a generic param is invalid. Here we emit the diagnostic and continue parsing
+                        // as if `Self` never existed.
+                        this.struct_span_err(
+                            this.prev_token.span,
+                            "unexpected keyword `Self` in generic parameters",
+                        )
+                        .note("you cannot use `Self` as a generic parameter because it is reserved for associated items")
+                        .emit();
+
+                        this.eat(&token::Comma);
+                    }
+
                     let param = if this.check_lifetime() {
                         let lifetime = this.expect_lifetime();
                         // Parse lifetime parameter.
diff --git a/compiler/rustc_passes/src/check_attr.rs b/compiler/rustc_passes/src/check_attr.rs
index 7c0b3a57da9..49e6a7df103 100644
--- a/compiler/rustc_passes/src/check_attr.rs
+++ b/compiler/rustc_passes/src/check_attr.rs
@@ -1953,7 +1953,12 @@ fn is_c_like_enum(item: &Item<'_>) -> bool {
     }
 }
 
+// FIXME: Fix "Cannot determine resolution" error and remove built-in macros
+// from this check.
 fn check_invalid_crate_level_attr(tcx: TyCtxt<'_>, attrs: &[Attribute]) {
+    // Check for builtin attributes at the crate level
+    // which were unsuccessfully resolved due to cannot determine
+    // resolution for the attribute macro error.
     const ATTRS_TO_CHECK: &[Symbol] = &[
         sym::macro_export,
         sym::repr,
@@ -1961,20 +1966,39 @@ fn check_invalid_crate_level_attr(tcx: TyCtxt<'_>, attrs: &[Attribute]) {
         sym::automatically_derived,
         sym::start,
         sym::rustc_main,
+        sym::derive,
+        sym::test,
+        sym::test_case,
+        sym::global_allocator,
+        sym::bench,
     ];
 
     for attr in attrs {
-        for attr_to_check in ATTRS_TO_CHECK {
-            if attr.has_name(*attr_to_check) {
-                tcx.sess
-                    .struct_span_err(
+        // This function should only be called with crate attributes
+        // which are inner attributes always but lets check to make sure
+        if attr.style == AttrStyle::Inner {
+            for attr_to_check in ATTRS_TO_CHECK {
+                if attr.has_name(*attr_to_check) {
+                    let mut err = tcx.sess.struct_span_err(
                         attr.span,
                         &format!(
                             "`{}` attribute cannot be used at crate level",
                             attr_to_check.to_ident_string()
                         ),
-                    )
-                    .emit();
+                    );
+                    // Only emit an error with a suggestion if we can create a
+                    // string out of the attribute span
+                    if let Ok(src) = tcx.sess.source_map().span_to_snippet(attr.span) {
+                        let replacement = src.replace("#!", "#");
+                        err.span_suggestion_verbose(
+                            attr.span,
+                            "perhaps you meant to use an outer attribute",
+                            replacement,
+                            rustc_errors::Applicability::MachineApplicable,
+                        );
+                    }
+                    err.emit()
+                }
             }
         }
     }
diff --git a/compiler/rustc_query_system/src/lib.rs b/compiler/rustc_query_system/src/lib.rs
index b1295ba48cc..0da141f6836 100644
--- a/compiler/rustc_query_system/src/lib.rs
+++ b/compiler/rustc_query_system/src/lib.rs
@@ -5,7 +5,6 @@
 #![feature(iter_zip)]
 #![feature(let_else)]
 #![feature(min_specialization)]
-#![feature(thread_local_const_init)]
 #![feature(extern_types)]
 
 #[macro_use]
diff --git a/compiler/rustc_resolve/src/late/diagnostics.rs b/compiler/rustc_resolve/src/late/diagnostics.rs
index 69697f275e1..72ba3f7b980 100644
--- a/compiler/rustc_resolve/src/late/diagnostics.rs
+++ b/compiler/rustc_resolve/src/late/diagnostics.rs
@@ -1735,7 +1735,7 @@ impl<'a: 'ast, 'ast> LateResolutionVisitor<'a, '_, 'ast> {
                         (generics.span, format!("<{}>", ident))
                     };
                     // Do not suggest if this is coming from macro expansion.
-                    if !span.from_expansion() {
+                    if span.can_be_used_for_suggestions() {
                         return Some((
                             span.shrink_to_hi(),
                             msg,
@@ -1803,7 +1803,7 @@ impl<'tcx> LifetimeContext<'_, 'tcx> {
         );
         err.span_label(lifetime_ref.span, "undeclared lifetime");
         let mut suggests_in_band = false;
-        let mut suggest_note = true;
+        let mut suggested_spans = vec![];
         for missing in &self.missing_named_lifetime_spots {
             match missing {
                 MissingLifetimeSpot::Generics(generics) => {
@@ -1821,23 +1821,17 @@ impl<'tcx> LifetimeContext<'_, 'tcx> {
                         suggests_in_band = true;
                         (generics.span, format!("<{}>", lifetime_ref))
                     };
-                    if !span.from_expansion() {
+                    if suggested_spans.contains(&span) {
+                        continue;
+                    }
+                    suggested_spans.push(span);
+                    if span.can_be_used_for_suggestions() {
                         err.span_suggestion(
                             span,
                             &format!("consider introducing lifetime `{}` here", lifetime_ref),
                             sugg,
                             Applicability::MaybeIncorrect,
                         );
-                    } else if suggest_note {
-                        suggest_note = false; // Avoid displaying the same help multiple times.
-                        err.span_label(
-                            span,
-                            &format!(
-                                "lifetime `{}` is missing in item created through this procedural \
-                                 macro",
-                                lifetime_ref,
-                            ),
-                        );
                     }
                 }
                 MissingLifetimeSpot::HigherRanked { span, span_type } => {
diff --git a/compiler/rustc_session/src/options.rs b/compiler/rustc_session/src/options.rs
index 779f29e3dfe..20ef1afaab2 100644
--- a/compiler/rustc_session/src/options.rs
+++ b/compiler/rustc_session/src/options.rs
@@ -101,6 +101,29 @@ macro_rules! top_level_options {
     );
 }
 
+impl Options {
+    pub fn mir_opt_level(&self) -> usize {
+        self.debugging_opts
+            .mir_opt_level
+            .unwrap_or_else(|| if self.optimize != OptLevel::No { 2 } else { 1 })
+    }
+
+    pub fn instrument_coverage(&self) -> bool {
+        self.debugging_opts.instrument_coverage.unwrap_or(InstrumentCoverage::Off)
+            != InstrumentCoverage::Off
+    }
+
+    pub fn instrument_coverage_except_unused_generics(&self) -> bool {
+        self.debugging_opts.instrument_coverage.unwrap_or(InstrumentCoverage::Off)
+            == InstrumentCoverage::ExceptUnusedGenerics
+    }
+
+    pub fn instrument_coverage_except_unused_functions(&self) -> bool {
+        self.debugging_opts.instrument_coverage.unwrap_or(InstrumentCoverage::Off)
+            == InstrumentCoverage::ExceptUnusedFunctions
+    }
+}
+
 top_level_options!(
     /// The top-level command-line options struct.
     ///
diff --git a/compiler/rustc_session/src/session.rs b/compiler/rustc_session/src/session.rs
index 54109559a3b..52a92de842f 100644
--- a/compiler/rustc_session/src/session.rs
+++ b/compiler/rustc_session/src/session.rs
@@ -562,10 +562,7 @@ impl Session {
         self.opts.debugging_opts.binary_dep_depinfo
     }
     pub fn mir_opt_level(&self) -> usize {
-        self.opts
-            .debugging_opts
-            .mir_opt_level
-            .unwrap_or_else(|| if self.opts.optimize != config::OptLevel::No { 2 } else { 1 })
+        self.opts.mir_opt_level()
     }
 
     /// Gets the features enabled for the current compilation session.
@@ -1047,18 +1044,15 @@ impl Session {
     }
 
     pub fn instrument_coverage(&self) -> bool {
-        self.opts.debugging_opts.instrument_coverage.unwrap_or(config::InstrumentCoverage::Off)
-            != config::InstrumentCoverage::Off
+        self.opts.instrument_coverage()
     }
 
     pub fn instrument_coverage_except_unused_generics(&self) -> bool {
-        self.opts.debugging_opts.instrument_coverage.unwrap_or(config::InstrumentCoverage::Off)
-            == config::InstrumentCoverage::ExceptUnusedGenerics
+        self.opts.instrument_coverage_except_unused_generics()
     }
 
     pub fn instrument_coverage_except_unused_functions(&self) -> bool {
-        self.opts.debugging_opts.instrument_coverage.unwrap_or(config::InstrumentCoverage::Off)
-            == config::InstrumentCoverage::ExceptUnusedFunctions
+        self.opts.instrument_coverage_except_unused_functions()
     }
 
     pub fn is_proc_macro_attr(&self, attr: &Attribute) -> bool {
diff --git a/compiler/rustc_span/src/lib.rs b/compiler/rustc_span/src/lib.rs
index 66c01140abc..ea3d3363b80 100644
--- a/compiler/rustc_span/src/lib.rs
+++ b/compiler/rustc_span/src/lib.rs
@@ -20,7 +20,6 @@
 #![feature(negative_impls)]
 #![feature(nll)]
 #![feature(min_specialization)]
-#![feature(thread_local_const_init)]
 
 #[macro_use]
 extern crate rustc_macros;
@@ -551,6 +550,16 @@ impl Span {
         matches!(self.ctxt().outer_expn_data().kind, ExpnKind::Macro(MacroKind::Derive, _))
     }
 
+    /// Gate suggestions that would not be appropriate in a context the user didn't write.
+    pub fn can_be_used_for_suggestions(self) -> bool {
+        !self.from_expansion()
+        // FIXME: If this span comes from a `derive` macro but it points at code the user wrote,
+        // the callsite span and the span will be pointing at different places. It also means that
+        // we can safely provide suggestions on this span.
+            || (matches!(self.ctxt().outer_expn_data().kind, ExpnKind::Macro(MacroKind::Derive, _))
+                && self.parent_callsite().map(|p| (p.lo(), p.hi())) != Some((self.lo(), self.hi())))
+    }
+
     #[inline]
     pub fn with_root_ctxt(lo: BytePos, hi: BytePos) -> Span {
         Span::new(lo, hi, SyntaxContext::root(), None)
diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs
index dd6ce60abfb..309c305293f 100644
--- a/compiler/rustc_span/src/symbol.rs
+++ b/compiler/rustc_span/src/symbol.rs
@@ -196,6 +196,7 @@ symbols! {
         Implied,
         Input,
         Into,
+        IntoFuture,
         IntoIterator,
         IoRead,
         IoWrite,
@@ -331,6 +332,7 @@ symbols! {
         asm_const,
         asm_experimental_arch,
         asm_sym,
+        asm_unwind,
         assert,
         assert_inhabited,
         assert_macro,
@@ -737,6 +739,7 @@ symbols! {
         inout,
         instruction_set,
         intel,
+        into_future,
         into_iter,
         intra_doc_pointers,
         intrinsics,
@@ -815,6 +818,7 @@ symbols! {
         maxnumf32,
         maxnumf64,
         may_dangle,
+        may_unwind,
         maybe_uninit,
         maybe_uninit_uninit,
         maybe_uninit_zeroed,
diff --git a/compiler/rustc_trait_selection/src/autoderef.rs b/compiler/rustc_trait_selection/src/autoderef.rs
index 46c74660f86..4c80483fc1f 100644
--- a/compiler/rustc_trait_selection/src/autoderef.rs
+++ b/compiler/rustc_trait_selection/src/autoderef.rs
@@ -3,7 +3,7 @@ use crate::traits::{self, TraitEngine};
 use rustc_errors::struct_span_err;
 use rustc_hir as hir;
 use rustc_infer::infer::InferCtxt;
-use rustc_middle::ty::{self, TraitRef, Ty, TyCtxt};
+use rustc_middle::ty::{self, TraitRef, Ty, TyCtxt, WithConstness};
 use rustc_middle::ty::{ToPredicate, TypeFoldable};
 use rustc_session::{DiagnosticMessageId, Limit};
 use rustc_span::def_id::LOCAL_CRATE;
diff --git a/compiler/rustc_trait_selection/src/infer.rs b/compiler/rustc_trait_selection/src/infer.rs
index f135f0c1b13..70816b5722b 100644
--- a/compiler/rustc_trait_selection/src/infer.rs
+++ b/compiler/rustc_trait_selection/src/infer.rs
@@ -9,6 +9,7 @@ use rustc_middle::infer::canonical::{Canonical, CanonicalizedQueryResponse, Quer
 use rustc_middle::traits::query::Fallible;
 use rustc_middle::ty::subst::SubstsRef;
 use rustc_middle::ty::ToPredicate;
+use rustc_middle::ty::WithConstness;
 use rustc_middle::ty::{self, Ty, TypeFoldable};
 use rustc_span::{Span, DUMMY_SP};
 
diff --git a/compiler/rustc_trait_selection/src/traits/auto_trait.rs b/compiler/rustc_trait_selection/src/traits/auto_trait.rs
index 3642aebaec2..54f7b91080d 100644
--- a/compiler/rustc_trait_selection/src/traits/auto_trait.rs
+++ b/compiler/rustc_trait_selection/src/traits/auto_trait.rs
@@ -370,17 +370,12 @@ impl AutoTraitFinder<'tcx> {
                 computed_preds.clone().chain(user_computed_preds.iter().cloned()),
             )
             .map(|o| o.predicate);
-            new_env = ty::ParamEnv::new(
-                tcx.mk_predicates(normalized_preds),
-                param_env.reveal(),
-                param_env.constness(),
-            );
+            new_env = ty::ParamEnv::new(tcx.mk_predicates(normalized_preds), param_env.reveal());
         }
 
         let final_user_env = ty::ParamEnv::new(
             tcx.mk_predicates(user_computed_preds.into_iter()),
             user_env.reveal(),
-            user_env.constness(),
         );
         debug!(
             "evaluate_nested_obligations(ty={:?}, trait_did={:?}): succeeded with '{:?}' \
diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs
index ed56d4c2827..d9f86fbc23b 100644
--- a/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs
+++ b/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs
@@ -24,7 +24,7 @@ use rustc_middle::ty::error::ExpectedFound;
 use rustc_middle::ty::fold::TypeFolder;
 use rustc_middle::ty::{
     self, fast_reject, AdtKind, SubtypePredicate, ToPolyTraitRef, ToPredicate, Ty, TyCtxt,
-    TypeFoldable,
+    TypeFoldable, WithConstness,
 };
 use rustc_session::DiagnosticMessageId;
 use rustc_span::symbol::{kw, sym};
diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs
index af0a39b239f..2e87d6fdd3d 100644
--- a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs
+++ b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs
@@ -21,7 +21,7 @@ use rustc_hir::lang_items::LangItem;
 use rustc_hir::{AsyncGeneratorKind, GeneratorKind, Node};
 use rustc_middle::ty::{
     self, suggest_arbitrary_trait_bound, suggest_constraining_type_param, AdtKind, DefIdTree,
-    Infer, InferTy, ToPredicate, Ty, TyCtxt, TypeFoldable,
+    Infer, InferTy, ToPredicate, Ty, TyCtxt, TypeFoldable, WithConstness,
 };
 use rustc_middle::ty::{TypeAndMut, TypeckResults};
 use rustc_session::Limit;
@@ -262,8 +262,8 @@ fn suggest_restriction(
             match generics
                 .params
                 .iter()
-                .map(|p| p.bounds_span().unwrap_or(p.span))
-                .filter(|&span| generics.span.contains(span) && span.desugaring_kind().is_none())
+                .map(|p| p.bounds_span_for_suggestions().unwrap_or(p.span.shrink_to_hi()))
+                .filter(|&span| generics.span.contains(span) && span.can_be_used_for_suggestions())
                 .max_by_key(|span| span.hi())
             {
                 // `fn foo(t: impl Trait)`
@@ -271,7 +271,7 @@ fn suggest_restriction(
                 None => (generics.span, format!("<{}>", type_param)),
                 // `fn foo<A>(t: impl Trait)`
                 //        ^^^ suggest `<A, T: Trait>` here
-                Some(span) => (span.shrink_to_hi(), format!(", {}", type_param)),
+                Some(span) => (span, format!(", {}", type_param)),
             },
             // `fn foo(t: impl Trait)`
             //                       ^ suggest `where <T as Trait>::A: Bound`
diff --git a/compiler/rustc_trait_selection/src/traits/fulfill.rs b/compiler/rustc_trait_selection/src/traits/fulfill.rs
index 8a60f9b8602..e121837c987 100644
--- a/compiler/rustc_trait_selection/src/traits/fulfill.rs
+++ b/compiler/rustc_trait_selection/src/traits/fulfill.rs
@@ -4,6 +4,7 @@ use rustc_data_structures::obligation_forest::ProcessResult;
 use rustc_data_structures::obligation_forest::{Error, ForestObligation, Outcome};
 use rustc_data_structures::obligation_forest::{ObligationForest, ObligationProcessor};
 use rustc_errors::ErrorReported;
+use rustc_hir as hir;
 use rustc_infer::traits::{SelectionError, TraitEngine, TraitEngineExt as _, TraitObligation};
 use rustc_middle::mir::interpret::ErrorHandled;
 use rustc_middle::thir::abstract_const::NotConstEvaluatable;
@@ -230,6 +231,21 @@ impl<'tcx> TraitEngine<'tcx> for FulfillmentContext<'tcx> {
         self.predicates.to_errors(CodeAmbiguity).into_iter().map(to_fulfillment_error).collect()
     }
 
+    fn select_all_with_constness_or_error(
+        &mut self,
+        infcx: &InferCtxt<'_, 'tcx>,
+        constness: rustc_hir::Constness,
+    ) -> Vec<FulfillmentError<'tcx>> {
+        {
+            let errors = self.select_with_constness_where_possible(infcx, constness);
+            if !errors.is_empty() {
+                return errors;
+            }
+        }
+
+        self.predicates.to_errors(CodeAmbiguity).into_iter().map(to_fulfillment_error).collect()
+    }
+
     fn select_where_possible(
         &mut self,
         infcx: &InferCtxt<'_, 'tcx>,
@@ -238,6 +254,15 @@ impl<'tcx> TraitEngine<'tcx> for FulfillmentContext<'tcx> {
         self.select(&mut selcx)
     }
 
+    fn select_with_constness_where_possible(
+        &mut self,
+        infcx: &InferCtxt<'_, 'tcx>,
+        constness: hir::Constness,
+    ) -> Vec<FulfillmentError<'tcx>> {
+        let mut selcx = SelectionContext::with_constness(infcx, constness);
+        self.select(&mut selcx)
+    }
+
     fn pending_obligations(&self) -> Vec<PredicateObligation<'tcx>> {
         self.predicates.map_pending_obligations(|o| o.obligation.clone())
     }
@@ -654,7 +679,12 @@ impl<'a, 'b, 'tcx> FulfillProcessor<'a, 'b, 'tcx> {
         if obligation.predicate.is_known_global() {
             // no type variables present, can use evaluation for better caching.
             // FIXME: consider caching errors too.
-            if infcx.predicate_must_hold_considering_regions(obligation) {
+            //
+            // If the predicate is considered const, then we cannot use this because
+            // it will cause false negatives in the ui tests.
+            if !self.selcx.is_predicate_const(obligation.predicate)
+                && infcx.predicate_must_hold_considering_regions(obligation)
+            {
                 debug!(
                     "selecting trait at depth {} evaluated to holds",
                     obligation.recursion_depth
@@ -708,7 +738,12 @@ impl<'a, 'b, 'tcx> FulfillProcessor<'a, 'b, 'tcx> {
         if obligation.predicate.is_global(tcx) {
             // no type variables present, can use evaluation for better caching.
             // FIXME: consider caching errors too.
-            if self.selcx.infcx().predicate_must_hold_considering_regions(obligation) {
+            //
+            // If the predicate is considered const, then we cannot use this because
+            // it will cause false negatives in the ui tests.
+            if !self.selcx.is_predicate_const(obligation.predicate)
+                && self.selcx.infcx().predicate_must_hold_considering_regions(obligation)
+            {
                 return ProcessResult::Changed(vec![]);
             } else {
                 tracing::debug!("Does NOT hold: {:?}", obligation);
diff --git a/compiler/rustc_trait_selection/src/traits/mod.rs b/compiler/rustc_trait_selection/src/traits/mod.rs
index d81b6949cae..4bc22d5d735 100644
--- a/compiler/rustc_trait_selection/src/traits/mod.rs
+++ b/compiler/rustc_trait_selection/src/traits/mod.rs
@@ -33,7 +33,8 @@ use rustc_hir::lang_items::LangItem;
 use rustc_middle::ty::fold::TypeFoldable;
 use rustc_middle::ty::subst::{InternalSubsts, SubstsRef};
 use rustc_middle::ty::{
-    self, GenericParamDefKind, ToPredicate, Ty, TyCtxt, VtblEntry, COMMON_VTABLE_ENTRIES,
+    self, GenericParamDefKind, ToPredicate, Ty, TyCtxt, VtblEntry, WithConstness,
+    COMMON_VTABLE_ENTRIES,
 };
 use rustc_span::{sym, Span};
 use smallvec::SmallVec;
@@ -306,11 +307,8 @@ pub fn normalize_param_env_or_error<'tcx>(
 
     debug!("normalize_param_env_or_error: elaborated-predicates={:?}", predicates);
 
-    let elaborated_env = ty::ParamEnv::new(
-        tcx.intern_predicates(&predicates),
-        unnormalized_env.reveal(),
-        unnormalized_env.constness(),
-    );
+    let elaborated_env =
+        ty::ParamEnv::new(tcx.intern_predicates(&predicates), unnormalized_env.reveal());
 
     // HACK: we are trying to normalize the param-env inside *itself*. The problem is that
     // normalization expects its param-env to be already normalized, which means we have
@@ -362,11 +360,8 @@ pub fn normalize_param_env_or_error<'tcx>(
     // predicates here anyway. Keeping them here anyway because it seems safer.
     let outlives_env: Vec<_> =
         non_outlives_predicates.iter().chain(&outlives_predicates).cloned().collect();
-    let outlives_env = ty::ParamEnv::new(
-        tcx.intern_predicates(&outlives_env),
-        unnormalized_env.reveal(),
-        unnormalized_env.constness(),
-    );
+    let outlives_env =
+        ty::ParamEnv::new(tcx.intern_predicates(&outlives_env), unnormalized_env.reveal());
     let outlives_predicates = match do_normalize_predicates(
         tcx,
         region_context,
@@ -386,11 +381,7 @@ pub fn normalize_param_env_or_error<'tcx>(
     let mut predicates = non_outlives_predicates;
     predicates.extend(outlives_predicates);
     debug!("normalize_param_env_or_error: final predicates={:?}", predicates);
-    ty::ParamEnv::new(
-        tcx.intern_predicates(&predicates),
-        unnormalized_env.reveal(),
-        unnormalized_env.constness(),
-    )
+    ty::ParamEnv::new(tcx.intern_predicates(&predicates), unnormalized_env.reveal())
 }
 
 pub fn fully_normalize<'a, 'tcx, T>(
@@ -573,17 +564,14 @@ fn prepare_vtable_segments<'tcx, T>(
                     .predicates
                     .into_iter()
                     .filter_map(move |(pred, _)| {
-                        pred.subst_supertrait(tcx, &inner_most_trait_ref).to_opt_poly_trait_pred()
+                        pred.subst_supertrait(tcx, &inner_most_trait_ref).to_opt_poly_trait_ref()
                     });
 
                 'diving_in_skip_visited_traits: loop {
                     if let Some(next_super_trait) = direct_super_traits_iter.next() {
                         if visited.insert(next_super_trait.to_predicate(tcx)) {
-                            // We're throwing away potential constness of super traits here.
-                            // FIXME: handle ~const super traits
-                            let next_super_trait = next_super_trait.map_bound(|t| t.trait_ref);
                             stack.push((
-                                next_super_trait,
+                                next_super_trait.value,
                                 emit_vptr_on_new_entry,
                                 Some(direct_super_traits_iter),
                             ));
@@ -615,11 +603,7 @@ fn prepare_vtable_segments<'tcx, T>(
                     if let Some(siblings) = siblings_opt {
                         if let Some(next_inner_most_trait_ref) = siblings.next() {
                             if visited.insert(next_inner_most_trait_ref.to_predicate(tcx)) {
-                                // We're throwing away potential constness of super traits here.
-                                // FIXME: handle ~const super traits
-                                let next_inner_most_trait_ref =
-                                    next_inner_most_trait_ref.map_bound(|t| t.trait_ref);
-                                *inner_most_trait_ref = next_inner_most_trait_ref;
+                                *inner_most_trait_ref = next_inner_most_trait_ref.value;
                                 *emit_vptr = emit_vptr_on_new_entry;
                                 break 'exiting_out;
                             } else {
diff --git a/compiler/rustc_trait_selection/src/traits/object_safety.rs b/compiler/rustc_trait_selection/src/traits/object_safety.rs
index 412f7923fb5..afc546540d2 100644
--- a/compiler/rustc_trait_selection/src/traits/object_safety.rs
+++ b/compiler/rustc_trait_selection/src/traits/object_safety.rs
@@ -18,7 +18,7 @@ use rustc_errors::FatalError;
 use rustc_hir as hir;
 use rustc_hir::def_id::DefId;
 use rustc_middle::ty::subst::{GenericArg, InternalSubsts, Subst};
-use rustc_middle::ty::{self, Ty, TyCtxt, TypeFoldable, TypeVisitor};
+use rustc_middle::ty::{self, Ty, TyCtxt, TypeFoldable, TypeVisitor, WithConstness};
 use rustc_middle::ty::{Predicate, ToPredicate};
 use rustc_session::lint::builtin::WHERE_CLAUSES_OBJECT_SAFETY;
 use rustc_span::symbol::Symbol;
@@ -698,11 +698,7 @@ fn receiver_is_dispatchable<'tcx>(
             .chain(array::IntoIter::new([unsize_predicate, trait_predicate]))
             .collect();
 
-        ty::ParamEnv::new(
-            tcx.intern_predicates(&caller_bounds),
-            param_env.reveal(),
-            param_env.constness(),
-        )
+        ty::ParamEnv::new(tcx.intern_predicates(&caller_bounds), param_env.reveal())
     };
 
     // Receiver: DispatchFromDyn<Receiver[Self => U]>
diff --git a/compiler/rustc_trait_selection/src/traits/project.rs b/compiler/rustc_trait_selection/src/traits/project.rs
index 79ed6656819..b8c66931cbe 100644
--- a/compiler/rustc_trait_selection/src/traits/project.rs
+++ b/compiler/rustc_trait_selection/src/traits/project.rs
@@ -27,7 +27,7 @@ use rustc_hir::lang_items::LangItem;
 use rustc_infer::infer::resolve::OpportunisticRegionResolver;
 use rustc_middle::ty::fold::{TypeFoldable, TypeFolder};
 use rustc_middle::ty::subst::Subst;
-use rustc_middle::ty::{self, ToPredicate, Ty, TyCtxt};
+use rustc_middle::ty::{self, ToPredicate, Ty, TyCtxt, WithConstness};
 use rustc_span::symbol::sym;
 
 use std::collections::BTreeMap;
diff --git a/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs b/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs
index 89c01fe3440..6e3e3b9b144 100644
--- a/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs
+++ b/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs
@@ -11,7 +11,7 @@ use rustc_infer::traits::TraitEngine;
 use rustc_infer::traits::{Obligation, SelectionError, TraitObligation};
 use rustc_lint_defs::builtin::DEREF_INTO_DYN_SUPERTRAIT;
 use rustc_middle::ty::print::with_no_trimmed_paths;
-use rustc_middle::ty::{self, ToPredicate, Ty, TypeFoldable};
+use rustc_middle::ty::{self, ToPredicate, Ty, TypeFoldable, WithConstness};
 use rustc_target::spec::abi::Abi;
 
 use crate::traits;
@@ -303,7 +303,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
             } else if lang_items.drop_trait() == Some(def_id)
                 && obligation.predicate.skip_binder().constness == ty::BoundConstness::ConstIfConst
             {
-                if obligation.param_env.constness() == hir::Constness::Const {
+                if self.is_in_const_context {
                     self.assemble_const_drop_candidates(obligation, stack, &mut candidates)?;
                 } else {
                     debug!("passing ~const Drop bound; in non-const context");
@@ -383,19 +383,17 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
             .param_env
             .caller_bounds()
             .iter()
-            .filter_map(|o| o.to_opt_poly_trait_pred());
+            .filter_map(|o| o.to_opt_poly_trait_ref());
 
         // Micro-optimization: filter out predicates relating to different traits.
         let matching_bounds =
-            all_bounds.filter(|p| p.def_id() == stack.obligation.predicate.def_id());
+            all_bounds.filter(|p| p.value.def_id() == stack.obligation.predicate.def_id());
 
         // Keep only those bounds which may apply, and propagate overflow if it occurs.
         for bound in matching_bounds {
-            // FIXME(oli-obk): it is suspicious that we are dropping the constness and
-            // polarity here.
-            let wc = self.evaluate_where_clause(stack, bound.map_bound(|t| t.trait_ref))?;
+            let wc = self.evaluate_where_clause(stack, bound.value)?;
             if wc.may_apply() {
-                candidates.vec.push(ParamCandidate(bound));
+                candidates.vec.push(ParamCandidate((bound, stack.obligation.polarity())));
             }
         }
 
diff --git a/compiler/rustc_trait_selection/src/traits/select/confirmation.rs b/compiler/rustc_trait_selection/src/traits/select/confirmation.rs
index e9b368f683e..2f1f7971a79 100644
--- a/compiler/rustc_trait_selection/src/traits/select/confirmation.rs
+++ b/compiler/rustc_trait_selection/src/traits/select/confirmation.rs
@@ -13,7 +13,7 @@ use rustc_infer::infer::InferOk;
 use rustc_infer::infer::LateBoundRegionConversionTime::HigherRankedType;
 use rustc_middle::ty::subst::{GenericArg, GenericArgKind, Subst, SubstsRef};
 use rustc_middle::ty::{self, Ty};
-use rustc_middle::ty::{ToPolyTraitRef, ToPredicate};
+use rustc_middle::ty::{ToPolyTraitRef, ToPredicate, WithConstness};
 use rustc_span::def_id::DefId;
 
 use crate::traits::project::{normalize_with_depth, normalize_with_depth_to};
@@ -58,9 +58,8 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
             }
 
             ParamCandidate(param) => {
-                let obligations =
-                    self.confirm_param_candidate(obligation, param.map_bound(|t| t.trait_ref));
-                Ok(ImplSource::Param(obligations, param.skip_binder().constness))
+                let obligations = self.confirm_param_candidate(obligation, param.0.value);
+                Ok(ImplSource::Param(obligations, param.0.constness))
             }
 
             ImplCandidate(impl_def_id) => {
@@ -140,7 +139,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
 
             let trait_predicate = self.infcx.shallow_resolve(obligation.predicate);
             let placeholder_trait_predicate =
-                self.infcx().replace_bound_vars_with_placeholders(trait_predicate).trait_ref;
+                self.infcx().replace_bound_vars_with_placeholders(trait_predicate);
             let placeholder_self_ty = placeholder_trait_predicate.self_ty();
             let placeholder_trait_predicate = ty::Binder::dummy(placeholder_trait_predicate);
             let (def_id, substs) = match *placeholder_self_ty.kind() {
@@ -151,9 +150,8 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
 
             let candidate_predicate = tcx.item_bounds(def_id)[idx].subst(tcx, substs);
             let candidate = candidate_predicate
-                .to_opt_poly_trait_pred()
-                .expect("projection candidate is not a trait predicate")
-                .map_bound(|t| t.trait_ref);
+                .to_opt_poly_trait_ref()
+                .expect("projection candidate is not a trait predicate");
             let mut obligations = Vec::new();
             let candidate = normalize_with_depth_to(
                 self,
@@ -167,7 +165,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
             obligations.extend(self.infcx.commit_if_ok(|_| {
                 self.infcx
                     .at(&obligation.cause, obligation.param_env)
-                    .sup(placeholder_trait_predicate, candidate)
+                    .sup(placeholder_trait_predicate.to_poly_trait_ref(), candidate.value)
                     .map(|InferOk { obligations, .. }| obligations)
                     .map_err(|_| Unimplemented)
             })?);
diff --git a/compiler/rustc_trait_selection/src/traits/select/mod.rs b/compiler/rustc_trait_selection/src/traits/select/mod.rs
index 2b120e855eb..32d04b55754 100644
--- a/compiler/rustc_trait_selection/src/traits/select/mod.rs
+++ b/compiler/rustc_trait_selection/src/traits/select/mod.rs
@@ -39,6 +39,7 @@ use rustc_middle::ty::fast_reject;
 use rustc_middle::ty::print::with_no_trimmed_paths;
 use rustc_middle::ty::relate::TypeRelation;
 use rustc_middle::ty::subst::{GenericArgKind, Subst, SubstsRef};
+use rustc_middle::ty::WithConstness;
 use rustc_middle::ty::{self, PolyProjectionPredicate, ToPolyTraitRef, ToPredicate};
 use rustc_middle::ty::{Ty, TyCtxt, TypeFoldable};
 use rustc_span::symbol::sym;
@@ -127,6 +128,9 @@ pub struct SelectionContext<'cx, 'tcx> {
     /// and a negative impl
     allow_negative_impls: bool,
 
+    /// Are we in a const context that needs `~const` bounds to be const?
+    is_in_const_context: bool,
+
     /// The mode that trait queries run in, which informs our error handling
     /// policy. In essence, canonicalized queries need their errors propagated
     /// rather than immediately reported because we do not have accurate spans.
@@ -137,9 +141,9 @@ pub struct SelectionContext<'cx, 'tcx> {
 struct TraitObligationStack<'prev, 'tcx> {
     obligation: &'prev TraitObligation<'tcx>,
 
-    /// The trait predicate from `obligation` but "freshened" with the
+    /// The trait ref from `obligation` but "freshened" with the
     /// selection-context's freshener. Used to check for recursion.
-    fresh_trait_pred: ty::PolyTraitPredicate<'tcx>,
+    fresh_trait_ref: ty::ConstnessAnd<ty::PolyTraitRef<'tcx>>,
 
     /// Starts out equal to `depth` -- if, during evaluation, we
     /// encounter a cycle, then we will set this flag to the minimum
@@ -218,6 +222,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
             intercrate: false,
             intercrate_ambiguity_causes: None,
             allow_negative_impls: false,
+            is_in_const_context: false,
             query_mode: TraitQueryMode::Standard,
         }
     }
@@ -229,6 +234,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
             intercrate: true,
             intercrate_ambiguity_causes: None,
             allow_negative_impls: false,
+            is_in_const_context: false,
             query_mode: TraitQueryMode::Standard,
         }
     }
@@ -244,6 +250,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
             intercrate: false,
             intercrate_ambiguity_causes: None,
             allow_negative_impls,
+            is_in_const_context: false,
             query_mode: TraitQueryMode::Standard,
         }
     }
@@ -259,10 +266,26 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
             intercrate: false,
             intercrate_ambiguity_causes: None,
             allow_negative_impls: false,
+            is_in_const_context: false,
             query_mode,
         }
     }
 
+    pub fn with_constness(
+        infcx: &'cx InferCtxt<'cx, 'tcx>,
+        constness: hir::Constness,
+    ) -> SelectionContext<'cx, 'tcx> {
+        SelectionContext {
+            infcx,
+            freshener: infcx.freshener_keep_static(),
+            intercrate: false,
+            intercrate_ambiguity_causes: None,
+            allow_negative_impls: false,
+            is_in_const_context: matches!(constness, hir::Constness::Const),
+            query_mode: TraitQueryMode::Standard,
+        }
+    }
+
     /// Enables tracking of intercrate ambiguity causes. These are
     /// used in coherence to give improved diagnostics. We don't do
     /// this until we detect a coherence error because it can lead to
@@ -295,6 +318,20 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
         self.intercrate
     }
 
+    /// Returns `true` if the trait predicate is considerd `const` to this selection context.
+    pub fn is_trait_predicate_const(&self, pred: ty::TraitPredicate<'_>) -> bool {
+        matches!(pred.constness, ty::BoundConstness::ConstIfConst) && self.is_in_const_context
+    }
+
+    /// Returns `true` if the predicate is considered `const` to
+    /// this selection context.
+    pub fn is_predicate_const(&self, pred: ty::Predicate<'_>) -> bool {
+        match pred.kind().skip_binder() {
+            ty::PredicateKind::Trait(pred) => self.is_trait_predicate_const(pred),
+            _ => false,
+        }
+    }
+
     ///////////////////////////////////////////////////////////////////////////
     // Selection
     //
@@ -679,22 +716,20 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
         }
 
         let stack = self.push_stack(previous_stack, &obligation);
-        let mut fresh_trait_pred = stack.fresh_trait_pred;
-        let mut param_env = obligation.param_env;
-
-        fresh_trait_pred = fresh_trait_pred.map_bound(|mut pred| {
-            param_env = param_env.with_constness(pred.constness.and(param_env.constness()));
-            pred
-        });
+        let fresh_trait_ref = stack.fresh_trait_ref;
 
-        debug!(?fresh_trait_pred);
+        debug!(?fresh_trait_ref);
 
-        if let Some(result) = self.check_evaluation_cache(param_env, fresh_trait_pred) {
+        if let Some(result) = self.check_evaluation_cache(
+            obligation.param_env,
+            fresh_trait_ref,
+            obligation.polarity(),
+        ) {
             debug!(?result, "CACHE HIT");
             return Ok(result);
         }
 
-        if let Some(result) = stack.cache().get_provisional(fresh_trait_pred) {
+        if let Some(result) = stack.cache().get_provisional(fresh_trait_ref) {
             debug!(?result, "PROVISIONAL CACHE HIT");
             stack.update_reached_depth(result.reached_depth);
             return Ok(result.result);
@@ -719,12 +754,19 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
         let reached_depth = stack.reached_depth.get();
         if reached_depth >= stack.depth {
             debug!(?result, "CACHE MISS");
-            self.insert_evaluation_cache(param_env, fresh_trait_pred, dep_node, result);
+            self.insert_evaluation_cache(
+                obligation.param_env,
+                fresh_trait_ref,
+                obligation.polarity(),
+                dep_node,
+                result,
+            );
 
-            stack.cache().on_completion(stack.dfn, |fresh_trait_pred, provisional_result| {
+            stack.cache().on_completion(stack.dfn, |fresh_trait_ref, provisional_result| {
                 self.insert_evaluation_cache(
-                    param_env,
-                    fresh_trait_pred,
+                    obligation.param_env,
+                    fresh_trait_ref,
+                    obligation.polarity(),
                     dep_node,
                     provisional_result.max(result),
                 );
@@ -734,10 +776,10 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
             debug!(
                 "caching provisionally because {:?} \
                  is a cycle participant (at depth {}, reached depth {})",
-                fresh_trait_pred, stack.depth, reached_depth,
+                fresh_trait_ref, stack.depth, reached_depth,
             );
 
-            stack.cache().insert_provisional(stack.dfn, reached_depth, fresh_trait_pred, result);
+            stack.cache().insert_provisional(stack.dfn, reached_depth, fresh_trait_ref, result);
         }
 
         Ok(result)
@@ -771,7 +813,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
             .skip(1) // Skip top-most frame.
             .find(|prev| {
                 stack.obligation.param_env == prev.obligation.param_env
-                    && stack.fresh_trait_pred == prev.fresh_trait_pred
+                    && stack.fresh_trait_ref == prev.fresh_trait_ref
             })
             .map(|stack| stack.depth)
         {
@@ -834,7 +876,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
         // terms of `Fn` etc, but we could probably make this more
         // precise still.
         let unbound_input_types =
-            stack.fresh_trait_pred.skip_binder().trait_ref.substs.types().any(|ty| ty.is_fresh());
+            stack.fresh_trait_ref.value.skip_binder().substs.types().any(|ty| ty.is_fresh());
 
         if stack.obligation.polarity() != ty::ImplPolarity::Negative {
             // This check was an imperfect workaround for a bug in the old
@@ -872,8 +914,8 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
             && stack.iter().skip(1).any(|prev| {
                 stack.obligation.param_env == prev.obligation.param_env
                     && self.match_fresh_trait_refs(
-                        stack.fresh_trait_pred,
-                        prev.fresh_trait_pred,
+                        stack.fresh_trait_ref,
+                        prev.fresh_trait_ref,
                         prev.obligation.param_env,
                     )
             })
@@ -951,7 +993,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
         // not just the lifetime choice for this particular (non-erased)
         // predicate.
         // See issue #80691
-        if stack.fresh_trait_pred.has_erased_regions() {
+        if stack.fresh_trait_ref.has_erased_regions() {
             result = result.max(EvaluatedToOkModuloRegions);
         }
 
@@ -962,7 +1004,8 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
     fn check_evaluation_cache(
         &self,
         param_env: ty::ParamEnv<'tcx>,
-        trait_pred: ty::PolyTraitPredicate<'tcx>,
+        trait_ref: ty::ConstnessAnd<ty::PolyTraitRef<'tcx>>,
+        polarity: ty::ImplPolarity,
     ) -> Option<EvaluationResult> {
         // Neither the global nor local cache is aware of intercrate
         // mode, so don't do any caching. In particular, we might
@@ -974,17 +1017,19 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
 
         let tcx = self.tcx();
         if self.can_use_global_caches(param_env) {
-            if let Some(res) = tcx.evaluation_cache.get(&param_env.and(trait_pred), tcx) {
+            if let Some(res) = tcx.evaluation_cache.get(&(param_env.and(trait_ref), polarity), tcx)
+            {
                 return Some(res);
             }
         }
-        self.infcx.evaluation_cache.get(&param_env.and(trait_pred), tcx)
+        self.infcx.evaluation_cache.get(&(param_env.and(trait_ref), polarity), tcx)
     }
 
     fn insert_evaluation_cache(
         &mut self,
         param_env: ty::ParamEnv<'tcx>,
-        trait_pred: ty::PolyTraitPredicate<'tcx>,
+        trait_ref: ty::ConstnessAnd<ty::PolyTraitRef<'tcx>>,
+        polarity: ty::ImplPolarity,
         dep_node: DepNodeIndex,
         result: EvaluationResult,
     ) {
@@ -1003,19 +1048,23 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
         }
 
         if self.can_use_global_caches(param_env) {
-            if !trait_pred.needs_infer() {
-                debug!(?trait_pred, ?result, "insert_evaluation_cache global");
+            if !trait_ref.needs_infer() {
+                debug!(?trait_ref, ?result, "insert_evaluation_cache global");
                 // This may overwrite the cache with the same value
                 // FIXME: Due to #50507 this overwrites the different values
                 // This should be changed to use HashMapExt::insert_same
                 // when that is fixed
-                self.tcx().evaluation_cache.insert(param_env.and(trait_pred), dep_node, result);
+                self.tcx().evaluation_cache.insert(
+                    (param_env.and(trait_ref), polarity),
+                    dep_node,
+                    result,
+                );
                 return;
             }
         }
 
-        debug!(?trait_pred, ?result, "insert_evaluation_cache");
-        self.infcx.evaluation_cache.insert(param_env.and(trait_pred), dep_node, result);
+        debug!(?trait_ref, ?result, "insert_evaluation_cache");
+        self.infcx.evaluation_cache.insert((param_env.and(trait_ref), polarity), dep_node, result);
     }
 
     /// For various reasons, it's possible for a subobligation
@@ -1093,15 +1142,16 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
 
         for candidate in candidates {
             // Respect const trait obligations
-            if obligation.is_const() {
+            if self.is_trait_predicate_const(obligation.predicate.skip_binder()) {
                 match candidate {
                     // const impl
                     ImplCandidate(def_id)
                         if tcx.impl_constness(def_id) == hir::Constness::Const => {}
                     // const param
-                    ParamCandidate(trait_pred)
-                        if trait_pred.skip_binder().constness
-                            == ty::BoundConstness::ConstIfConst => {}
+                    ParamCandidate((
+                        ty::ConstnessAnd { constness: ty::BoundConstness::ConstIfConst, .. },
+                        _,
+                    )) => {}
                     // auto trait impl
                     AutoImplCandidate(..) => {}
                     // generator, this will raise error in other places
@@ -1210,7 +1260,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
 
     fn check_candidate_cache(
         &mut self,
-        mut param_env: ty::ParamEnv<'tcx>,
+        param_env: ty::ParamEnv<'tcx>,
         cache_fresh_trait_pred: ty::PolyTraitPredicate<'tcx>,
     ) -> Option<SelectionResult<'tcx, SelectionCandidate<'tcx>>> {
         // Neither the global nor local cache is aware of intercrate
@@ -1221,15 +1271,19 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
             return None;
         }
         let tcx = self.tcx();
-        let mut pred = cache_fresh_trait_pred.skip_binder();
-        param_env = param_env.with_constness(pred.constness.and(param_env.constness()));
-
+        let pred = &cache_fresh_trait_pred.skip_binder();
+        let trait_ref = pred.trait_ref;
         if self.can_use_global_caches(param_env) {
-            if let Some(res) = tcx.selection_cache.get(&param_env.and(pred), tcx) {
+            if let Some(res) = tcx
+                .selection_cache
+                .get(&(param_env.and(trait_ref).with_constness(pred.constness), pred.polarity), tcx)
+            {
                 return Some(res);
             }
         }
-        self.infcx.selection_cache.get(&param_env.and(pred), tcx)
+        self.infcx
+            .selection_cache
+            .get(&(param_env.and(trait_ref).with_constness(pred.constness), pred.polarity), tcx)
     }
 
     /// Determines whether can we safely cache the result
@@ -1267,36 +1321,43 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
 
     fn insert_candidate_cache(
         &mut self,
-        mut param_env: ty::ParamEnv<'tcx>,
+        param_env: ty::ParamEnv<'tcx>,
         cache_fresh_trait_pred: ty::PolyTraitPredicate<'tcx>,
         dep_node: DepNodeIndex,
         candidate: SelectionResult<'tcx, SelectionCandidate<'tcx>>,
     ) {
         let tcx = self.tcx();
-        let mut pred = cache_fresh_trait_pred.skip_binder();
-
-        param_env = param_env.with_constness(pred.constness.and(param_env.constness()));
+        let pred = cache_fresh_trait_pred.skip_binder();
+        let trait_ref = pred.trait_ref;
 
         if !self.can_cache_candidate(&candidate) {
-            debug!(?pred, ?candidate, "insert_candidate_cache - candidate is not cacheable");
+            debug!(?trait_ref, ?candidate, "insert_candidate_cache - candidate is not cacheable");
             return;
         }
 
         if self.can_use_global_caches(param_env) {
             if let Err(Overflow) = candidate {
                 // Don't cache overflow globally; we only produce this in certain modes.
-            } else if !pred.needs_infer() {
+            } else if !trait_ref.needs_infer() {
                 if !candidate.needs_infer() {
-                    debug!(?pred, ?candidate, "insert_candidate_cache global");
+                    debug!(?trait_ref, ?candidate, "insert_candidate_cache global");
                     // This may overwrite the cache with the same value.
-                    tcx.selection_cache.insert(param_env.and(pred), dep_node, candidate);
+                    tcx.selection_cache.insert(
+                        (param_env.and(trait_ref).with_constness(pred.constness), pred.polarity),
+                        dep_node,
+                        candidate,
+                    );
                     return;
                 }
             }
         }
 
-        debug!(?pred, ?candidate, "insert_candidate_cache local");
-        self.infcx.selection_cache.insert(param_env.and(pred), dep_node, candidate);
+        debug!(?trait_ref, ?candidate, "insert_candidate_cache local");
+        self.infcx.selection_cache.insert(
+            (param_env.and(trait_ref).with_constness(pred.constness), pred.polarity),
+            dep_node,
+            candidate,
+        );
     }
 
     /// Matches a predicate against the bounds of its self type.
@@ -1487,7 +1548,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
         // Check if a bound would previously have been removed when normalizing
         // the param_env so that it can be given the lowest priority. See
         // #50825 for the motivation for this.
-        let is_global = |cand: &ty::PolyTraitPredicate<'tcx>| {
+        let is_global = |cand: &ty::PolyTraitRef<'tcx>| {
             cand.is_global(self.infcx.tcx) && !cand.has_late_bound_regions()
         };
 
@@ -1520,22 +1581,25 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
                 | ConstDropCandidate,
             ) => false,
 
-            (ParamCandidate(other), ParamCandidate(victim)) => {
-                let same_except_bound_vars = other.skip_binder().trait_ref
-                    == victim.skip_binder().trait_ref
-                    && other.skip_binder().constness == victim.skip_binder().constness
-                    && other.skip_binder().polarity == victim.skip_binder().polarity
-                    && !other.skip_binder().trait_ref.has_escaping_bound_vars();
+            (
+                ParamCandidate((other, other_polarity)),
+                ParamCandidate((victim, victim_polarity)),
+            ) => {
+                let same_except_bound_vars = other.value.skip_binder()
+                    == victim.value.skip_binder()
+                    && other.constness == victim.constness
+                    && other_polarity == victim_polarity
+                    && !other.value.skip_binder().has_escaping_bound_vars();
                 if same_except_bound_vars {
                     // See issue #84398. In short, we can generate multiple ParamCandidates which are
                     // the same except for unused bound vars. Just pick the one with the fewest bound vars
                     // or the current one if tied (they should both evaluate to the same answer). This is
                     // probably best characterized as a "hack", since we might prefer to just do our
                     // best to *not* create essentially duplicate candidates in the first place.
-                    other.bound_vars().len() <= victim.bound_vars().len()
-                } else if other.skip_binder().trait_ref == victim.skip_binder().trait_ref
-                    && victim.skip_binder().constness == ty::BoundConstness::NotConst
-                    && other.skip_binder().polarity == victim.skip_binder().polarity
+                    other.value.bound_vars().len() <= victim.value.bound_vars().len()
+                } else if other.value == victim.value
+                    && victim.constness == ty::BoundConstness::NotConst
+                    && other_polarity == victim_polarity
                 {
                     // Drop otherwise equivalent non-const candidates in favor of const candidates.
                     true
@@ -1565,11 +1629,11 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
                 | TraitAliasCandidate(..)
                 | ObjectCandidate(_)
                 | ProjectionCandidate(_),
-            ) => !is_global(cand),
+            ) => !is_global(&cand.0.value),
             (ObjectCandidate(_) | ProjectionCandidate(_), ParamCandidate(ref cand)) => {
                 // Prefer these to a global where-clause bound
                 // (see issue #50825).
-                is_global(cand)
+                is_global(&cand.0.value)
             }
             (
                 ImplCandidate(_)
@@ -1585,7 +1649,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
             ) => {
                 // Prefer these to a global where-clause bound
                 // (see issue #50825).
-                is_global(cand) && other.evaluation.must_apply_modulo_regions()
+                is_global(&cand.0.value) && other.evaluation.must_apply_modulo_regions()
             }
 
             (ProjectionCandidate(i), ProjectionCandidate(j))
@@ -2145,8 +2209,8 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
 
     fn match_fresh_trait_refs(
         &self,
-        previous: ty::PolyTraitPredicate<'tcx>,
-        current: ty::PolyTraitPredicate<'tcx>,
+        previous: ty::ConstnessAnd<ty::PolyTraitRef<'tcx>>,
+        current: ty::ConstnessAnd<ty::PolyTraitRef<'tcx>>,
         param_env: ty::ParamEnv<'tcx>,
     ) -> bool {
         let mut matcher = ty::_match::Match::new(self.tcx(), param_env);
@@ -2158,13 +2222,17 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
         previous_stack: TraitObligationStackList<'o, 'tcx>,
         obligation: &'o TraitObligation<'tcx>,
     ) -> TraitObligationStack<'o, 'tcx> {
-        let fresh_trait_pred = obligation.predicate.fold_with(&mut self.freshener);
+        let fresh_trait_ref = obligation
+            .predicate
+            .to_poly_trait_ref()
+            .fold_with(&mut self.freshener)
+            .with_constness(obligation.predicate.skip_binder().constness);
 
         let dfn = previous_stack.cache.next_dfn();
         let depth = previous_stack.depth() + 1;
         TraitObligationStack {
             obligation,
-            fresh_trait_pred,
+            fresh_trait_ref,
             reached_depth: Cell::new(depth),
             previous: previous_stack,
             dfn,
@@ -2358,7 +2426,7 @@ impl<'o, 'tcx> TraitObligationStack<'o, 'tcx> {
         debug!(reached_depth, "update_reached_depth");
         let mut p = self;
         while reached_depth < p.depth {
-            debug!(?p.fresh_trait_pred, "update_reached_depth: marking as cycle participant");
+            debug!(?p.fresh_trait_ref, "update_reached_depth: marking as cycle participant");
             p.reached_depth.set(p.reached_depth.get().min(reached_depth));
             p = p.previous.head.unwrap();
         }
@@ -2437,7 +2505,7 @@ struct ProvisionalEvaluationCache<'tcx> {
     /// - then we determine that `E` is in error -- we will then clear
     ///   all cache values whose DFN is >= 4 -- in this case, that
     ///   means the cached value for `F`.
-    map: RefCell<FxHashMap<ty::PolyTraitPredicate<'tcx>, ProvisionalEvaluation>>,
+    map: RefCell<FxHashMap<ty::ConstnessAnd<ty::PolyTraitRef<'tcx>>, ProvisionalEvaluation>>,
 }
 
 /// A cache value for the provisional cache: contains the depth-first
@@ -2469,28 +2537,28 @@ impl<'tcx> ProvisionalEvaluationCache<'tcx> {
     /// `reached_depth` (from the returned value).
     fn get_provisional(
         &self,
-        fresh_trait_pred: ty::PolyTraitPredicate<'tcx>,
+        fresh_trait_ref: ty::ConstnessAnd<ty::PolyTraitRef<'tcx>>,
     ) -> Option<ProvisionalEvaluation> {
         debug!(
-            ?fresh_trait_pred,
+            ?fresh_trait_ref,
             "get_provisional = {:#?}",
-            self.map.borrow().get(&fresh_trait_pred),
+            self.map.borrow().get(&fresh_trait_ref),
         );
-        Some(*self.map.borrow().get(&fresh_trait_pred)?)
+        Some(*self.map.borrow().get(&fresh_trait_ref)?)
     }
 
     /// Insert a provisional result into the cache. The result came
     /// from the node with the given DFN. It accessed a minimum depth
-    /// of `reached_depth` to compute. It evaluated `fresh_trait_pred`
+    /// of `reached_depth` to compute. It evaluated `fresh_trait_ref`
     /// and resulted in `result`.
     fn insert_provisional(
         &self,
         from_dfn: usize,
         reached_depth: usize,
-        fresh_trait_pred: ty::PolyTraitPredicate<'tcx>,
+        fresh_trait_ref: ty::ConstnessAnd<ty::PolyTraitRef<'tcx>>,
         result: EvaluationResult,
     ) {
-        debug!(?from_dfn, ?fresh_trait_pred, ?result, "insert_provisional");
+        debug!(?from_dfn, ?fresh_trait_ref, ?result, "insert_provisional");
 
         let mut map = self.map.borrow_mut();
 
@@ -2514,7 +2582,7 @@ impl<'tcx> ProvisionalEvaluationCache<'tcx> {
             }
         }
 
-        map.insert(fresh_trait_pred, ProvisionalEvaluation { from_dfn, reached_depth, result });
+        map.insert(fresh_trait_ref, ProvisionalEvaluation { from_dfn, reached_depth, result });
     }
 
     /// Invoked when the node with dfn `dfn` does not get a successful
@@ -2565,16 +2633,16 @@ impl<'tcx> ProvisionalEvaluationCache<'tcx> {
     fn on_completion(
         &self,
         dfn: usize,
-        mut op: impl FnMut(ty::PolyTraitPredicate<'tcx>, EvaluationResult),
+        mut op: impl FnMut(ty::ConstnessAnd<ty::PolyTraitRef<'tcx>>, EvaluationResult),
     ) {
         debug!(?dfn, "on_completion");
 
-        for (fresh_trait_pred, eval) in
+        for (fresh_trait_ref, eval) in
             self.map.borrow_mut().drain_filter(|_k, eval| eval.from_dfn >= dfn)
         {
-            debug!(?fresh_trait_pred, ?eval, "on_completion");
+            debug!(?fresh_trait_ref, ?eval, "on_completion");
 
-            op(fresh_trait_pred, eval.result);
+            op(fresh_trait_ref, eval.result);
         }
     }
 }
diff --git a/compiler/rustc_trait_selection/src/traits/specialize/mod.rs b/compiler/rustc_trait_selection/src/traits/specialize/mod.rs
index ab732f510ff..b64c5559227 100644
--- a/compiler/rustc_trait_selection/src/traits/specialize/mod.rs
+++ b/compiler/rustc_trait_selection/src/traits/specialize/mod.rs
@@ -508,9 +508,9 @@ crate fn to_pretty_impl_header(tcx: TyCtxt<'_>, impl_def_id: DefId) -> Option<St
         Vec::with_capacity(predicates.len() + types_without_default_bounds.len());
 
     for (p, _) in predicates {
-        if let Some(poly_trait_ref) = p.to_opt_poly_trait_pred() {
-            if Some(poly_trait_ref.def_id()) == sized_trait {
-                types_without_default_bounds.remove(poly_trait_ref.self_ty().skip_binder());
+        if let Some(poly_trait_ref) = p.to_opt_poly_trait_ref() {
+            if Some(poly_trait_ref.value.def_id()) == sized_trait {
+                types_without_default_bounds.remove(poly_trait_ref.value.self_ty().skip_binder());
                 continue;
             }
         }
diff --git a/compiler/rustc_trait_selection/src/traits/util.rs b/compiler/rustc_trait_selection/src/traits/util.rs
index 5577e98e893..6d2323abba4 100644
--- a/compiler/rustc_trait_selection/src/traits/util.rs
+++ b/compiler/rustc_trait_selection/src/traits/util.rs
@@ -6,7 +6,7 @@ use smallvec::SmallVec;
 use rustc_data_structures::fx::FxHashSet;
 use rustc_hir::def_id::DefId;
 use rustc_middle::ty::subst::{GenericArg, Subst, SubstsRef};
-use rustc_middle::ty::{self, ToPredicate, Ty, TyCtxt, TypeFoldable};
+use rustc_middle::ty::{self, ToPredicate, Ty, TyCtxt, TypeFoldable, WithConstness};
 
 use super::{Normalized, Obligation, ObligationCause, PredicateObligation, SelectionContext};
 pub use rustc_infer::traits::{self, util::*};
@@ -126,8 +126,8 @@ impl<'tcx> TraitAliasExpander<'tcx> {
 
         let items = predicates.predicates.iter().rev().filter_map(|(pred, span)| {
             pred.subst_supertrait(tcx, &trait_ref)
-                .to_opt_poly_trait_pred()
-                .map(|trait_ref| item.clone_and_push(trait_ref.map_bound(|t| t.trait_ref), *span))
+                .to_opt_poly_trait_ref()
+                .map(|trait_ref| item.clone_and_push(trait_ref.value, *span))
         });
         debug!("expand_trait_aliases: items={:?}", items.clone());
 
@@ -183,8 +183,8 @@ impl Iterator for SupertraitDefIds<'tcx> {
             predicates
                 .predicates
                 .iter()
-                .filter_map(|(pred, _)| pred.to_opt_poly_trait_pred())
-                .map(|trait_ref| trait_ref.def_id())
+                .filter_map(|(pred, _)| pred.to_opt_poly_trait_ref())
+                .map(|trait_ref| trait_ref.value.def_id())
                 .filter(|&super_def_id| visited.insert(super_def_id)),
         );
         Some(def_id)
diff --git a/compiler/rustc_trait_selection/src/traits/wf.rs b/compiler/rustc_trait_selection/src/traits/wf.rs
index 5875b764e9f..2a66684e2a2 100644
--- a/compiler/rustc_trait_selection/src/traits/wf.rs
+++ b/compiler/rustc_trait_selection/src/traits/wf.rs
@@ -6,7 +6,7 @@ use rustc_hir as hir;
 use rustc_hir::def_id::DefId;
 use rustc_hir::lang_items::LangItem;
 use rustc_middle::ty::subst::{GenericArg, GenericArgKind, SubstsRef};
-use rustc_middle::ty::{self, ToPredicate, Ty, TyCtxt, TypeFoldable};
+use rustc_middle::ty::{self, ToPredicate, Ty, TyCtxt, TypeFoldable, WithConstness};
 use rustc_span::Span;
 
 use std::iter;
@@ -298,10 +298,9 @@ impl<'a, 'tcx> WfPredicates<'a, 'tcx> {
 
         let extend = |obligation: traits::PredicateObligation<'tcx>| {
             let mut cause = cause.clone();
-            if let Some(parent_trait_ref) = obligation.predicate.to_opt_poly_trait_pred() {
+            if let Some(parent_trait_ref) = obligation.predicate.to_opt_poly_trait_ref() {
                 let derived_cause = traits::DerivedObligationCause {
-                    // FIXME(fee1-dead): when improving error messages, change this to PolyTraitPredicate
-                    parent_trait_ref: parent_trait_ref.map_bound(|t| t.trait_ref),
+                    parent_trait_ref: parent_trait_ref.value,
                     parent_code: Lrc::new(obligation.cause.code.clone()),
                 };
                 cause.make_mut().code =
diff --git a/compiler/rustc_ty_utils/src/needs_drop.rs b/compiler/rustc_ty_utils/src/needs_drop.rs
index 595b623b020..fc309aa848c 100644
--- a/compiler/rustc_ty_utils/src/needs_drop.rs
+++ b/compiler/rustc_ty_utils/src/needs_drop.rs
@@ -147,8 +147,10 @@ where
                             Ok(tys) => tys,
                         };
                         for required_ty in tys {
-                            let required =
-                                tcx.normalize_erasing_regions(self.param_env, required_ty);
+                            let required = tcx
+                                .try_normalize_erasing_regions(self.param_env, required_ty)
+                                .unwrap_or(required_ty);
+
                             queue_type(self, required);
                         }
                     }
diff --git a/compiler/rustc_ty_utils/src/ty.rs b/compiler/rustc_ty_utils/src/ty.rs
index f990709bd8d..711a6f2fbeb 100644
--- a/compiler/rustc_ty_utils/src/ty.rs
+++ b/compiler/rustc_ty_utils/src/ty.rs
@@ -2,7 +2,9 @@ use rustc_data_structures::fx::FxIndexSet;
 use rustc_hir as hir;
 use rustc_hir::def_id::{DefId, LocalDefId};
 use rustc_middle::ty::subst::Subst;
-use rustc_middle::ty::{self, Binder, Predicate, PredicateKind, ToPredicate, Ty, TyCtxt};
+use rustc_middle::ty::{
+    self, Binder, Predicate, PredicateKind, ToPredicate, Ty, TyCtxt, WithConstness,
+};
 use rustc_span::Span;
 use rustc_trait_selection::traits;
 
@@ -280,79 +282,16 @@ fn param_env(tcx: TyCtxt<'_>, def_id: DefId) -> ty::ParamEnv<'_> {
     // issue #89334
     predicates = tcx.expose_default_const_substs(predicates);
 
-    let local_did = def_id.as_local();
-    let hir_id = local_did.map(|def_id| tcx.hir().local_def_id_to_hir_id(def_id));
+    let unnormalized_env =
+        ty::ParamEnv::new(tcx.intern_predicates(&predicates), traits::Reveal::UserFacing);
 
-    let constness = match hir_id {
-        Some(hir_id) => match tcx.hir().get(hir_id) {
-            hir::Node::Item(hir::Item { kind: hir::ItemKind::Const(..), .. })
-            | hir::Node::Item(hir::Item { kind: hir::ItemKind::Static(..), .. })
-            | hir::Node::TraitItem(hir::TraitItem {
-                kind: hir::TraitItemKind::Const(..), ..
-            })
-            | hir::Node::AnonConst(_)
-            | hir::Node::ImplItem(hir::ImplItem { kind: hir::ImplItemKind::Const(..), .. })
-            | hir::Node::ImplItem(hir::ImplItem {
-                kind:
-                    hir::ImplItemKind::Fn(
-                        hir::FnSig {
-                            header: hir::FnHeader { constness: hir::Constness::Const, .. },
-                            ..
-                        },
-                        ..,
-                    ),
-                ..
-            }) => hir::Constness::Const,
-
-            hir::Node::ImplItem(hir::ImplItem {
-                kind: hir::ImplItemKind::TyAlias(..) | hir::ImplItemKind::Fn(..),
-                ..
-            }) => {
-                let parent_hir_id = tcx.hir().get_parent_node(hir_id);
-                match tcx.hir().get(parent_hir_id) {
-                    hir::Node::Item(hir::Item {
-                        kind: hir::ItemKind::Impl(hir::Impl { constness, .. }),
-                        ..
-                    }) => *constness,
-                    _ => span_bug!(
-                        tcx.def_span(parent_hir_id.owner),
-                        "impl item's parent node is not an impl",
-                    ),
-                }
-            }
-
-            hir::Node::Item(hir::Item {
-                kind:
-                    hir::ItemKind::Fn(hir::FnSig { header: hir::FnHeader { constness, .. }, .. }, ..),
-                ..
-            })
-            | hir::Node::TraitItem(hir::TraitItem {
-                kind:
-                    hir::TraitItemKind::Fn(
-                        hir::FnSig { header: hir::FnHeader { constness, .. }, .. },
-                        ..,
-                    ),
-                ..
-            })
-            | hir::Node::Item(hir::Item {
-                kind: hir::ItemKind::Impl(hir::Impl { constness, .. }),
-                ..
-            }) => *constness,
-
-            _ => hir::Constness::NotConst,
-        },
-        None => hir::Constness::NotConst,
-    };
-
-    let unnormalized_env = ty::ParamEnv::new(
-        tcx.intern_predicates(&predicates),
-        traits::Reveal::UserFacing,
-        constness,
-    );
-
-    let body_id = hir_id.map_or(hir::CRATE_HIR_ID, |id| {
-        tcx.hir().maybe_body_owned_by(id).map_or(id, |body| body.hir_id)
-    });
+    debug!("unnormalized_env caller bounds: {:?}", unnormalized_env.caller_bounds());
+    let body_id = def_id
+        .as_local()
+        .map(|def_id| tcx.hir().local_def_id_to_hir_id(def_id))
+        .map_or(hir::CRATE_HIR_ID, |id| {
+            tcx.hir().maybe_body_owned_by(id).map_or(id, |body| body.hir_id)
+        });
     let cause = traits::ObligationCause::misc(tcx.def_span(def_id), body_id);
     traits::normalize_param_env_or_error(tcx, def_id, unnormalized_env, cause)
 }
diff --git a/compiler/rustc_typeck/src/astconv/mod.rs b/compiler/rustc_typeck/src/astconv/mod.rs
index b532a6b118f..da751f20753 100644
--- a/compiler/rustc_typeck/src/astconv/mod.rs
+++ b/compiler/rustc_typeck/src/astconv/mod.rs
@@ -1588,7 +1588,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
                 traits::transitive_bounds_that_define_assoc_type(
                     tcx,
                     predicates.iter().filter_map(|(p, _)| {
-                        Some(p.to_opt_poly_trait_pred()?.map_bound(|t| t.trait_ref))
+                        p.to_opt_poly_trait_ref().map(|trait_ref| trait_ref.value)
                     }),
                     assoc_name,
                 )
diff --git a/compiler/rustc_typeck/src/bounds.rs b/compiler/rustc_typeck/src/bounds.rs
index 8bc3a48e5b5..24474e163b9 100644
--- a/compiler/rustc_typeck/src/bounds.rs
+++ b/compiler/rustc_typeck/src/bounds.rs
@@ -1,7 +1,7 @@
 //! Bounds are restrictions applied to some types after they've been converted into the
 //! `ty` form from the HIR.
 
-use rustc_middle::ty::{self, ToPredicate, Ty, TyCtxt};
+use rustc_middle::ty::{self, ToPredicate, Ty, TyCtxt, WithConstness};
 use rustc_span::Span;
 
 /// Collects together a list of type bounds. These lists of bounds occur in many places
diff --git a/compiler/rustc_typeck/src/check/compare_method.rs b/compiler/rustc_typeck/src/check/compare_method.rs
index 2001a4575d6..44fc81a889d 100644
--- a/compiler/rustc_typeck/src/check/compare_method.rs
+++ b/compiler/rustc_typeck/src/check/compare_method.rs
@@ -208,11 +208,8 @@ fn compare_predicate_entailment<'tcx>(
     // The key step here is to update the caller_bounds's predicates to be
     // the new hybrid bounds we computed.
     let normalize_cause = traits::ObligationCause::misc(impl_m_span, impl_m_hir_id);
-    let param_env = ty::ParamEnv::new(
-        tcx.intern_predicates(&hybrid_preds.predicates),
-        Reveal::UserFacing,
-        hir::Constness::NotConst,
-    );
+    let param_env =
+        ty::ParamEnv::new(tcx.intern_predicates(&hybrid_preds.predicates), Reveal::UserFacing);
     let param_env =
         traits::normalize_param_env_or_error(tcx, impl_m.def_id, param_env, normalize_cause);
 
@@ -1168,11 +1165,8 @@ fn compare_type_predicate_entailment<'tcx>(
     debug!("compare_type_predicate_entailment: bounds={:?}", hybrid_preds);
 
     let normalize_cause = traits::ObligationCause::misc(impl_ty_span, impl_ty_hir_id);
-    let param_env = ty::ParamEnv::new(
-        tcx.intern_predicates(&hybrid_preds.predicates),
-        Reveal::UserFacing,
-        hir::Constness::NotConst,
-    );
+    let param_env =
+        ty::ParamEnv::new(tcx.intern_predicates(&hybrid_preds.predicates), Reveal::UserFacing);
     let param_env = traits::normalize_param_env_or_error(
         tcx,
         impl_ty.def_id,
@@ -1357,11 +1351,7 @@ pub fn check_type_bounds<'tcx>(
                 .to_predicate(tcx),
             ),
         };
-        ty::ParamEnv::new(
-            tcx.intern_predicates(&predicates),
-            Reveal::UserFacing,
-            param_env.constness(),
-        )
+        ty::ParamEnv::new(tcx.intern_predicates(&predicates), Reveal::UserFacing)
     };
     debug!(?normalize_param_env);
 
@@ -1370,7 +1360,13 @@ pub fn check_type_bounds<'tcx>(
         impl_ty_substs.rebase_onto(tcx, impl_ty.container.id(), impl_trait_ref.substs);
 
     tcx.infer_ctxt().enter(move |infcx| {
-        let inh = Inherited::new(infcx, impl_ty.def_id.expect_local());
+        let constness = impl_ty
+            .container
+            .impl_def_id()
+            .map(|did| tcx.impl_constness(did))
+            .unwrap_or(hir::Constness::NotConst);
+
+        let inh = Inherited::with_constness(infcx, impl_ty.def_id.expect_local(), constness);
         let infcx = &inh.infcx;
         let mut selcx = traits::SelectionContext::new(&infcx);
 
@@ -1414,7 +1410,8 @@ pub fn check_type_bounds<'tcx>(
 
         // Check that all obligations are satisfied by the implementation's
         // version.
-        let errors = inh.fulfillment_cx.borrow_mut().select_all_or_error(&infcx);
+        let errors =
+            inh.fulfillment_cx.borrow_mut().select_all_with_constness_or_error(&infcx, constness);
         if !errors.is_empty() {
             infcx.report_fulfillment_errors(&errors, None, false);
             return Err(ErrorReported);
diff --git a/compiler/rustc_typeck/src/check/demand.rs b/compiler/rustc_typeck/src/check/demand.rs
index 12cd7ad1848..b210c78cae0 100644
--- a/compiler/rustc_typeck/src/check/demand.rs
+++ b/compiler/rustc_typeck/src/check/demand.rs
@@ -1223,7 +1223,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                     // Missing try_into implementation for `{integer}` to `{float}`
                     err.multipart_suggestion_verbose(
                         &format!(
-                            "{}, producing the floating point representation of the integer,
+                            "{}, producing the floating point representation of the integer, \
                                  rounded if necessary",
                             cast_msg,
                         ),
diff --git a/compiler/rustc_typeck/src/check/fn_ctxt/_impl.rs b/compiler/rustc_typeck/src/check/fn_ctxt/_impl.rs
index bc059df9524..a02a7d7cbfe 100644
--- a/compiler/rustc_typeck/src/check/fn_ctxt/_impl.rs
+++ b/compiler/rustc_typeck/src/check/fn_ctxt/_impl.rs
@@ -616,7 +616,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
 
     #[instrument(skip(self), level = "debug")]
     pub(in super::super) fn select_all_obligations_or_error(&self) {
-        let errors = self.fulfillment_cx.borrow_mut().select_all_or_error(&self);
+        let errors = self
+            .fulfillment_cx
+            .borrow_mut()
+            .select_all_with_constness_or_error(&self, self.inh.constness);
 
         if !errors.is_empty() {
             self.report_fulfillment_errors(&errors, self.inh.body_id, false);
@@ -629,7 +632,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         fallback_has_occurred: bool,
         mutate_fulfillment_errors: impl Fn(&mut Vec<traits::FulfillmentError<'tcx>>),
     ) {
-        let mut result = self.fulfillment_cx.borrow_mut().select_where_possible(self);
+        let mut result = self
+            .fulfillment_cx
+            .borrow_mut()
+            .select_with_constness_where_possible(self, self.inh.constness);
         if !result.is_empty() {
             mutate_fulfillment_errors(&mut result);
             self.report_fulfillment_errors(&result, self.inh.body_id, fallback_has_occurred);
diff --git a/compiler/rustc_typeck/src/check/inherited.rs b/compiler/rustc_typeck/src/check/inherited.rs
index bf52e775043..f7552c1f4eb 100644
--- a/compiler/rustc_typeck/src/check/inherited.rs
+++ b/compiler/rustc_typeck/src/check/inherited.rs
@@ -53,6 +53,9 @@ pub struct Inherited<'a, 'tcx> {
     pub(super) deferred_generator_interiors:
         RefCell<Vec<(hir::BodyId, Ty<'tcx>, hir::GeneratorKind)>>,
 
+    /// Reports whether this is in a const context.
+    pub(super) constness: hir::Constness,
+
     pub(super) body_id: Option<hir::BodyId>,
 
     /// Whenever we introduce an adjustment from `!` into a type variable,
@@ -101,6 +104,16 @@ impl Inherited<'a, 'tcx> {
     pub(super) fn new(infcx: InferCtxt<'a, 'tcx>, def_id: LocalDefId) -> Self {
         let tcx = infcx.tcx;
         let item_id = tcx.hir().local_def_id_to_hir_id(def_id);
+        Self::with_constness(infcx, def_id, tcx.hir().get(item_id).constness_for_typeck())
+    }
+
+    pub(super) fn with_constness(
+        infcx: InferCtxt<'a, 'tcx>,
+        def_id: LocalDefId,
+        constness: hir::Constness,
+    ) -> Self {
+        let tcx = infcx.tcx;
+        let item_id = tcx.hir().local_def_id_to_hir_id(def_id);
         let body_id = tcx.hir().maybe_body_owned_by(item_id);
 
         Inherited {
@@ -115,6 +128,7 @@ impl Inherited<'a, 'tcx> {
             deferred_cast_checks: RefCell::new(Vec::new()),
             deferred_generator_interiors: RefCell::new(Vec::new()),
             diverging_type_vars: RefCell::new(Default::default()),
+            constness,
             body_id,
         }
     }
diff --git a/compiler/rustc_typeck/src/check/method/mod.rs b/compiler/rustc_typeck/src/check/method/mod.rs
index 03518dc8d12..dbc1d4ec193 100644
--- a/compiler/rustc_typeck/src/check/method/mod.rs
+++ b/compiler/rustc_typeck/src/check/method/mod.rs
@@ -22,7 +22,7 @@ use rustc_infer::infer::{self, InferOk};
 use rustc_middle::ty::subst::Subst;
 use rustc_middle::ty::subst::{InternalSubsts, SubstsRef};
 use rustc_middle::ty::GenericParamDefKind;
-use rustc_middle::ty::{self, ToPredicate, Ty, TypeFoldable};
+use rustc_middle::ty::{self, ToPredicate, Ty, TypeFoldable, WithConstness};
 use rustc_span::symbol::Ident;
 use rustc_span::Span;
 use rustc_trait_selection::traits;
diff --git a/compiler/rustc_typeck/src/check/method/probe.rs b/compiler/rustc_typeck/src/check/method/probe.rs
index 9f9f0df97a8..9fd7e8c4daa 100644
--- a/compiler/rustc_typeck/src/check/method/probe.rs
+++ b/compiler/rustc_typeck/src/check/method/probe.rs
@@ -21,7 +21,7 @@ use rustc_infer::infer::{self, InferOk, TyCtxtInferExt};
 use rustc_middle::middle::stability;
 use rustc_middle::ty::subst::{InternalSubsts, Subst, SubstsRef};
 use rustc_middle::ty::GenericParamDefKind;
-use rustc_middle::ty::{self, ParamEnvAnd, ToPredicate, Ty, TyCtxt, TypeFoldable};
+use rustc_middle::ty::{self, ParamEnvAnd, ToPredicate, Ty, TyCtxt, TypeFoldable, WithConstness};
 use rustc_session::lint;
 use rustc_span::def_id::LocalDefId;
 use rustc_span::lev_distance::{find_best_match_for_name, lev_distance};
diff --git a/compiler/rustc_typeck/src/check/method/suggest.rs b/compiler/rustc_typeck/src/check/method/suggest.rs
index 6a3ce2132f8..ca174ed5e84 100644
--- a/compiler/rustc_typeck/src/check/method/suggest.rs
+++ b/compiler/rustc_typeck/src/check/method/suggest.rs
@@ -12,7 +12,7 @@ use rustc_hir::{ExprKind, Node, QPath};
 use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
 use rustc_middle::ty::fast_reject::simplify_type;
 use rustc_middle::ty::print::with_crate_prefix;
-use rustc_middle::ty::{self, ToPredicate, Ty, TyCtxt, TypeFoldable};
+use rustc_middle::ty::{self, ToPredicate, Ty, TyCtxt, TypeFoldable, WithConstness};
 use rustc_span::lev_distance;
 use rustc_span::symbol::{kw, sym, Ident};
 use rustc_span::{source_map, FileName, MultiSpan, Span, Symbol};
diff --git a/compiler/rustc_typeck/src/check/wfcheck.rs b/compiler/rustc_typeck/src/check/wfcheck.rs
index a73dc339d76..33a0c3275ca 100644
--- a/compiler/rustc_typeck/src/check/wfcheck.rs
+++ b/compiler/rustc_typeck/src/check/wfcheck.rs
@@ -21,6 +21,7 @@ use rustc_middle::ty::subst::{GenericArgKind, InternalSubsts, Subst};
 use rustc_middle::ty::trait_def::TraitSpecializationKind;
 use rustc_middle::ty::{
     self, AdtKind, GenericParamDefKind, ToPredicate, Ty, TyCtxt, TypeFoldable, TypeVisitor,
+    WithConstness,
 };
 use rustc_session::parse::feature_err;
 use rustc_span::symbol::{sym, Ident, Symbol};
diff --git a/compiler/rustc_typeck/src/collect.rs b/compiler/rustc_typeck/src/collect.rs
index bc41c230b11..eaa69b7eb60 100644
--- a/compiler/rustc_typeck/src/collect.rs
+++ b/compiler/rustc_typeck/src/collect.rs
@@ -41,7 +41,7 @@ use rustc_middle::ty::subst::InternalSubsts;
 use rustc_middle::ty::util::Discr;
 use rustc_middle::ty::util::IntTypeExt;
 use rustc_middle::ty::{self, AdtKind, Const, DefIdTree, Ty, TyCtxt};
-use rustc_middle::ty::{ReprOptions, ToPredicate};
+use rustc_middle::ty::{ReprOptions, ToPredicate, WithConstness};
 use rustc_session::lint;
 use rustc_session::parse::feature_err;
 use rustc_span::symbol::{kw, sym, Ident, Symbol};
@@ -177,11 +177,9 @@ crate fn placeholder_type_error(
         sugg.push((arg.span, (*type_name).to_string()));
     } else {
         let last = generics.iter().last().unwrap();
-        sugg.push((
-            // Account for bounds, we want `fn foo<T: E, K>(_: K)` not `fn foo<T, K: E>(_: K)`.
-            last.bounds_span().unwrap_or(last.span).shrink_to_hi(),
-            format!(", {}", type_name),
-        ));
+        // Account for bounds, we want `fn foo<T: E, K>(_: K)` not `fn foo<T, K: E>(_: K)`.
+        let span = last.bounds_span_for_suggestions().unwrap_or(last.span.shrink_to_hi());
+        sugg.push((span, format!(", {}", type_name)));
     }
 
     let mut err = bad_placeholder_type(tcx, placeholder_types, kind);
diff --git a/library/alloc/src/boxed.rs b/library/alloc/src/boxed.rs
index f6332b072cf..ab41f5646e5 100644
--- a/library/alloc/src/boxed.rs
+++ b/library/alloc/src/boxed.rs
@@ -763,6 +763,42 @@ impl<T, A: Allocator> Box<mem::MaybeUninit<T>, A> {
         let (raw, alloc) = Box::into_raw_with_allocator(self);
         unsafe { Box::from_raw_in(raw as *mut T, alloc) }
     }
+
+    /// Writes the value and converts to `Box<T, A>`.
+    ///
+    /// This method converts the box similarly to [`Box::assume_init`] but
+    /// writes `value` into it before conversion thus guaranteeing safety.
+    /// In some scenarios use of this method may improve performance because
+    /// the compiler may be able to optimize copying from stack.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// #![feature(new_uninit)]
+    ///
+    /// let big_box = Box::<[usize; 1024]>::new_uninit();
+    ///
+    /// let mut array = [0; 1024];
+    /// for (i, place) in array.iter_mut().enumerate() {
+    ///     *place = i;
+    /// }
+    ///
+    /// // The optimizer may be able to elide this copy, so previous code writes
+    /// // to heap directly.
+    /// let big_box = Box::write(big_box, array);
+    ///
+    /// for (i, x) in big_box.iter().enumerate() {
+    ///     assert_eq!(*x, i);
+    /// }
+    /// ```
+    #[unstable(feature = "new_uninit", issue = "63291")]
+    #[inline]
+    pub fn write(mut boxed: Self, value: T) -> Box<T, A> {
+        unsafe {
+            (*boxed).write(value);
+            boxed.assume_init()
+        }
+    }
 }
 
 impl<T, A: Allocator> Box<[mem::MaybeUninit<T>], A> {
@@ -1482,8 +1518,6 @@ impl<T, const N: usize> TryFrom<Box<[T]>> for Box<[T; N]> {
 }
 
 impl<A: Allocator> Box<dyn Any, A> {
-    #[inline]
-    #[stable(feature = "rust1", since = "1.0.0")]
     /// Attempt to downcast the box to a concrete type.
     ///
     /// # Examples
@@ -1501,21 +1535,48 @@ impl<A: Allocator> Box<dyn Any, A> {
     /// print_if_string(Box::new(my_string));
     /// print_if_string(Box::new(0i8));
     /// ```
+    #[inline]
+    #[stable(feature = "rust1", since = "1.0.0")]
     pub fn downcast<T: Any>(self) -> Result<Box<T, A>, Self> {
-        if self.is::<T>() {
-            unsafe {
-                let (raw, alloc): (*mut dyn Any, _) = Box::into_raw_with_allocator(self);
-                Ok(Box::from_raw_in(raw as *mut T, alloc))
-            }
-        } else {
-            Err(self)
+        if self.is::<T>() { unsafe { Ok(self.downcast_unchecked::<T>()) } } else { Err(self) }
+    }
+
+    /// Downcasts the box to a concrete type.
+    ///
+    /// For a safe alternative see [`downcast`].
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// #![feature(downcast_unchecked)]
+    ///
+    /// use std::any::Any;
+    ///
+    /// let x: Box<dyn Any> = Box::new(1_usize);
+    ///
+    /// unsafe {
+    ///     assert_eq!(*x.downcast_unchecked::<usize>(), 1);
+    /// }
+    /// ```
+    ///
+    /// # Safety
+    ///
+    /// The contained value must be of type `T`. Calling this method
+    /// with the incorrect type is *undefined behavior*.
+    ///
+    /// [`downcast`]: Self::downcast
+    #[inline]
+    #[unstable(feature = "downcast_unchecked", issue = "90850")]
+    pub unsafe fn downcast_unchecked<T: Any>(self) -> Box<T, A> {
+        debug_assert!(self.is::<T>());
+        unsafe {
+            let (raw, alloc): (*mut dyn Any, _) = Box::into_raw_with_allocator(self);
+            Box::from_raw_in(raw as *mut T, alloc)
         }
     }
 }
 
 impl<A: Allocator> Box<dyn Any + Send, A> {
-    #[inline]
-    #[stable(feature = "rust1", since = "1.0.0")]
     /// Attempt to downcast the box to a concrete type.
     ///
     /// # Examples
@@ -1533,21 +1594,48 @@ impl<A: Allocator> Box<dyn Any + Send, A> {
     /// print_if_string(Box::new(my_string));
     /// print_if_string(Box::new(0i8));
     /// ```
+    #[inline]
+    #[stable(feature = "rust1", since = "1.0.0")]
     pub fn downcast<T: Any>(self) -> Result<Box<T, A>, Self> {
-        if self.is::<T>() {
-            unsafe {
-                let (raw, alloc): (*mut (dyn Any + Send), _) = Box::into_raw_with_allocator(self);
-                Ok(Box::from_raw_in(raw as *mut T, alloc))
-            }
-        } else {
-            Err(self)
+        if self.is::<T>() { unsafe { Ok(self.downcast_unchecked::<T>()) } } else { Err(self) }
+    }
+
+    /// Downcasts the box to a concrete type.
+    ///
+    /// For a safe alternative see [`downcast`].
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// #![feature(downcast_unchecked)]
+    ///
+    /// use std::any::Any;
+    ///
+    /// let x: Box<dyn Any + Send> = Box::new(1_usize);
+    ///
+    /// unsafe {
+    ///     assert_eq!(*x.downcast_unchecked::<usize>(), 1);
+    /// }
+    /// ```
+    ///
+    /// # Safety
+    ///
+    /// The contained value must be of type `T`. Calling this method
+    /// with the incorrect type is *undefined behavior*.
+    ///
+    /// [`downcast`]: Self::downcast
+    #[inline]
+    #[unstable(feature = "downcast_unchecked", issue = "90850")]
+    pub unsafe fn downcast_unchecked<T: Any>(self) -> Box<T, A> {
+        debug_assert!(self.is::<T>());
+        unsafe {
+            let (raw, alloc): (*mut (dyn Any + Send), _) = Box::into_raw_with_allocator(self);
+            Box::from_raw_in(raw as *mut T, alloc)
         }
     }
 }
 
 impl<A: Allocator> Box<dyn Any + Send + Sync, A> {
-    #[inline]
-    #[stable(feature = "box_send_sync_any_downcast", since = "1.51.0")]
     /// Attempt to downcast the box to a concrete type.
     ///
     /// # Examples
@@ -1565,15 +1653,44 @@ impl<A: Allocator> Box<dyn Any + Send + Sync, A> {
     /// print_if_string(Box::new(my_string));
     /// print_if_string(Box::new(0i8));
     /// ```
+    #[inline]
+    #[stable(feature = "box_send_sync_any_downcast", since = "1.51.0")]
     pub fn downcast<T: Any>(self) -> Result<Box<T, A>, Self> {
-        if self.is::<T>() {
-            unsafe {
-                let (raw, alloc): (*mut (dyn Any + Send + Sync), _) =
-                    Box::into_raw_with_allocator(self);
-                Ok(Box::from_raw_in(raw as *mut T, alloc))
-            }
-        } else {
-            Err(self)
+        if self.is::<T>() { unsafe { Ok(self.downcast_unchecked::<T>()) } } else { Err(self) }
+    }
+
+    /// Downcasts the box to a concrete type.
+    ///
+    /// For a safe alternative see [`downcast`].
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// #![feature(downcast_unchecked)]
+    ///
+    /// use std::any::Any;
+    ///
+    /// let x: Box<dyn Any + Send + Sync> = Box::new(1_usize);
+    ///
+    /// unsafe {
+    ///     assert_eq!(*x.downcast_unchecked::<usize>(), 1);
+    /// }
+    /// ```
+    ///
+    /// # Safety
+    ///
+    /// The contained value must be of type `T`. Calling this method
+    /// with the incorrect type is *undefined behavior*.
+    ///
+    /// [`downcast`]: Self::downcast
+    #[inline]
+    #[unstable(feature = "downcast_unchecked", issue = "90850")]
+    pub unsafe fn downcast_unchecked<T: Any>(self) -> Box<T, A> {
+        debug_assert!(self.is::<T>());
+        unsafe {
+            let (raw, alloc): (*mut (dyn Any + Send + Sync), _) =
+                Box::into_raw_with_allocator(self);
+            Box::from_raw_in(raw as *mut T, alloc)
         }
     }
 }
diff --git a/library/alloc/src/collections/vec_deque/mod.rs b/library/alloc/src/collections/vec_deque/mod.rs
index de607c8fdab..42eae6a54b5 100644
--- a/library/alloc/src/collections/vec_deque/mod.rs
+++ b/library/alloc/src/collections/vec_deque/mod.rs
@@ -2149,13 +2149,44 @@ impl<T, A: Allocator> VecDeque<T, A> {
     where
         F: FnMut(&T) -> bool,
     {
+        self.retain_mut(|elem| f(elem));
+    }
+
+    /// Retains only the elements specified by the predicate.
+    ///
+    /// In other words, remove all elements `e` such that `f(&e)` returns false.
+    /// This method operates in place, visiting each element exactly once in the
+    /// original order, and preserves the order of the retained elements.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// #![feature(vec_retain_mut)]
+    ///
+    /// use std::collections::VecDeque;
+    ///
+    /// let mut buf = VecDeque::new();
+    /// buf.extend(1..5);
+    /// buf.retain_mut(|x| if *x % 2 == 0 {
+    ///     *x += 1;
+    ///     true
+    /// } else {
+    ///     false
+    /// });
+    /// assert_eq!(buf, [3, 5]);
+    /// ```
+    #[unstable(feature = "vec_retain_mut", issue = "90829")]
+    pub fn retain_mut<F>(&mut self, mut f: F)
+    where
+        F: FnMut(&mut T) -> bool,
+    {
         let len = self.len();
         let mut idx = 0;
         let mut cur = 0;
 
         // Stage 1: All values are retained.
         while cur < len {
-            if !f(&self[cur]) {
+            if !f(&mut self[cur]) {
                 cur += 1;
                 break;
             }
@@ -2164,7 +2195,7 @@ impl<T, A: Allocator> VecDeque<T, A> {
         }
         // Stage 2: Swap retained value into current idx.
         while cur < len {
-            if !f(&self[cur]) {
+            if !f(&mut self[cur]) {
                 cur += 1;
                 continue;
             }
@@ -2173,25 +2204,27 @@ impl<T, A: Allocator> VecDeque<T, A> {
             cur += 1;
             idx += 1;
         }
-        // Stage 3: Trancate all values after idx.
+        // Stage 3: Truncate all values after idx.
         if cur != idx {
             self.truncate(idx);
         }
     }
 
+    // Double the buffer size. This method is inline(never), so we expect it to only
+    // be called in cold paths.
     // This may panic or abort
     #[inline(never)]
     fn grow(&mut self) {
-        if self.is_full() {
-            let old_cap = self.cap();
-            // Double the buffer size.
-            self.buf.reserve_exact(old_cap, old_cap);
-            assert!(self.cap() == old_cap * 2);
-            unsafe {
-                self.handle_capacity_increase(old_cap);
-            }
-            debug_assert!(!self.is_full());
+        // Extend or possibly remove this assertion when valid use-cases for growing the
+        // buffer without it being full emerge
+        debug_assert!(self.is_full());
+        let old_cap = self.cap();
+        self.buf.reserve_exact(old_cap, old_cap);
+        assert!(self.cap() == old_cap * 2);
+        unsafe {
+            self.handle_capacity_increase(old_cap);
         }
+        debug_assert!(!self.is_full());
     }
 
     /// Modifies the `VecDeque` in-place so that `len()` is equal to `new_len`,
diff --git a/library/core/src/any.rs b/library/core/src/any.rs
index 1fd5aa27fce..72528185707 100644
--- a/library/core/src/any.rs
+++ b/library/core/src/any.rs
@@ -164,7 +164,7 @@ impl fmt::Debug for dyn Any + Send + Sync {
 }
 
 impl dyn Any {
-    /// Returns `true` if the boxed type is the same as `T`.
+    /// Returns `true` if the inner type is the same as `T`.
     ///
     /// # Examples
     ///
@@ -195,7 +195,7 @@ impl dyn Any {
         t == concrete
     }
 
-    /// Returns some reference to the boxed value if it is of type `T`, or
+    /// Returns some reference to the inner value if it is of type `T`, or
     /// `None` if it isn't.
     ///
     /// # Examples
@@ -221,13 +221,13 @@ impl dyn Any {
             // SAFETY: just checked whether we are pointing to the correct type, and we can rely on
             // that check for memory safety because we have implemented Any for all types; no other
             // impls can exist as they would conflict with our impl.
-            unsafe { Some(&*(self as *const dyn Any as *const T)) }
+            unsafe { Some(self.downcast_ref_unchecked()) }
         } else {
             None
         }
     }
 
-    /// Returns some mutable reference to the boxed value if it is of type `T`, or
+    /// Returns some mutable reference to the inner value if it is of type `T`, or
     /// `None` if it isn't.
     ///
     /// # Examples
@@ -257,15 +257,73 @@ impl dyn Any {
             // SAFETY: just checked whether we are pointing to the correct type, and we can rely on
             // that check for memory safety because we have implemented Any for all types; no other
             // impls can exist as they would conflict with our impl.
-            unsafe { Some(&mut *(self as *mut dyn Any as *mut T)) }
+            unsafe { Some(self.downcast_mut_unchecked()) }
         } else {
             None
         }
     }
+
+    /// Returns a reference to the inner value as type `dyn T`.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// #![feature(downcast_unchecked)]
+    ///
+    /// use std::any::Any;
+    ///
+    /// let x: Box<dyn Any> = Box::new(1_usize);
+    ///
+    /// unsafe {
+    ///     assert_eq!(*x.downcast_ref_unchecked::<usize>(), 1);
+    /// }
+    /// ```
+    ///
+    /// # Safety
+    ///
+    /// The contained value must be of type `T`. Calling this method
+    /// with the incorrect type is *undefined behavior*.
+    #[unstable(feature = "downcast_unchecked", issue = "90850")]
+    #[inline]
+    pub unsafe fn downcast_ref_unchecked<T: Any>(&self) -> &T {
+        debug_assert!(self.is::<T>());
+        // SAFETY: caller guarantees that T is the correct type
+        unsafe { &*(self as *const dyn Any as *const T) }
+    }
+
+    /// Returns a mutable reference to the inner value as type `dyn T`.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// #![feature(downcast_unchecked)]
+    ///
+    /// use std::any::Any;
+    ///
+    /// let mut x: Box<dyn Any> = Box::new(1_usize);
+    ///
+    /// unsafe {
+    ///     *x.downcast_mut_unchecked::<usize>() += 1;
+    /// }
+    ///
+    /// assert_eq!(*x.downcast_ref::<usize>().unwrap(), 2);
+    /// ```
+    ///
+    /// # Safety
+    ///
+    /// The contained value must be of type `T`. Calling this method
+    /// with the incorrect type is *undefined behavior*.
+    #[unstable(feature = "downcast_unchecked", issue = "90850")]
+    #[inline]
+    pub unsafe fn downcast_mut_unchecked<T: Any>(&mut self) -> &mut T {
+        debug_assert!(self.is::<T>());
+        // SAFETY: caller guarantees that T is the correct type
+        unsafe { &mut *(self as *mut dyn Any as *mut T) }
+    }
 }
 
 impl dyn Any + Send {
-    /// Forwards to the method defined on the type `Any`.
+    /// Forwards to the method defined on the type `dyn Any`.
     ///
     /// # Examples
     ///
@@ -289,7 +347,7 @@ impl dyn Any + Send {
         <dyn Any>::is::<T>(self)
     }
 
-    /// Forwards to the method defined on the type `Any`.
+    /// Forwards to the method defined on the type `dyn Any`.
     ///
     /// # Examples
     ///
@@ -313,7 +371,7 @@ impl dyn Any + Send {
         <dyn Any>::downcast_ref::<T>(self)
     }
 
-    /// Forwards to the method defined on the type `Any`.
+    /// Forwards to the method defined on the type `dyn Any`.
     ///
     /// # Examples
     ///
@@ -340,6 +398,60 @@ impl dyn Any + Send {
     pub fn downcast_mut<T: Any>(&mut self) -> Option<&mut T> {
         <dyn Any>::downcast_mut::<T>(self)
     }
+
+    /// Forwards to the method defined on the type `dyn Any`.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// #![feature(downcast_unchecked)]
+    ///
+    /// use std::any::Any;
+    ///
+    /// let x: Box<dyn Any> = Box::new(1_usize);
+    ///
+    /// unsafe {
+    ///     assert_eq!(*x.downcast_ref_unchecked::<usize>(), 1);
+    /// }
+    /// ```
+    ///
+    /// # Safety
+    ///
+    /// Same as the method on the type `dyn Any`.
+    #[unstable(feature = "downcast_unchecked", issue = "90850")]
+    #[inline]
+    pub unsafe fn downcast_ref_unchecked<T: Any>(&self) -> &T {
+        // SAFETY: guaranteed by caller
+        unsafe { <dyn Any>::downcast_ref_unchecked::<T>(self) }
+    }
+
+    /// Forwards to the method defined on the type `dyn Any`.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// #![feature(downcast_unchecked)]
+    ///
+    /// use std::any::Any;
+    ///
+    /// let mut x: Box<dyn Any> = Box::new(1_usize);
+    ///
+    /// unsafe {
+    ///     *x.downcast_mut_unchecked::<usize>() += 1;
+    /// }
+    ///
+    /// assert_eq!(*x.downcast_ref::<usize>().unwrap(), 2);
+    /// ```
+    ///
+    /// # Safety
+    ///
+    /// Same as the method on the type `dyn Any`.
+    #[unstable(feature = "downcast_unchecked", issue = "90850")]
+    #[inline]
+    pub unsafe fn downcast_mut_unchecked<T: Any>(&mut self) -> &mut T {
+        // SAFETY: guaranteed by caller
+        unsafe { <dyn Any>::downcast_mut_unchecked::<T>(self) }
+    }
 }
 
 impl dyn Any + Send + Sync {
@@ -418,6 +530,52 @@ impl dyn Any + Send + Sync {
     pub fn downcast_mut<T: Any>(&mut self) -> Option<&mut T> {
         <dyn Any>::downcast_mut::<T>(self)
     }
+
+    /// Forwards to the method defined on the type `Any`.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// #![feature(downcast_unchecked)]
+    ///
+    /// use std::any::Any;
+    ///
+    /// let x: Box<dyn Any> = Box::new(1_usize);
+    ///
+    /// unsafe {
+    ///     assert_eq!(*x.downcast_ref_unchecked::<usize>(), 1);
+    /// }
+    /// ```
+    #[unstable(feature = "downcast_unchecked", issue = "90850")]
+    #[inline]
+    pub unsafe fn downcast_ref_unchecked<T: Any>(&self) -> &T {
+        // SAFETY: guaranteed by caller
+        unsafe { <dyn Any>::downcast_ref_unchecked::<T>(self) }
+    }
+
+    /// Forwards to the method defined on the type `Any`.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// #![feature(downcast_unchecked)]
+    ///
+    /// use std::any::Any;
+    ///
+    /// let mut x: Box<dyn Any> = Box::new(1_usize);
+    ///
+    /// unsafe {
+    ///     *x.downcast_mut_unchecked::<usize>() += 1;
+    /// }
+    ///
+    /// assert_eq!(*x.downcast_ref::<usize>().unwrap(), 2);
+    /// ```
+    #[unstable(feature = "downcast_unchecked", issue = "90850")]
+    #[inline]
+    pub unsafe fn downcast_mut_unchecked<T: Any>(&mut self) -> &mut T {
+        // SAFETY: guaranteed by caller
+        unsafe { <dyn Any>::downcast_mut_unchecked::<T>(self) }
+    }
 }
 
 ///////////////////////////////////////////////////////////////////////////////
diff --git a/library/core/src/array/mod.rs b/library/core/src/array/mod.rs
index 39ccbaaaf7b..d635829151e 100644
--- a/library/core/src/array/mod.rs
+++ b/library/core/src/array/mod.rs
@@ -11,7 +11,9 @@ use crate::fmt;
 use crate::hash::{self, Hash};
 use crate::iter::TrustedLen;
 use crate::mem::{self, MaybeUninit};
-use crate::ops::{Index, IndexMut};
+use crate::ops::{
+    ChangeOutputType, ControlFlow, FromResidual, Index, IndexMut, NeverShortCircuit, Residual, Try,
+};
 use crate::slice::{Iter, IterMut};
 
 mod equality;
@@ -49,9 +51,13 @@ where
 }
 
 /// Creates an array `[T; N]` where each fallible array element `T` is returned by the `cb` call.
-/// Unlike `core::array::from_fn`, where the element creation can't fail, this version will return an error
+/// Unlike [`from_fn`], where the element creation can't fail, this version will return an error
 /// if any element creation was unsuccessful.
 ///
+/// The return type of this function depends on the return type of the closure.
+/// If you return `Result<T, E>` from the closure, you'll get a `Result<[T; N]; E>`.
+/// If you return `Option<T>` from the closure, you'll get an `Option<[T; N]>`.
+///
 /// # Arguments
 ///
 /// * `cb`: Callback where the passed argument is the current array index.
@@ -60,27 +66,32 @@ where
 ///
 /// ```rust
 /// #![feature(array_from_fn)]
+/// # // Apparently these doc tests are still on edition2018
+/// # use std::convert::TryInto;
 ///
-/// #[derive(Debug, PartialEq)]
-/// enum SomeError {
-///     Foo,
-/// }
-///
-/// let array = core::array::try_from_fn(|i| Ok::<_, SomeError>(i));
+/// let array: Result<[u8; 5], _> = std::array::try_from_fn(|i| i.try_into());
 /// assert_eq!(array, Ok([0, 1, 2, 3, 4]));
 ///
-/// let another_array = core::array::try_from_fn::<SomeError, _, (), 2>(|_| Err(SomeError::Foo));
-/// assert_eq!(another_array, Err(SomeError::Foo));
+/// let array: Result<[i8; 200], _> = std::array::try_from_fn(|i| i.try_into());
+/// assert!(array.is_err());
+///
+/// let array: Option<[_; 4]> = std::array::try_from_fn(|i| i.checked_add(100));
+/// assert_eq!(array, Some([100, 101, 102, 103]));
+///
+/// let array: Option<[_; 4]> = std::array::try_from_fn(|i| i.checked_sub(100));
+/// assert_eq!(array, None);
 /// ```
 #[inline]
 #[unstable(feature = "array_from_fn", issue = "89379")]
-pub fn try_from_fn<E, F, T, const N: usize>(cb: F) -> Result<[T; N], E>
+pub fn try_from_fn<F, R, const N: usize>(cb: F) -> ChangeOutputType<R, [R::Output; N]>
 where
-    F: FnMut(usize) -> Result<T, E>,
+    F: FnMut(usize) -> R,
+    R: Try,
+    R::Residual: Residual<[R::Output; N]>,
 {
     // SAFETY: we know for certain that this iterator will yield exactly `N`
     // items.
-    unsafe { collect_into_array_rslt_unchecked(&mut (0..N).map(cb)) }
+    unsafe { try_collect_into_array_unchecked(&mut (0..N).map(cb)) }
 }
 
 /// Converts a reference to `T` into a reference to an array of length 1 (without copying).
@@ -444,6 +455,45 @@ impl<T, const N: usize> [T; N] {
         unsafe { collect_into_array_unchecked(&mut IntoIterator::into_iter(self).map(f)) }
     }
 
+    /// A fallible function `f` applied to each element on array `self` in order to
+    /// return an array the same size as `self` or the first error encountered.
+    ///
+    /// The return type of this function depends on the return type of the closure.
+    /// If you return `Result<T, E>` from the closure, you'll get a `Result<[T; N]; E>`.
+    /// If you return `Option<T>` from the closure, you'll get an `Option<[T; N]>`.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// #![feature(array_try_map)]
+    /// let a = ["1", "2", "3"];
+    /// let b = a.try_map(|v| v.parse::<u32>()).unwrap().map(|v| v + 1);
+    /// assert_eq!(b, [2, 3, 4]);
+    ///
+    /// let a = ["1", "2a", "3"];
+    /// let b = a.try_map(|v| v.parse::<u32>());
+    /// assert!(b.is_err());
+    ///
+    /// use std::num::NonZeroU32;
+    /// let z = [1, 2, 0, 3, 4];
+    /// assert_eq!(z.try_map(NonZeroU32::new), None);
+    /// let a = [1, 2, 3];
+    /// let b = a.try_map(NonZeroU32::new);
+    /// let c = b.map(|x| x.map(NonZeroU32::get));
+    /// assert_eq!(c, Some(a));
+    /// ```
+    #[unstable(feature = "array_try_map", issue = "79711")]
+    pub fn try_map<F, R>(self, f: F) -> ChangeOutputType<R, [R::Output; N]>
+    where
+        F: FnMut(T) -> R,
+        R: Try,
+        R::Residual: Residual<[R::Output; N]>,
+    {
+        // SAFETY: we know for certain that this iterator will yield exactly `N`
+        // items.
+        unsafe { try_collect_into_array_unchecked(&mut IntoIterator::into_iter(self).map(f)) }
+    }
+
     /// 'Zips up' two arrays into a single array of pairs.
     ///
     /// `zip()` returns a new array where every element is a tuple where the
@@ -621,42 +671,42 @@ impl<T, const N: usize> [T; N] {
 /// Pulls `N` items from `iter` and returns them as an array. If the iterator
 /// yields fewer than `N` items, this function exhibits undefined behavior.
 ///
-/// See [`collect_into_array`] for more information.
+/// See [`try_collect_into_array`] for more information.
 ///
 ///
 /// # Safety
 ///
 /// It is up to the caller to guarantee that `iter` yields at least `N` items.
 /// Violating this condition causes undefined behavior.
-unsafe fn collect_into_array_rslt_unchecked<E, I, T, const N: usize>(
-    iter: &mut I,
-) -> Result<[T; N], E>
+unsafe fn try_collect_into_array_unchecked<I, T, R, const N: usize>(iter: &mut I) -> R::TryType
 where
     // Note: `TrustedLen` here is somewhat of an experiment. This is just an
     // internal function, so feel free to remove if this bound turns out to be a
     // bad idea. In that case, remember to also remove the lower bound
     // `debug_assert!` below!
-    I: Iterator<Item = Result<T, E>> + TrustedLen,
+    I: Iterator + TrustedLen,
+    I::Item: Try<Output = T, Residual = R>,
+    R: Residual<[T; N]>,
 {
     debug_assert!(N <= iter.size_hint().1.unwrap_or(usize::MAX));
     debug_assert!(N <= iter.size_hint().0);
 
     // SAFETY: covered by the function contract.
-    unsafe { collect_into_array(iter).unwrap_unchecked() }
+    unsafe { try_collect_into_array(iter).unwrap_unchecked() }
 }
 
-// Infallible version of `collect_into_array_rslt_unchecked`.
+// Infallible version of `try_collect_into_array_unchecked`.
 unsafe fn collect_into_array_unchecked<I, const N: usize>(iter: &mut I) -> [I::Item; N]
 where
     I: Iterator + TrustedLen,
 {
-    let mut map = iter.map(Ok::<_, Infallible>);
+    let mut map = iter.map(NeverShortCircuit);
 
     // SAFETY: The same safety considerations w.r.t. the iterator length
-    // apply for `collect_into_array_rslt_unchecked` as for
+    // apply for `try_collect_into_array_unchecked` as for
     // `collect_into_array_unchecked`
-    match unsafe { collect_into_array_rslt_unchecked(&mut map) } {
-        Ok(array) => array,
+    match unsafe { try_collect_into_array_unchecked(&mut map) } {
+        NeverShortCircuit(array) => array,
     }
 }
 
@@ -670,13 +720,15 @@ where
 ///
 /// If `iter.next()` panicks, all items already yielded by the iterator are
 /// dropped.
-fn collect_into_array<E, I, T, const N: usize>(iter: &mut I) -> Option<Result<[T; N], E>>
+fn try_collect_into_array<I, T, R, const N: usize>(iter: &mut I) -> Option<R::TryType>
 where
-    I: Iterator<Item = Result<T, E>>,
+    I: Iterator,
+    I::Item: Try<Output = T, Residual = R>,
+    R: Residual<[T; N]>,
 {
     if N == 0 {
         // SAFETY: An empty array is always inhabited and has no validity invariants.
-        return unsafe { Some(Ok(mem::zeroed())) };
+        return unsafe { Some(Try::from_output(mem::zeroed())) };
     }
 
     struct Guard<'a, T, const N: usize> {
@@ -701,11 +753,11 @@ where
     let mut guard = Guard { array_mut: &mut array, initialized: 0 };
 
     while let Some(item_rslt) = iter.next() {
-        let item = match item_rslt {
-            Err(err) => {
-                return Some(Err(err));
+        let item = match item_rslt.branch() {
+            ControlFlow::Break(r) => {
+                return Some(FromResidual::from_residual(r));
             }
-            Ok(elem) => elem,
+            ControlFlow::Continue(elem) => elem,
         };
 
         // SAFETY: `guard.initialized` starts at 0, is increased by one in the
@@ -723,7 +775,7 @@ where
             // SAFETY: the condition above asserts that all elements are
             // initialized.
             let out = unsafe { MaybeUninit::array_assume_init(array) };
-            return Some(Ok(out));
+            return Some(Try::from_output(out));
         }
     }
 
diff --git a/library/core/src/future/future.rs b/library/core/src/future/future.rs
index 09d8a2aac26..6b62236b32f 100644
--- a/library/core/src/future/future.rs
+++ b/library/core/src/future/future.rs
@@ -28,7 +28,11 @@ use crate::task::{Context, Poll};
 #[must_use = "futures do nothing unless you `.await` or poll them"]
 #[stable(feature = "futures_api", since = "1.36.0")]
 #[lang = "future_trait"]
-#[rustc_on_unimplemented(label = "`{Self}` is not a future", message = "`{Self}` is not a future")]
+#[rustc_on_unimplemented(
+    label = "`{Self}` is not a future",
+    message = "`{Self}` is not a future",
+    note = "{Self} must be a future or must implement `IntoFuture` to be awaited"
+)]
 pub trait Future {
     /// The type of value produced on completion.
     #[stable(feature = "futures_api", since = "1.36.0")]
diff --git a/library/core/src/future/into_future.rs b/library/core/src/future/into_future.rs
index 4020c254446..cac1866188e 100644
--- a/library/core/src/future/into_future.rs
+++ b/library/core/src/future/into_future.rs
@@ -13,6 +13,7 @@ pub trait IntoFuture {
 
     /// Creates a future from a value.
     #[unstable(feature = "into_future", issue = "67644")]
+    #[cfg_attr(not(bootstrap), lang = "into_future")]
     fn into_future(self) -> Self::Future;
 }
 
diff --git a/library/core/src/iter/traits/iterator.rs b/library/core/src/iter/traits/iterator.rs
index 35ce9400f8f..267fa406798 100644
--- a/library/core/src/iter/traits/iterator.rs
+++ b/library/core/src/iter/traits/iterator.rs
@@ -1,5 +1,5 @@
 use crate::cmp::{self, Ordering};
-use crate::ops::{ControlFlow, Try};
+use crate::ops::{ChangeOutputType, ControlFlow, FromResidual, Residual, Try};
 
 use super::super::TrustedRandomAccessNoCoerce;
 use super::super::{Chain, Cloned, Copied, Cycle, Enumerate, Filter, FilterMap, Fuse};
@@ -2216,6 +2216,86 @@ pub trait Iterator {
         Some(self.fold(first, f))
     }
 
+    /// Reduces the elements to a single one by repeatedly applying a reducing operation. If the
+    /// closure returns a failure, the failure is propagated back to the caller immediately.
+    ///
+    /// The return type of this method depends on the return type of the closure. If the closure
+    /// returns `Result<Self::Item, E>`, then this function will return `Result<Option<Self::Item>,
+    /// E>`. If the closure returns `Option<Self::Item>`, then this function will return
+    /// `Option<Option<Self::Item>>`.
+    ///
+    /// When called on an empty iterator, this function will return either `Some(None)` or
+    /// `Ok(None)` depending on the type of the provided closure.
+    ///
+    /// For iterators with at least one element, this is essentially the same as calling
+    /// [`try_fold()`] with the first element of the iterator as the initial accumulator value.
+    ///
+    /// [`try_fold()`]: Iterator::try_fold
+    ///
+    /// # Examples
+    ///
+    /// Safely calculate the sum of a series of numbers:
+    ///
+    /// ```
+    /// #![feature(iterator_try_reduce)]
+    ///
+    /// let numbers: Vec<usize> = vec![10, 20, 5, 23, 0];
+    /// let sum = numbers.into_iter().try_reduce(|x, y| x.checked_add(y));
+    /// assert_eq!(sum, Some(Some(58)));
+    /// ```
+    ///
+    /// Determine when a reduction short circuited:
+    ///
+    /// ```
+    /// #![feature(iterator_try_reduce)]
+    ///
+    /// let numbers = vec![1, 2, 3, usize::MAX, 4, 5];
+    /// let sum = numbers.into_iter().try_reduce(|x, y| x.checked_add(y));
+    /// assert_eq!(sum, None);
+    /// ```
+    ///
+    /// Determine when a reduction was not performed because there are no elements:
+    ///
+    /// ```
+    /// #![feature(iterator_try_reduce)]
+    ///
+    /// let numbers: Vec<usize> = Vec::new();
+    /// let sum = numbers.into_iter().try_reduce(|x, y| x.checked_add(y));
+    /// assert_eq!(sum, Some(None));
+    /// ```
+    ///
+    /// Use a [`Result`] instead of an [`Option`]:
+    ///
+    /// ```
+    /// #![feature(iterator_try_reduce)]
+    ///
+    /// let numbers = vec!["1", "2", "3", "4", "5"];
+    /// let max: Result<Option<_>, <usize as std::str::FromStr>::Err> =
+    ///     numbers.into_iter().try_reduce(|x, y| {
+    ///         if x.parse::<usize>()? > y.parse::<usize>()? { Ok(x) } else { Ok(y) }
+    ///     });
+    /// assert_eq!(max, Ok(Some("5")));
+    /// ```
+    #[inline]
+    #[unstable(feature = "iterator_try_reduce", reason = "new API", issue = "87053")]
+    fn try_reduce<F, R>(&mut self, f: F) -> ChangeOutputType<R, Option<R::Output>>
+    where
+        Self: Sized,
+        F: FnMut(Self::Item, Self::Item) -> R,
+        R: Try<Output = Self::Item>,
+        R::Residual: Residual<Option<Self::Item>>,
+    {
+        let first = match self.next() {
+            Some(i) => i,
+            None => return Try::from_output(None),
+        };
+
+        match self.try_fold(first, f).branch() {
+            ControlFlow::Break(r) => FromResidual::from_residual(r),
+            ControlFlow::Continue(i) => Try::from_output(Some(i)),
+        }
+    }
+
     /// Tests if every element of the iterator matches a predicate.
     ///
     /// `all()` takes a closure that returns `true` or `false`. It applies
@@ -2418,6 +2498,10 @@ pub trait Iterator {
     /// Applies function to the elements of iterator and returns
     /// the first true result or the first error.
     ///
+    /// The return type of this method depends on the return type of the closure.
+    /// If you return `Result<bool, E>` from the closure, you'll get a `Result<Option<Self::Item>; E>`.
+    /// If you return `Option<bool>` from the closure, you'll get an `Option<Option<Self::Item>>`.
+    ///
     /// # Examples
     ///
     /// ```
@@ -2435,32 +2519,48 @@ pub trait Iterator {
     /// let result = a.iter().try_find(|&&s| is_my_num(s, 5));
     /// assert!(result.is_err());
     /// ```
+    ///
+    /// This also supports other types which implement `Try`, not just `Result`.
+    /// ```
+    /// #![feature(try_find)]
+    ///
+    /// use std::num::NonZeroU32;
+    /// let a = [3, 5, 7, 4, 9, 0, 11];
+    /// let result = a.iter().try_find(|&&x| NonZeroU32::new(x).map(|y| y.is_power_of_two()));
+    /// assert_eq!(result, Some(Some(&4)));
+    /// let result = a.iter().take(3).try_find(|&&x| NonZeroU32::new(x).map(|y| y.is_power_of_two()));
+    /// assert_eq!(result, Some(None));
+    /// let result = a.iter().rev().try_find(|&&x| NonZeroU32::new(x).map(|y| y.is_power_of_two()));
+    /// assert_eq!(result, None);
+    /// ```
     #[inline]
     #[unstable(feature = "try_find", reason = "new API", issue = "63178")]
-    fn try_find<F, R, E>(&mut self, f: F) -> Result<Option<Self::Item>, E>
+    fn try_find<F, R>(&mut self, f: F) -> ChangeOutputType<R, Option<Self::Item>>
     where
         Self: Sized,
         F: FnMut(&Self::Item) -> R,
         R: Try<Output = bool>,
-        // FIXME: This bound is rather strange, but means minimal breakage on nightly.
-        // See #85115 for the issue tracking a holistic solution for this and try_map.
-        R: Try<Residual = Result<crate::convert::Infallible, E>>,
+        R::Residual: Residual<Option<Self::Item>>,
     {
         #[inline]
-        fn check<F, T, R, E>(mut f: F) -> impl FnMut((), T) -> ControlFlow<Result<T, E>>
+        fn check<I, V, R>(
+            mut f: impl FnMut(&I) -> V,
+        ) -> impl FnMut((), I) -> ControlFlow<R::TryType>
         where
-            F: FnMut(&T) -> R,
-            R: Try<Output = bool>,
-            R: Try<Residual = Result<crate::convert::Infallible, E>>,
+            V: Try<Output = bool, Residual = R>,
+            R: Residual<Option<I>>,
         {
             move |(), x| match f(&x).branch() {
                 ControlFlow::Continue(false) => ControlFlow::CONTINUE,
-                ControlFlow::Continue(true) => ControlFlow::Break(Ok(x)),
-                ControlFlow::Break(Err(x)) => ControlFlow::Break(Err(x)),
+                ControlFlow::Continue(true) => ControlFlow::Break(Try::from_output(Some(x))),
+                ControlFlow::Break(r) => ControlFlow::Break(FromResidual::from_residual(r)),
             }
         }
 
-        self.try_fold((), check(f)).break_value().transpose()
+        match self.try_fold((), check(f)) {
+            ControlFlow::Break(x) => x,
+            ControlFlow::Continue(()) => Try::from_output(None),
+        }
     }
 
     /// Searches for an element in an iterator, returning its index.
diff --git a/library/core/src/ops/control_flow.rs b/library/core/src/ops/control_flow.rs
index b0c15898a1f..5ee8e377de1 100644
--- a/library/core/src/ops/control_flow.rs
+++ b/library/core/src/ops/control_flow.rs
@@ -123,6 +123,11 @@ impl<B, C> ops::FromResidual for ControlFlow<B, C> {
     }
 }
 
+#[unstable(feature = "try_trait_v2_residual", issue = "91285")]
+impl<B, C> ops::Residual<C> for ControlFlow<B, convert::Infallible> {
+    type TryType = ControlFlow<B, C>;
+}
+
 impl<B, C> ControlFlow<B, C> {
     /// Returns `true` if this is a `Break` variant.
     ///
diff --git a/library/core/src/ops/mod.rs b/library/core/src/ops/mod.rs
index 6c866031370..9d1e7e81b0e 100644
--- a/library/core/src/ops/mod.rs
+++ b/library/core/src/ops/mod.rs
@@ -187,6 +187,11 @@ pub use self::range::OneSidedRange;
 #[unstable(feature = "try_trait_v2", issue = "84277")]
 pub use self::try_trait::{FromResidual, Try};
 
+#[unstable(feature = "try_trait_v2_residual", issue = "91285")]
+pub use self::try_trait::Residual;
+
+pub(crate) use self::try_trait::{ChangeOutputType, NeverShortCircuit};
+
 #[unstable(feature = "generator_trait", issue = "43122")]
 pub use self::generator::{Generator, GeneratorState};
 
diff --git a/library/core/src/ops/try_trait.rs b/library/core/src/ops/try_trait.rs
index 6bdcda775ee..f4f0a589809 100644
--- a/library/core/src/ops/try_trait.rs
+++ b/library/core/src/ops/try_trait.rs
@@ -338,3 +338,61 @@ pub trait FromResidual<R = <Self as Try>::Residual> {
     #[unstable(feature = "try_trait_v2", issue = "84277")]
     fn from_residual(residual: R) -> Self;
 }
+
+/// Allows retrieving the canonical type implementing [`Try`] that has this type
+/// as its residual and allows it to hold an `O` as its output.
+///
+/// If you think of the `Try` trait as splitting a type into its [`Try::Output`]
+/// and [`Try::Residual`] components, this allows putting them back together.
+///
+/// For example,
+/// `Result<T, E>: Try<Output = T, Residual = Result<Infallible, E>>`,
+/// and in the other direction,
+/// `<Result<Infallible, E> as Residual<T>>::TryType = Result<T, E>`.
+#[unstable(feature = "try_trait_v2_residual", issue = "91285")]
+pub trait Residual<O> {
+    /// The "return" type of this meta-function.
+    #[unstable(feature = "try_trait_v2_residual", issue = "91285")]
+    type TryType: Try<Output = O, Residual = Self>;
+}
+
+#[unstable(feature = "pub_crate_should_not_need_unstable_attr", issue = "none")]
+pub(crate) type ChangeOutputType<T, V> = <<T as Try>::Residual as Residual<V>>::TryType;
+
+/// An adapter for implementing non-try methods via the `Try` implementation.
+///
+/// Conceptually the same as `Result<T, !>`, but requiring less work in trait
+/// solving and inhabited-ness checking and such, by being an obvious newtype
+/// and not having `From` bounds lying around.
+///
+/// Not currently planned to be exposed publicly, so just `pub(crate)`.
+#[repr(transparent)]
+pub(crate) struct NeverShortCircuit<T>(pub T);
+
+pub(crate) enum NeverShortCircuitResidual {}
+
+impl<T> Try for NeverShortCircuit<T> {
+    type Output = T;
+    type Residual = NeverShortCircuitResidual;
+
+    #[inline]
+    fn branch(self) -> ControlFlow<NeverShortCircuitResidual, T> {
+        ControlFlow::Continue(self.0)
+    }
+
+    #[inline]
+    fn from_output(x: T) -> Self {
+        NeverShortCircuit(x)
+    }
+}
+
+impl<T> FromResidual for NeverShortCircuit<T> {
+    #[inline]
+    fn from_residual(never: NeverShortCircuitResidual) -> Self {
+        match never {}
+    }
+}
+
+impl<T> Residual<T> for NeverShortCircuitResidual {
+    type TryType = NeverShortCircuit<T>;
+}
diff --git a/library/core/src/option.rs b/library/core/src/option.rs
index 4eeb5e43943..7b9c6e43960 100644
--- a/library/core/src/option.rs
+++ b/library/core/src/option.rs
@@ -703,7 +703,8 @@ impl<T> Option<T> {
     #[inline]
     #[track_caller]
     #[stable(feature = "rust1", since = "1.0.0")]
-    pub fn expect(self, msg: &str) -> T {
+    #[rustc_const_unstable(feature = "const_option", issue = "67441")]
+    pub const fn expect(self, msg: &str) -> T {
         match self {
             Some(val) => val,
             None => expect_failed(msg),
@@ -1658,7 +1659,7 @@ impl<T, E> Option<Result<T, E>> {
 #[inline(never)]
 #[cold]
 #[track_caller]
-fn expect_failed(msg: &str) -> ! {
+const fn expect_failed(msg: &str) -> ! {
     panic!("{}", msg)
 }
 
@@ -2088,6 +2089,11 @@ impl<T> const ops::FromResidual for Option<T> {
     }
 }
 
+#[unstable(feature = "try_trait_v2_residual", issue = "91285")]
+impl<T> ops::Residual<T> for Option<convert::Infallible> {
+    type TryType = Option<T>;
+}
+
 impl<T> Option<Option<T>> {
     /// Converts from `Option<Option<T>>` to `Option<T>`.
     ///
diff --git a/library/core/src/result.rs b/library/core/src/result.rs
index a494c089f68..e6b8c8ec338 100644
--- a/library/core/src/result.rs
+++ b/library/core/src/result.rs
@@ -1959,3 +1959,8 @@ impl<T, E, F: From<E>> ops::FromResidual<Result<convert::Infallible, E>> for Res
         }
     }
 }
+
+#[unstable(feature = "try_trait_v2_residual", issue = "91285")]
+impl<T, E> ops::Residual<T> for Result<convert::Infallible, E> {
+    type TryType = Result<T, E>;
+}
diff --git a/library/core/tests/array.rs b/library/core/tests/array.rs
index 7dc071b7423..43d30d12355 100644
--- a/library/core/tests/array.rs
+++ b/library/core/tests/array.rs
@@ -377,7 +377,7 @@ fn array_try_from_fn() {
     let array = core::array::try_from_fn(|i| Ok::<_, SomeError>(i));
     assert_eq!(array, Ok([0, 1, 2, 3, 4]));
 
-    let another_array = core::array::try_from_fn::<SomeError, _, (), 2>(|_| Err(SomeError::Foo));
+    let another_array = core::array::try_from_fn::<_, Result<(), _>, 2>(|_| Err(SomeError::Foo));
     assert_eq!(another_array, Err(SomeError::Foo));
 }
 
diff --git a/library/core/tests/iter/traits/iterator.rs b/library/core/tests/iter/traits/iterator.rs
index 422e389e380..d38bca1e3b3 100644
--- a/library/core/tests/iter/traits/iterator.rs
+++ b/library/core/tests/iter/traits/iterator.rs
@@ -455,6 +455,34 @@ fn test_find_map() {
 }
 
 #[test]
+fn test_try_reduce() {
+    let v: Vec<usize> = vec![1, 2, 3, 4, 5];
+    let sum = v.into_iter().try_reduce(|x, y| x.checked_add(y));
+    assert_eq!(sum, Some(Some(15)));
+
+    let v: Vec<usize> = vec![1, 2, 3, 4, 5, usize::MAX];
+    let sum = v.into_iter().try_reduce(|x, y| x.checked_add(y));
+    assert_eq!(sum, None);
+
+    let v: Vec<usize> = Vec::new();
+    let sum = v.into_iter().try_reduce(|x, y| x.checked_add(y));
+    assert_eq!(sum, Some(None));
+
+    let v = vec!["1", "2", "3", "4", "5"];
+    let max = v.into_iter().try_reduce(|x, y| {
+        if x.parse::<usize>().ok()? > y.parse::<usize>().ok()? { Some(x) } else { Some(y) }
+    });
+    assert_eq!(max, Some(Some("5")));
+
+    let v = vec!["1", "2", "3", "4", "5"];
+    let max: Result<Option<_>, <usize as std::str::FromStr>::Err> =
+        v.into_iter().try_reduce(|x, y| {
+            if x.parse::<usize>()? > y.parse::<usize>()? { Ok(x) } else { Ok(y) }
+        });
+    assert_eq!(max, Ok(Some("5")));
+}
+
+#[test]
 fn test_iterator_len() {
     let v: &[_] = &[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
     assert_eq!(v[..4].iter().count(), 4);
diff --git a/library/core/tests/lib.rs b/library/core/tests/lib.rs
index d49c2552cfd..9ab98ba8886 100644
--- a/library/core/tests/lib.rs
+++ b/library/core/tests/lib.rs
@@ -56,6 +56,7 @@
 #![feature(iter_intersperse)]
 #![feature(iter_is_partitioned)]
 #![feature(iter_order_by)]
+#![feature(iterator_try_reduce)]
 #![feature(const_mut_refs)]
 #![feature(const_pin)]
 #![feature(const_slice_from_raw_parts)]
diff --git a/library/std/src/lib.rs b/library/std/src/lib.rs
index 41b94cb294c..67846e78835 100644
--- a/library/std/src/lib.rs
+++ b/library/std/src/lib.rs
@@ -216,10 +216,7 @@
 // std may use features in a platform-specific way
 #![allow(unused_features)]
 #![feature(rustc_allow_const_fn_unstable)]
-#![cfg_attr(
-    test,
-    feature(internal_output_capture, print_internals, update_panic_count, thread_local_const_init)
-)]
+#![cfg_attr(test, feature(internal_output_capture, print_internals, update_panic_count))]
 #![cfg_attr(
     all(target_vendor = "fortanix", target_env = "sgx"),
     feature(slice_index_methods, coerce_unsized, sgx_platform)
diff --git a/library/std/src/sys/unix/os.rs b/library/std/src/sys/unix/os.rs
index 7686b61b67a..8a028d99306 100644
--- a/library/std/src/sys/unix/os.rs
+++ b/library/std/src/sys/unix/os.rs
@@ -97,6 +97,7 @@ pub fn errno() -> i32 {
 }
 
 #[cfg(target_os = "dragonfly")]
+#[allow(dead_code)]
 pub fn set_errno(e: i32) {
     extern "C" {
         #[thread_local]
@@ -472,10 +473,7 @@ impl Iterator for Env {
 
 #[cfg(target_os = "macos")]
 pub unsafe fn environ() -> *mut *const *const c_char {
-    extern "C" {
-        fn _NSGetEnviron() -> *mut *const *const c_char;
-    }
-    _NSGetEnviron()
+    libc::_NSGetEnviron() as *mut *const *const c_char
 }
 
 #[cfg(not(target_os = "macos"))]
diff --git a/library/std/src/thread/local.rs b/library/std/src/thread/local.rs
index 4da59577d78..c03fe116320 100644
--- a/library/std/src/thread/local.rs
+++ b/library/std/src/thread/local.rs
@@ -76,7 +76,21 @@ use crate::fmt;
 ///    destroyed, but not all platforms have this guard. Those platforms that do
 ///    not guard typically have a synthetic limit after which point no more
 ///    destructors are run.
+/// 3. When the process exits on Windows systems, TLS destructors may only be
+///    run on the thread that causes the process to exit. This is because the
+///    other threads may be forcibly terminated.
 ///
+/// ## Synchronization in thread-local destructors
+///
+/// On Windows, synchronization operations (such as [`JoinHandle::join`]) in
+/// thread local destructors are prone to deadlocks and so should be avoided.
+/// This is because the [loader lock] is held while a destructor is run. The
+/// lock is acquired whenever a thread starts or exits or when a DLL is loaded
+/// or unloaded. Therefore these events are blocked for as long as a thread
+/// local destructor is running.
+///
+/// [loader lock]: https://docs.microsoft.com/en-us/windows/win32/dlls/dynamic-link-library-best-practices
+/// [`JoinHandle::join`]: crate::thread::JoinHandle::join
 /// [`with`]: LocalKey::with
 #[stable(feature = "rust1", since = "1.0.0")]
 pub struct LocalKey<T: 'static> {
@@ -164,7 +178,6 @@ macro_rules! __thread_local_inner {
     (@key $t:ty, const $init:expr) => {{
         #[cfg_attr(not(windows), inline)] // see comments below
         unsafe fn __getit() -> $crate::option::Option<&'static $t> {
-            const _REQUIRE_UNSTABLE: () = $crate::thread::require_unstable_const_init_thread_local();
             const INIT_EXPR: $t = $init;
 
             // wasm without atomics maps directly to `static mut`, and dtors
diff --git a/library/std/src/thread/mod.rs b/library/std/src/thread/mod.rs
index 343d3ef8dc5..64f6c7fa022 100644
--- a/library/std/src/thread/mod.rs
+++ b/library/std/src/thread/mod.rs
@@ -204,13 +204,6 @@ pub use self::local::os::Key as __OsLocalKeyInner;
 #[doc(hidden)]
 pub use self::local::statik::Key as __StaticLocalKeyInner;
 
-// This is only used to make thread locals with `const { .. }` initialization
-// expressions unstable. If and/or when that syntax is stabilized with thread
-// locals this will simply be removed.
-#[doc(hidden)]
-#[unstable(feature = "thread_local_const_init", issue = "84223")]
-pub const fn require_unstable_const_init_thread_local() {}
-
 ////////////////////////////////////////////////////////////////////////////////
 // Builder
 ////////////////////////////////////////////////////////////////////////////////
diff --git a/library/unwind/build.rs b/library/unwind/build.rs
index 1d0b4a59a28..a3f5224151d 100644
--- a/library/unwind/build.rs
+++ b/library/unwind/build.rs
@@ -17,6 +17,9 @@ fn main() {
         } else {
             println!("cargo:rustc-link-lib=gcc");
         }
+
+        // Android's unwinding library depends on dl_iterate_phdr in `libdl`.
+        println!("cargo:rustc-link-lib=dl");
     } else if target.contains("freebsd") {
         println!("cargo:rustc-link-lib=gcc_s");
     } else if target.contains("netbsd") {
diff --git a/src/doc/unstable-book/src/library-features/asm.md b/src/doc/unstable-book/src/library-features/asm.md
index fac55b97888..fa238a8b3bc 100644
--- a/src/doc/unstable-book/src/library-features/asm.md
+++ b/src/doc/unstable-book/src/library-features/asm.md
@@ -454,7 +454,7 @@ operand_expr := expr / "_" / expr "=>" expr / expr "=>" "_"
 reg_operand := dir_spec "(" reg_spec ")" operand_expr
 operand := reg_operand / "const" const_expr / "sym" path
 clobber_abi := "clobber_abi(" <abi> *["," <abi>] [","] ")"
-option := "pure" / "nomem" / "readonly" / "preserves_flags" / "noreturn" / "nostack" / "att_syntax" / "raw"
+option := "pure" / "nomem" / "readonly" / "preserves_flags" / "noreturn" / "nostack" / "att_syntax" / "raw" / "may_unwind"
 options := "options(" option *["," option] [","] ")"
 asm := "asm!(" format_string *("," format_string) *("," [ident "="] operand) *("," clobber_abi) *("," options) [","] ")"
 ```
@@ -829,6 +829,7 @@ Currently the following options are defined:
 - `noreturn`: The `asm` block never returns, and its return type is defined as `!` (never). Behavior is undefined if execution falls through past the end of the asm code. A `noreturn` asm block behaves just like a function which doesn't return; notably, local variables in scope are not dropped before it is invoked.
 - `nostack`: The `asm` block does not push data to the stack, or write to the stack red-zone (if supported by the target). If this option is *not* used then the stack pointer is guaranteed to be suitably aligned (according to the target ABI) for a function call.
 - `att_syntax`: This option is only valid on x86, and causes the assembler to use the `.att_syntax prefix` mode of the GNU assembler. Register operands are substituted in with a leading `%`.
+- `may_unwind`: The `asm` block may unwind the stack and be part of the stack unwinding process (This option is only supported by the LLVM backend right now).
 - `raw`: This causes the template string to be parsed as a raw assembly string, with no special handling for `{` and `}`. This is primarily useful when including raw assembly code from an external file using `include_str!`.
 
 The compiler performs some additional checks on options:
diff --git a/src/etc/htmldocck.py b/src/etc/htmldocck.py
index 8647db5a45d..48a341ffe08 100644
--- a/src/etc/htmldocck.py
+++ b/src/etc/htmldocck.py
@@ -90,10 +90,20 @@ There are a number of supported commands:
   highlights for example. If you want to simply check for the presence of
   a given node or attribute, use an empty string (`""`) as a `PATTERN`.
 
-* `@count PATH XPATH COUNT' checks for the occurrence of the given XPath
+* `@count PATH XPATH COUNT` checks for the occurrence of the given XPath
   in the specified file. The number of occurrences must match the given
   count.
 
+* `@snapshot NAME PATH XPATH` creates a snapshot test named NAME.
+  A snapshot test captures a subtree of the DOM, at the location
+  determined by the XPath, and compares it to a pre-recorded value
+  in a file. The file's name is the test's name with the `.rs` extension
+  replaced with `.NAME.html`, where NAME is the snapshot's name.
+
+  htmldocck supports the `--bless` option to accept the current subtree
+  as expected, saving it to the file determined by the snapshot's name.
+  compiletest's `--bless` flag is forwarded to htmldocck.
+
 * `@has-dir PATH` checks for the existence of the given directory.
 
 All conditions can be negated with `!`. `@!has foo/type.NoSuch.html`
@@ -137,6 +147,10 @@ except NameError:
 
 channel = os.environ["DOC_RUST_LANG_ORG_CHANNEL"]
 
+# Initialized in main
+rust_test_path = None
+bless = None
+
 class CustomHTMLParser(HTMLParser):
     """simplified HTML parser.
 
@@ -387,6 +401,32 @@ def get_tree_count(tree, path):
     return len(tree.findall(path))
 
 
+def check_snapshot(snapshot_name, tree):
+    assert rust_test_path.endswith('.rs')
+    snapshot_path = '{}.{}.{}'.format(rust_test_path[:-3], snapshot_name, 'html')
+    try:
+        with open(snapshot_path, 'r') as snapshot_file:
+            expected_str = snapshot_file.read()
+    except FileNotFoundError:
+        if bless:
+            expected_str = None
+        else:
+            raise FailedCheck('No saved snapshot value')
+
+    actual_str = ET.tostring(tree).decode('utf-8')
+
+    if expected_str != actual_str:
+        if bless:
+            with open(snapshot_path, 'w') as snapshot_file:
+                snapshot_file.write(actual_str)
+        else:
+            print('--- expected ---\n')
+            print(expected_str)
+            print('\n\n--- actual ---\n')
+            print(actual_str)
+            print()
+            raise FailedCheck('Actual snapshot value is different than expected')
+
 def stderr(*args):
     if sys.version_info.major < 3:
         file = codecs.getwriter('utf-8')(sys.stderr)
@@ -448,6 +488,28 @@ def check_command(c, cache):
                 ret = expected == found
             else:
                 raise InvalidCheck('Invalid number of @{} arguments'.format(c.cmd))
+
+        elif c.cmd == 'snapshot':  # snapshot test
+            if len(c.args) == 3:  # @snapshot <snapshot-name> <html-path> <xpath>
+                [snapshot_name, html_path, pattern] = c.args
+                tree = cache.get_tree(html_path)
+                xpath = normalize_xpath(pattern)
+                subtrees = tree.findall(xpath)
+                if len(subtrees) == 1:
+                    [subtree] = subtrees
+                    try:
+                        check_snapshot(snapshot_name, subtree)
+                        ret = True
+                    except FailedCheck as err:
+                        cerr = str(err)
+                        ret = False
+                elif len(subtrees) == 0:
+                    raise FailedCheck('XPATH did not match')
+                else:
+                    raise FailedCheck('Expected 1 match, but found {}'.format(len(subtrees)))
+            else:
+                raise InvalidCheck('Invalid number of @{} arguments'.format(c.cmd))
+
         elif c.cmd == 'has-dir':  # has-dir test
             if len(c.args) == 1:  # @has-dir <path> = has-dir test
                 try:
@@ -458,11 +520,13 @@ def check_command(c, cache):
                     ret = False
             else:
                 raise InvalidCheck('Invalid number of @{} arguments'.format(c.cmd))
+
         elif c.cmd == 'valid-html':
             raise InvalidCheck('Unimplemented @valid-html')
 
         elif c.cmd == 'valid-links':
             raise InvalidCheck('Unimplemented @valid-links')
+
         else:
             raise InvalidCheck('Unrecognized @{}'.format(c.cmd))
 
@@ -483,11 +547,19 @@ def check(target, commands):
 
 
 if __name__ == '__main__':
-    if len(sys.argv) != 3:
-        stderr('Usage: {} <doc dir> <template>'.format(sys.argv[0]))
+    if len(sys.argv) not in [3, 4]:
+        stderr('Usage: {} <doc dir> <template> [--bless]'.format(sys.argv[0]))
         raise SystemExit(1)
 
-    check(sys.argv[1], get_commands(sys.argv[2]))
+    rust_test_path = sys.argv[2]
+    if len(sys.argv) > 3 and sys.argv[3] == '--bless':
+        bless = True
+    else:
+        # We only support `--bless` at the end of the arguments.
+        # This assert is to prevent silent failures.
+        assert '--bless' not in sys.argv
+        bless = False
+    check(sys.argv[1], get_commands(rust_test_path))
     if ERR_COUNT:
         stderr("\nEncountered {} errors".format(ERR_COUNT))
         raise SystemExit(1)
diff --git a/src/librustdoc/clean/auto_trait.rs b/src/librustdoc/clean/auto_trait.rs
index 2ccf17387d1..7b66ff7d411 100644
--- a/src/librustdoc/clean/auto_trait.rs
+++ b/src/librustdoc/clean/auto_trait.rs
@@ -100,9 +100,12 @@ impl<'a, 'tcx> AutoTraitFinder<'a, 'tcx> {
                 // Instead, we generate `impl !Send for Foo<T>`, which better
                 // expresses the fact that `Foo<T>` never implements `Send`,
                 // regardless of the choice of `T`.
-                let params = (tcx.generics_of(item_def_id), ty::GenericPredicates::default())
-                    .clean(self.cx)
-                    .params;
+                let raw_generics = clean_ty_generics(
+                    self.cx,
+                    tcx.generics_of(item_def_id),
+                    ty::GenericPredicates::default(),
+                );
+                let params = raw_generics.params;
 
                 Generics { params, where_predicates: Vec::new() }
             }
@@ -451,10 +454,12 @@ impl<'a, 'tcx> AutoTraitFinder<'a, 'tcx> {
             })
             .map(|p| p.fold_with(&mut replacer));
 
-        let mut generic_params =
-            (tcx.generics_of(item_def_id), tcx.explicit_predicates_of(item_def_id))
-                .clean(self.cx)
-                .params;
+        let raw_generics = clean_ty_generics(
+            self.cx,
+            tcx.generics_of(item_def_id),
+            tcx.explicit_predicates_of(item_def_id),
+        );
+        let mut generic_params = raw_generics.params;
 
         debug!("param_env_to_generics({:?}): generic_params={:?}", item_def_id, generic_params);
 
diff --git a/src/librustdoc/clean/blanket_impl.rs b/src/librustdoc/clean/blanket_impl.rs
index 7ca5cb4bd42..80e3bb5c662 100644
--- a/src/librustdoc/clean/blanket_impl.rs
+++ b/src/librustdoc/clean/blanket_impl.rs
@@ -3,7 +3,7 @@ use rustc_hir as hir;
 use rustc_infer::infer::{InferOk, TyCtxtInferExt};
 use rustc_infer::traits;
 use rustc_middle::ty::subst::Subst;
-use rustc_middle::ty::ToPredicate;
+use rustc_middle::ty::{ToPredicate, WithConstness};
 use rustc_span::DUMMY_SP;
 
 use super::*;
@@ -66,8 +66,7 @@ impl<'a, 'tcx> BlanketImplFinder<'a, 'tcx> {
                             .into_iter()
                             .chain(Some(
                                 ty::Binder::dummy(trait_ref)
-                                    .to_poly_trait_predicate()
-                                    .map_bound(ty::PredicateKind::Trait)
+                                    .without_const()
                                     .to_predicate(infcx.tcx),
                             ));
                         for predicate in predicates {
@@ -108,11 +107,11 @@ impl<'a, 'tcx> BlanketImplFinder<'a, 'tcx> {
                     def_id: ItemId::Blanket { impl_id: impl_def_id, for_: item_def_id },
                     kind: box ImplItem(Impl {
                         unsafety: hir::Unsafety::Normal,
-                        generics: (
+                        generics: clean_ty_generics(
+                            self.cx,
                             self.cx.tcx.generics_of(impl_def_id),
                             self.cx.tcx.explicit_predicates_of(impl_def_id),
-                        )
-                            .clean(self.cx),
+                        ),
                         // FIXME(eddyb) compute both `trait_` and `for_` from
                         // the post-inference `trait_ref`, as it's more accurate.
                         trait_: Some(trait_ref.clean(self.cx)),
diff --git a/src/librustdoc/clean/inline.rs b/src/librustdoc/clean/inline.rs
index ba67030d59f..39544fa843d 100644
--- a/src/librustdoc/clean/inline.rs
+++ b/src/librustdoc/clean/inline.rs
@@ -15,13 +15,12 @@ use rustc_span::hygiene::MacroKind;
 use rustc_span::symbol::{kw, sym, Symbol};
 
 use crate::clean::{
-    self, utils, Attributes, AttributesExt, ImplKind, ItemId, NestedAttributesExt, Type,
+    self, clean_fn_decl_from_did_and_sig, clean_ty_generics, utils, Attributes, AttributesExt,
+    Clean, ImplKind, ItemId, NestedAttributesExt, Type, Visibility,
 };
 use crate::core::DocContext;
 use crate::formats::item_type::ItemType;
 
-use super::{Clean, Visibility};
-
 type Attrs<'hir> = rustc_middle::ty::Attributes<'hir>;
 
 /// Attempt to inline a definition into this AST.
@@ -208,7 +207,7 @@ crate fn build_external_trait(cx: &mut DocContext<'_>, did: DefId) -> clean::Tra
         .collect();
 
     let predicates = cx.tcx.predicates_of(did);
-    let generics = (cx.tcx.generics_of(did), predicates).clean(cx);
+    let generics = clean_ty_generics(cx, cx.tcx.generics_of(did), predicates);
     let generics = filter_non_trait_generics(did, generics);
     let (generics, supertrait_bounds) = separate_supertrait_bounds(generics);
     let is_auto = cx.tcx.trait_is_auto(did);
@@ -230,7 +229,9 @@ fn build_external_function(cx: &mut DocContext<'_>, did: DefId) -> clean::Functi
     let predicates = cx.tcx.predicates_of(did);
     let (generics, decl) = clean::enter_impl_trait(cx, |cx| {
         // NOTE: generics need to be cleaned before the decl!
-        ((cx.tcx.generics_of(did), predicates).clean(cx), (did, sig).clean(cx))
+        let generics = clean_ty_generics(cx, cx.tcx.generics_of(did), predicates);
+        let decl = clean_fn_decl_from_did_and_sig(cx, did, sig);
+        (generics, decl)
     });
     clean::Function {
         decl,
@@ -243,7 +244,7 @@ fn build_enum(cx: &mut DocContext<'_>, did: DefId) -> clean::Enum {
     let predicates = cx.tcx.explicit_predicates_of(did);
 
     clean::Enum {
-        generics: (cx.tcx.generics_of(did), predicates).clean(cx),
+        generics: clean_ty_generics(cx, cx.tcx.generics_of(did), predicates),
         variants_stripped: false,
         variants: cx.tcx.adt_def(did).variants.iter().map(|v| v.clean(cx)).collect(),
     }
@@ -255,7 +256,7 @@ fn build_struct(cx: &mut DocContext<'_>, did: DefId) -> clean::Struct {
 
     clean::Struct {
         struct_type: variant.ctor_kind,
-        generics: (cx.tcx.generics_of(did), predicates).clean(cx),
+        generics: clean_ty_generics(cx, cx.tcx.generics_of(did), predicates),
         fields: variant.fields.iter().map(|x| x.clean(cx)).collect(),
         fields_stripped: false,
     }
@@ -265,7 +266,7 @@ fn build_union(cx: &mut DocContext<'_>, did: DefId) -> clean::Union {
     let predicates = cx.tcx.explicit_predicates_of(did);
     let variant = cx.tcx.adt_def(did).non_enum_variant();
 
-    let generics = (cx.tcx.generics_of(did), predicates).clean(cx);
+    let generics = clean_ty_generics(cx, cx.tcx.generics_of(did), predicates);
     let fields = variant.fields.iter().map(|x| x.clean(cx)).collect();
     clean::Union { generics, fields, fields_stripped: false }
 }
@@ -276,7 +277,7 @@ fn build_type_alias(cx: &mut DocContext<'_>, did: DefId) -> clean::Typedef {
 
     clean::Typedef {
         type_,
-        generics: (cx.tcx.generics_of(did), predicates).clean(cx),
+        generics: clean_ty_generics(cx, cx.tcx.generics_of(did), predicates),
         item_type: None,
     }
 }
@@ -440,7 +441,9 @@ crate fn build_impl(
                     }
                 })
                 .collect::<Vec<_>>(),
-            clean::enter_impl_trait(cx, |cx| (tcx.generics_of(did), predicates).clean(cx)),
+            clean::enter_impl_trait(cx, |cx| {
+                clean_ty_generics(cx, tcx.generics_of(did), predicates)
+            }),
         ),
     };
     let polarity = tcx.impl_polarity(did);
diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs
index 9c3484b4a31..f11fa0295c5 100644
--- a/src/librustdoc/clean/mod.rs
+++ b/src/librustdoc/clean/mod.rs
@@ -31,6 +31,7 @@ use rustc_typeck::hir_ty_to_ty;
 
 use std::assert_matches::assert_matches;
 use std::collections::hash_map::Entry;
+use std::collections::BTreeMap;
 use std::default::Default;
 use std::hash::Hash;
 use std::{mem, vec};
@@ -51,9 +52,17 @@ crate trait Clean<T> {
 impl Clean<Item> for DocModule<'_> {
     fn clean(&self, cx: &mut DocContext<'_>) -> Item {
         let mut items: Vec<Item> = vec![];
-        items.extend(self.foreigns.iter().map(|x| x.clean(cx)));
+        items.extend(
+            self.foreigns
+                .iter()
+                .map(|(item, renamed)| clean_maybe_renamed_foreign_item(cx, item, *renamed)),
+        );
         items.extend(self.mods.iter().map(|x| x.clean(cx)));
-        items.extend(self.items.iter().map(|x| x.clean(cx)).flatten());
+        items.extend(
+            self.items
+                .iter()
+                .flat_map(|(item, renamed)| clean_maybe_renamed_item(cx, item, *renamed)),
+        );
 
         // determine if we should display the inner contents or
         // the outer `mod` item for the source code.
@@ -102,11 +111,9 @@ impl Clean<GenericBound> for hir::GenericBound<'_> {
                     _ => bug!("clean: parenthesized `GenericBound::LangItemTrait`"),
                 };
 
+                let trait_ = clean_trait_ref_with_bindings(cx, trait_ref, &bindings);
                 GenericBound::TraitBound(
-                    PolyTrait {
-                        trait_: (trait_ref, &bindings[..]).clean(cx),
-                        generic_params: vec![],
-                    },
+                    PolyTrait { trait_, generic_params: vec![] },
                     hir::TraitBoundModifier::None,
                 )
             }
@@ -117,64 +124,60 @@ impl Clean<GenericBound> for hir::GenericBound<'_> {
     }
 }
 
-impl Clean<Path> for (ty::TraitRef<'_>, &[TypeBinding]) {
-    fn clean(&self, cx: &mut DocContext<'_>) -> Path {
-        let (trait_ref, bounds) = *self;
-        let kind = cx.tcx.def_kind(trait_ref.def_id).into();
-        if !matches!(kind, ItemType::Trait | ItemType::TraitAlias) {
-            span_bug!(
-                cx.tcx.def_span(trait_ref.def_id),
-                "`TraitRef` had unexpected kind {:?}",
-                kind
-            );
-        }
-        inline::record_extern_fqn(cx, trait_ref.def_id, kind);
-        let path = external_path(cx, trait_ref.def_id, true, bounds.to_vec(), trait_ref.substs);
+fn clean_trait_ref_with_bindings(
+    cx: &mut DocContext<'_>,
+    trait_ref: ty::TraitRef<'_>,
+    bindings: &[TypeBinding],
+) -> Path {
+    let kind = cx.tcx.def_kind(trait_ref.def_id).into();
+    if !matches!(kind, ItemType::Trait | ItemType::TraitAlias) {
+        span_bug!(cx.tcx.def_span(trait_ref.def_id), "`TraitRef` had unexpected kind {:?}", kind);
+    }
+    inline::record_extern_fqn(cx, trait_ref.def_id, kind);
+    let path = external_path(cx, trait_ref.def_id, true, bindings.to_vec(), trait_ref.substs);
 
-        debug!("ty::TraitRef\n  subst: {:?}\n", trait_ref.substs);
+    debug!("ty::TraitRef\n  subst: {:?}\n", trait_ref.substs);
 
-        path
-    }
+    path
 }
 
 impl Clean<Path> for ty::TraitRef<'tcx> {
     fn clean(&self, cx: &mut DocContext<'_>) -> Path {
-        (*self, &[][..]).clean(cx)
+        clean_trait_ref_with_bindings(cx, *self, &[])
     }
 }
 
-impl Clean<GenericBound> for (ty::PolyTraitRef<'_>, &[TypeBinding]) {
-    fn clean(&self, cx: &mut DocContext<'_>) -> GenericBound {
-        let (poly_trait_ref, bounds) = *self;
-        let poly_trait_ref = poly_trait_ref.lift_to_tcx(cx.tcx).unwrap();
-
-        // collect any late bound regions
-        let late_bound_regions: Vec<_> = cx
-            .tcx
-            .collect_referenced_late_bound_regions(&poly_trait_ref)
-            .into_iter()
-            .filter_map(|br| match br {
-                ty::BrNamed(_, name) => Some(GenericParamDef {
-                    name,
-                    kind: GenericParamDefKind::Lifetime { outlives: vec![] },
-                }),
-                _ => None,
-            })
-            .collect();
+fn clean_poly_trait_ref_with_bindings(
+    cx: &mut DocContext<'_>,
+    poly_trait_ref: ty::PolyTraitRef<'_>,
+    bindings: &[TypeBinding],
+) -> GenericBound {
+    let poly_trait_ref = poly_trait_ref.lift_to_tcx(cx.tcx).unwrap();
+
+    // collect any late bound regions
+    let late_bound_regions: Vec<_> = cx
+        .tcx
+        .collect_referenced_late_bound_regions(&poly_trait_ref)
+        .into_iter()
+        .filter_map(|br| match br {
+            ty::BrNamed(_, name) => Some(GenericParamDef {
+                name,
+                kind: GenericParamDefKind::Lifetime { outlives: vec![] },
+            }),
+            _ => None,
+        })
+        .collect();
 
-        GenericBound::TraitBound(
-            PolyTrait {
-                trait_: (poly_trait_ref.skip_binder(), bounds).clean(cx),
-                generic_params: late_bound_regions,
-            },
-            hir::TraitBoundModifier::None,
-        )
-    }
+    let trait_ = clean_trait_ref_with_bindings(cx, poly_trait_ref.skip_binder(), bindings);
+    GenericBound::TraitBound(
+        PolyTrait { trait_, generic_params: late_bound_regions },
+        hir::TraitBoundModifier::None,
+    )
 }
 
 impl<'tcx> Clean<GenericBound> for ty::PolyTraitRef<'tcx> {
     fn clean(&self, cx: &mut DocContext<'_>) -> GenericBound {
-        (*self, &[][..]).clean(cx)
+        clean_poly_trait_ref_with_bindings(cx, *self, &[])
     }
 }
 
@@ -528,170 +531,164 @@ impl Clean<Generics> for hir::Generics<'_> {
     }
 }
 
-impl<'a, 'tcx> Clean<Generics> for (&'a ty::Generics, ty::GenericPredicates<'tcx>) {
-    fn clean(&self, cx: &mut DocContext<'_>) -> Generics {
-        use self::WherePredicate as WP;
-        use std::collections::BTreeMap;
-
-        let (gens, preds) = *self;
-
-        // Don't populate `cx.impl_trait_bounds` before `clean`ning `where` clauses,
-        // since `Clean for ty::Predicate` would consume them.
-        let mut impl_trait = BTreeMap::<ImplTraitParam, Vec<GenericBound>>::default();
-
-        // Bounds in the type_params and lifetimes fields are repeated in the
-        // predicates field (see rustc_typeck::collect::ty_generics), so remove
-        // them.
-        let stripped_params = gens
-            .params
-            .iter()
-            .filter_map(|param| match param.kind {
-                ty::GenericParamDefKind::Lifetime => Some(param.clean(cx)),
-                ty::GenericParamDefKind::Type { synthetic, .. } => {
-                    if param.name == kw::SelfUpper {
-                        assert_eq!(param.index, 0);
-                        return None;
-                    }
-                    if synthetic {
-                        impl_trait.insert(param.index.into(), vec![]);
-                        return None;
-                    }
-                    Some(param.clean(cx))
+fn clean_ty_generics(
+    cx: &mut DocContext<'_>,
+    gens: &ty::Generics,
+    preds: ty::GenericPredicates<'tcx>,
+) -> Generics {
+    // Don't populate `cx.impl_trait_bounds` before `clean`ning `where` clauses,
+    // since `Clean for ty::Predicate` would consume them.
+    let mut impl_trait = BTreeMap::<ImplTraitParam, Vec<GenericBound>>::default();
+
+    // Bounds in the type_params and lifetimes fields are repeated in the
+    // predicates field (see rustc_typeck::collect::ty_generics), so remove
+    // them.
+    let stripped_params = gens
+        .params
+        .iter()
+        .filter_map(|param| match param.kind {
+            ty::GenericParamDefKind::Lifetime => Some(param.clean(cx)),
+            ty::GenericParamDefKind::Type { synthetic, .. } => {
+                if param.name == kw::SelfUpper {
+                    assert_eq!(param.index, 0);
+                    return None;
                 }
-                ty::GenericParamDefKind::Const { .. } => Some(param.clean(cx)),
-            })
-            .collect::<Vec<GenericParamDef>>();
+                if synthetic {
+                    impl_trait.insert(param.index.into(), vec![]);
+                    return None;
+                }
+                Some(param.clean(cx))
+            }
+            ty::GenericParamDefKind::Const { .. } => Some(param.clean(cx)),
+        })
+        .collect::<Vec<GenericParamDef>>();
 
-        // param index -> [(DefId of trait, associated type name, type)]
-        let mut impl_trait_proj = FxHashMap::<u32, Vec<(DefId, Symbol, Ty<'tcx>)>>::default();
+    // param index -> [(DefId of trait, associated type name, type)]
+    let mut impl_trait_proj = FxHashMap::<u32, Vec<(DefId, Symbol, Ty<'tcx>)>>::default();
 
-        let where_predicates = preds
-            .predicates
-            .iter()
-            .flat_map(|(p, _)| {
-                let mut projection = None;
-                let param_idx = (|| {
-                    let bound_p = p.kind();
-                    match bound_p.skip_binder() {
-                        ty::PredicateKind::Trait(pred) => {
-                            if let ty::Param(param) = pred.self_ty().kind() {
-                                return Some(param.index);
-                            }
-                        }
-                        ty::PredicateKind::TypeOutlives(ty::OutlivesPredicate(ty, _reg)) => {
-                            if let ty::Param(param) = ty.kind() {
-                                return Some(param.index);
-                            }
+    let where_predicates = preds
+        .predicates
+        .iter()
+        .flat_map(|(p, _)| {
+            let mut projection = None;
+            let param_idx = (|| {
+                let bound_p = p.kind();
+                match bound_p.skip_binder() {
+                    ty::PredicateKind::Trait(pred) => {
+                        if let ty::Param(param) = pred.self_ty().kind() {
+                            return Some(param.index);
                         }
-                        ty::PredicateKind::Projection(p) => {
-                            if let ty::Param(param) = p.projection_ty.self_ty().kind() {
-                                projection = Some(bound_p.rebind(p));
-                                return Some(param.index);
-                            }
+                    }
+                    ty::PredicateKind::TypeOutlives(ty::OutlivesPredicate(ty, _reg)) => {
+                        if let ty::Param(param) = ty.kind() {
+                            return Some(param.index);
                         }
-                        _ => (),
                     }
-
-                    None
-                })();
-
-                if let Some(param_idx) = param_idx {
-                    if let Some(b) = impl_trait.get_mut(&param_idx.into()) {
-                        let p = p.clean(cx)?;
-
-                        b.extend(
-                            p.get_bounds()
-                                .into_iter()
-                                .flatten()
-                                .cloned()
-                                .filter(|b| !b.is_sized_bound(cx)),
-                        );
-
-                        let proj = projection
-                            .map(|p| (p.skip_binder().projection_ty.clean(cx), p.skip_binder().ty));
-                        if let Some(((_, trait_did, name), rhs)) =
-                            proj.as_ref().and_then(|(lhs, rhs)| Some((lhs.projection()?, rhs)))
-                        {
-                            impl_trait_proj
-                                .entry(param_idx)
-                                .or_default()
-                                .push((trait_did, name, rhs));
+                    ty::PredicateKind::Projection(p) => {
+                        if let ty::Param(param) = p.projection_ty.self_ty().kind() {
+                            projection = Some(bound_p.rebind(p));
+                            return Some(param.index);
                         }
-
-                        return None;
                     }
+                    _ => (),
                 }
 
-                Some(p)
-            })
-            .collect::<Vec<_>>();
-
-        for (param, mut bounds) in impl_trait {
-            // Move trait bounds to the front.
-            bounds.sort_by_key(|b| !matches!(b, GenericBound::TraitBound(..)));
-
-            if let crate::core::ImplTraitParam::ParamIndex(idx) = param {
-                if let Some(proj) = impl_trait_proj.remove(&idx) {
-                    for (trait_did, name, rhs) in proj {
-                        let rhs = rhs.clean(cx);
-                        simplify::merge_bounds(cx, &mut bounds, trait_did, name, &rhs);
+                None
+            })();
+
+            if let Some(param_idx) = param_idx {
+                if let Some(b) = impl_trait.get_mut(&param_idx.into()) {
+                    let p = p.clean(cx)?;
+
+                    b.extend(
+                        p.get_bounds()
+                            .into_iter()
+                            .flatten()
+                            .cloned()
+                            .filter(|b| !b.is_sized_bound(cx)),
+                    );
+
+                    let proj = projection
+                        .map(|p| (p.skip_binder().projection_ty.clean(cx), p.skip_binder().ty));
+                    if let Some(((_, trait_did, name), rhs)) =
+                        proj.as_ref().and_then(|(lhs, rhs)| Some((lhs.projection()?, rhs)))
+                    {
+                        impl_trait_proj.entry(param_idx).or_default().push((trait_did, name, rhs));
                     }
+
+                    return None;
                 }
-            } else {
-                unreachable!();
             }
 
-            cx.impl_trait_bounds.insert(param, bounds);
-        }
+            Some(p)
+        })
+        .collect::<Vec<_>>();
 
-        // Now that `cx.impl_trait_bounds` is populated, we can process
-        // remaining predicates which could contain `impl Trait`.
-        let mut where_predicates =
-            where_predicates.into_iter().flat_map(|p| p.clean(cx)).collect::<Vec<_>>();
-
-        // Type parameters have a Sized bound by default unless removed with
-        // ?Sized. Scan through the predicates and mark any type parameter with
-        // a Sized bound, removing the bounds as we find them.
-        //
-        // Note that associated types also have a sized bound by default, but we
-        // don't actually know the set of associated types right here so that's
-        // handled in cleaning associated types
-        let mut sized_params = FxHashSet::default();
-        where_predicates.retain(|pred| match *pred {
-            WP::BoundPredicate { ty: Generic(ref g), ref bounds, .. } => {
-                if bounds.iter().any(|b| b.is_sized_bound(cx)) {
-                    sized_params.insert(*g);
-                    false
-                } else {
-                    true
+    for (param, mut bounds) in impl_trait {
+        // Move trait bounds to the front.
+        bounds.sort_by_key(|b| !matches!(b, GenericBound::TraitBound(..)));
+
+        if let crate::core::ImplTraitParam::ParamIndex(idx) = param {
+            if let Some(proj) = impl_trait_proj.remove(&idx) {
+                for (trait_did, name, rhs) in proj {
+                    let rhs = rhs.clean(cx);
+                    simplify::merge_bounds(cx, &mut bounds, trait_did, name, &rhs);
                 }
             }
-            _ => true,
-        });
+        } else {
+            unreachable!();
+        }
 
-        // Run through the type parameters again and insert a ?Sized
-        // unbound for any we didn't find to be Sized.
-        for tp in &stripped_params {
-            if matches!(tp.kind, types::GenericParamDefKind::Type { .. })
-                && !sized_params.contains(&tp.name)
-            {
-                where_predicates.push(WP::BoundPredicate {
-                    ty: Type::Generic(tp.name),
-                    bounds: vec![GenericBound::maybe_sized(cx)],
-                    bound_params: Vec::new(),
-                })
+        cx.impl_trait_bounds.insert(param, bounds);
+    }
+
+    // Now that `cx.impl_trait_bounds` is populated, we can process
+    // remaining predicates which could contain `impl Trait`.
+    let mut where_predicates =
+        where_predicates.into_iter().flat_map(|p| p.clean(cx)).collect::<Vec<_>>();
+
+    // Type parameters have a Sized bound by default unless removed with
+    // ?Sized. Scan through the predicates and mark any type parameter with
+    // a Sized bound, removing the bounds as we find them.
+    //
+    // Note that associated types also have a sized bound by default, but we
+    // don't actually know the set of associated types right here so that's
+    // handled in cleaning associated types
+    let mut sized_params = FxHashSet::default();
+    where_predicates.retain(|pred| match *pred {
+        WherePredicate::BoundPredicate { ty: Generic(ref g), ref bounds, .. } => {
+            if bounds.iter().any(|b| b.is_sized_bound(cx)) {
+                sized_params.insert(*g);
+                false
+            } else {
+                true
             }
         }
+        _ => true,
+    });
 
-        // It would be nice to collect all of the bounds on a type and recombine
-        // them if possible, to avoid e.g., `where T: Foo, T: Bar, T: Sized, T: 'a`
-        // and instead see `where T: Foo + Bar + Sized + 'a`
-
-        Generics {
-            params: stripped_params,
-            where_predicates: simplify::where_clauses(cx, where_predicates),
+    // Run through the type parameters again and insert a ?Sized
+    // unbound for any we didn't find to be Sized.
+    for tp in &stripped_params {
+        if matches!(tp.kind, types::GenericParamDefKind::Type { .. })
+            && !sized_params.contains(&tp.name)
+        {
+            where_predicates.push(WherePredicate::BoundPredicate {
+                ty: Type::Generic(tp.name),
+                bounds: vec![GenericBound::maybe_sized(cx)],
+                bound_params: Vec::new(),
+            })
         }
     }
+
+    // It would be nice to collect all of the bounds on a type and recombine
+    // them if possible, to avoid e.g., `where T: Foo, T: Bar, T: Sized, T: 'a`
+    // and instead see `where T: Foo + Bar + Sized + 'a`
+
+    Generics {
+        params: stripped_params,
+        where_predicates: simplify::where_clauses(cx, where_predicates),
+    }
 }
 
 fn clean_fn_or_proc_macro(
@@ -741,7 +738,7 @@ fn clean_fn_or_proc_macro(
             ProcMacroItem(ProcMacro { kind, helpers })
         }
         None => {
-            let mut func = (sig, generics, body_id).clean(cx);
+            let mut func = clean_function(cx, sig, generics, body_id);
             let def_id = item.def_id.to_def_id();
             func.header.constness =
                 if cx.tcx.is_const_fn(def_id) && is_unstable_const_fn(cx.tcx, def_id).is_none() {
@@ -785,54 +782,59 @@ fn clean_fn_decl_legacy_const_generics(func: &mut Function, attrs: &[ast::Attrib
     }
 }
 
-impl<'a> Clean<Function> for (&'a hir::FnSig<'a>, &'a hir::Generics<'a>, hir::BodyId) {
-    fn clean(&self, cx: &mut DocContext<'_>) -> Function {
-        let (generics, decl) = enter_impl_trait(cx, |cx| {
-            // NOTE: generics must be cleaned before args
-            let generics = self.1.clean(cx);
-            let args = (self.0.decl.inputs, self.2).clean(cx);
-            let decl = clean_fn_decl_with_args(cx, self.0.decl, args);
-            (generics, decl)
-        });
-        Function { decl, generics, header: self.0.header }
-    }
+fn clean_function(
+    cx: &mut DocContext<'_>,
+    sig: &hir::FnSig<'_>,
+    generics: &hir::Generics<'_>,
+    body_id: hir::BodyId,
+) -> Function {
+    let (generics, decl) = enter_impl_trait(cx, |cx| {
+        // NOTE: generics must be cleaned before args
+        let generics = generics.clean(cx);
+        let args = clean_args_from_types_and_body_id(cx, sig.decl.inputs, body_id);
+        let decl = clean_fn_decl_with_args(cx, sig.decl, args);
+        (generics, decl)
+    });
+    Function { decl, generics, header: sig.header }
 }
 
-impl<'a> Clean<Arguments> for (&'a [hir::Ty<'a>], &'a [Ident]) {
-    fn clean(&self, cx: &mut DocContext<'_>) -> Arguments {
-        Arguments {
-            values: self
-                .0
-                .iter()
-                .enumerate()
-                .map(|(i, ty)| {
-                    let mut name = self.1.get(i).map_or(kw::Empty, |ident| ident.name);
-                    if name.is_empty() {
-                        name = kw::Underscore;
-                    }
-                    Argument { name, type_: ty.clean(cx), is_const: false }
-                })
-                .collect(),
-        }
+fn clean_args_from_types_and_names(
+    cx: &mut DocContext<'_>,
+    types: &[hir::Ty<'_>],
+    names: &[Ident],
+) -> Arguments {
+    Arguments {
+        values: types
+            .iter()
+            .enumerate()
+            .map(|(i, ty)| {
+                let mut name = names.get(i).map_or(kw::Empty, |ident| ident.name);
+                if name.is_empty() {
+                    name = kw::Underscore;
+                }
+                Argument { name, type_: ty.clean(cx), is_const: false }
+            })
+            .collect(),
     }
 }
 
-impl<'a> Clean<Arguments> for (&'a [hir::Ty<'a>], hir::BodyId) {
-    fn clean(&self, cx: &mut DocContext<'_>) -> Arguments {
-        let body = cx.tcx.hir().body(self.1);
+fn clean_args_from_types_and_body_id(
+    cx: &mut DocContext<'_>,
+    types: &[hir::Ty<'_>],
+    body_id: hir::BodyId,
+) -> Arguments {
+    let body = cx.tcx.hir().body(body_id);
 
-        Arguments {
-            values: self
-                .0
-                .iter()
-                .enumerate()
-                .map(|(i, ty)| Argument {
-                    name: name_from_pat(body.params[i].pat),
-                    type_: ty.clean(cx),
-                    is_const: false,
-                })
-                .collect(),
-        }
+    Arguments {
+        values: types
+            .iter()
+            .enumerate()
+            .map(|(i, ty)| Argument {
+                name: name_from_pat(body.params[i].pat),
+                type_: ty.clean(cx),
+                is_const: false,
+            })
+            .collect(),
     }
 }
 
@@ -844,27 +846,28 @@ fn clean_fn_decl_with_args(
     FnDecl { inputs: args, output: decl.output.clean(cx), c_variadic: decl.c_variadic }
 }
 
-impl<'tcx> Clean<FnDecl> for (DefId, ty::PolyFnSig<'tcx>) {
-    fn clean(&self, cx: &mut DocContext<'_>) -> FnDecl {
-        let (did, sig) = *self;
-        let mut names = if did.is_local() { &[] } else { cx.tcx.fn_arg_names(did) }.iter();
-
-        FnDecl {
-            output: Return(sig.skip_binder().output().clean(cx)),
-            c_variadic: sig.skip_binder().c_variadic,
-            inputs: Arguments {
-                values: sig
-                    .skip_binder()
-                    .inputs()
-                    .iter()
-                    .map(|t| Argument {
-                        type_: t.clean(cx),
-                        name: names.next().map_or(kw::Empty, |i| i.name),
-                        is_const: false,
-                    })
-                    .collect(),
-            },
-        }
+fn clean_fn_decl_from_did_and_sig(
+    cx: &mut DocContext<'_>,
+    did: DefId,
+    sig: ty::PolyFnSig<'_>,
+) -> FnDecl {
+    let mut names = if did.is_local() { &[] } else { cx.tcx.fn_arg_names(did) }.iter();
+
+    FnDecl {
+        output: Return(sig.skip_binder().output().clean(cx)),
+        c_variadic: sig.skip_binder().c_variadic,
+        inputs: Arguments {
+            values: sig
+                .skip_binder()
+                .inputs()
+                .iter()
+                .map(|t| Argument {
+                    type_: t.clean(cx),
+                    name: names.next().map_or(kw::Empty, |i| i.name),
+                    is_const: false,
+                })
+                .collect(),
+        },
     }
 }
 
@@ -912,7 +915,7 @@ impl Clean<Item> for hir::TraitItem<'_> {
                     AssocConstItem(ty.clean(cx), default.map(|e| print_const_expr(cx.tcx, e)))
                 }
                 hir::TraitItemKind::Fn(ref sig, hir::TraitFn::Provided(body)) => {
-                    let mut m = (sig, &self.generics, body).clean(cx);
+                    let mut m = clean_function(cx, sig, &self.generics, body);
                     if m.header.constness == hir::Constness::Const
                         && is_unstable_const_fn(cx.tcx, local_did).is_some()
                     {
@@ -924,7 +927,7 @@ impl Clean<Item> for hir::TraitItem<'_> {
                     let (generics, decl) = enter_impl_trait(cx, |cx| {
                         // NOTE: generics must be cleaned before args
                         let generics = self.generics.clean(cx);
-                        let args = (sig.decl.inputs, names).clean(cx);
+                        let args = clean_args_from_types_and_names(cx, sig.decl.inputs, names);
                         let decl = clean_fn_decl_with_args(cx, sig.decl, args);
                         (generics, decl)
                     });
@@ -959,7 +962,7 @@ impl Clean<Item> for hir::ImplItem<'_> {
                     AssocConstItem(ty.clean(cx), Some(print_const_expr(cx.tcx, expr)))
                 }
                 hir::ImplItemKind::Fn(ref sig, body) => {
-                    let mut m = (sig, &self.generics, body).clean(cx);
+                    let mut m = clean_function(cx, sig, &self.generics, body);
                     if m.header.constness == hir::Constness::Const
                         && is_unstable_const_fn(cx.tcx, local_did).is_some()
                     {
@@ -1013,11 +1016,13 @@ impl Clean<Item> for ty::AssocItem {
                 AssocConstItem(ty.clean(cx), default)
             }
             ty::AssocKind::Fn => {
-                let generics =
-                    (tcx.generics_of(self.def_id), tcx.explicit_predicates_of(self.def_id))
-                        .clean(cx);
+                let generics = clean_ty_generics(
+                    cx,
+                    tcx.generics_of(self.def_id),
+                    tcx.explicit_predicates_of(self.def_id),
+                );
                 let sig = tcx.fn_sig(self.def_id);
-                let mut decl = (self.def_id, sig).clean(cx);
+                let mut decl = clean_fn_decl_from_did_and_sig(cx, self.def_id, sig);
 
                 if self.fn_has_self_parameter {
                     let self_ty = match self.container {
@@ -1086,7 +1091,7 @@ impl Clean<Item> for ty::AssocItem {
                 if let ty::TraitContainer(_) = self.container {
                     let bounds = tcx.explicit_item_bounds(self.def_id);
                     let predicates = ty::GenericPredicates { parent: None, predicates: bounds };
-                    let generics = (tcx.generics_of(self.def_id), predicates).clean(cx);
+                    let generics = clean_ty_generics(cx, tcx.generics_of(self.def_id), predicates);
                     let mut bounds = generics
                         .where_predicates
                         .iter()
@@ -1411,10 +1416,11 @@ impl<'tcx> Clean<Type> for Ty<'tcx> {
                 let ty = cx.tcx.lift(*self).expect("FnPtr lift failed");
                 let sig = ty.fn_sig(cx.tcx);
                 let def_id = DefId::local(CRATE_DEF_INDEX);
+                let decl = clean_fn_decl_from_did_and_sig(cx, def_id, sig);
                 BareFunction(box BareFunctionDecl {
                     unsafety: sig.unsafety(),
                     generic_params: Vec::new(),
-                    decl: (def_id, sig).clean(cx),
+                    decl,
                     abi: sig.abi(),
                 })
             }
@@ -1520,7 +1526,7 @@ impl<'tcx> Clean<Type> for Ty<'tcx> {
                             }
                         }
 
-                        let bounds: Vec<_> = bounds
+                        let bindings: Vec<_> = bounds
                             .iter()
                             .filter_map(|bound| {
                                 if let ty::PredicateKind::Projection(proj) =
@@ -1548,7 +1554,7 @@ impl<'tcx> Clean<Type> for Ty<'tcx> {
                             })
                             .collect();
 
-                        Some((trait_ref, &bounds[..]).clean(cx))
+                        Some(clean_poly_trait_ref_with_bindings(cx, trait_ref, &bindings))
                     })
                     .collect::<Vec<_>>();
                 bounds.extend(regions);
@@ -1720,7 +1726,7 @@ impl Clean<BareFunctionDecl> for hir::BareFnTy<'_> {
         let (generic_params, decl) = enter_impl_trait(cx, |cx| {
             // NOTE: generics must be cleaned before args
             let generic_params = self.generic_params.iter().map(|x| x.clean(cx)).collect();
-            let args = (self.decl.inputs, self.param_names).clean(cx);
+            let args = clean_args_from_types_and_names(cx, self.decl.inputs, self.param_names);
             let decl = clean_fn_decl_with_args(cx, self.decl, args);
             (generic_params, decl)
         });
@@ -1728,94 +1734,93 @@ impl Clean<BareFunctionDecl> for hir::BareFnTy<'_> {
     }
 }
 
-impl Clean<Vec<Item>> for (&hir::Item<'_>, Option<Symbol>) {
-    fn clean(&self, cx: &mut DocContext<'_>) -> Vec<Item> {
-        use hir::ItemKind;
-
-        let (item, renamed) = self;
-        let def_id = item.def_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 {
-                ItemKind::Static(ty, mutability, body_id) => {
-                    StaticItem(Static { type_: ty.clean(cx), mutability, expr: Some(body_id) })
-                }
-                ItemKind::Const(ty, body_id) => ConstantItem(Constant {
-                    type_: ty.clean(cx),
-                    kind: ConstantKind::Local { body: body_id, def_id },
-                }),
-                ItemKind::OpaqueTy(ref ty) => OpaqueTyItem(OpaqueTy {
-                    bounds: ty.bounds.iter().map(|x| x.clean(cx)).collect(),
-                    generics: ty.generics.clean(cx),
-                }),
-                ItemKind::TyAlias(hir_ty, ref generics) => {
-                    let rustdoc_ty = hir_ty.clean(cx);
-                    let ty = hir_ty_to_ty(cx.tcx, hir_ty).clean(cx);
-                    TypedefItem(
-                        Typedef {
-                            type_: rustdoc_ty,
-                            generics: generics.clean(cx),
-                            item_type: Some(ty),
-                        },
-                        false,
-                    )
-                }
-                ItemKind::Enum(ref def, ref generics) => EnumItem(Enum {
-                    variants: def.variants.iter().map(|v| v.clean(cx)).collect(),
-                    generics: generics.clean(cx),
-                    variants_stripped: false,
-                }),
-                ItemKind::TraitAlias(ref generics, bounds) => TraitAliasItem(TraitAlias {
+fn clean_maybe_renamed_item(
+    cx: &mut DocContext<'_>,
+    item: &hir::Item<'_>,
+    renamed: Option<Symbol>,
+) -> Vec<Item> {
+    use hir::ItemKind;
+
+    let def_id = item.def_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 {
+            ItemKind::Static(ty, mutability, body_id) => {
+                StaticItem(Static { type_: ty.clean(cx), mutability, expr: Some(body_id) })
+            }
+            ItemKind::Const(ty, body_id) => ConstantItem(Constant {
+                type_: ty.clean(cx),
+                kind: ConstantKind::Local { body: body_id, def_id },
+            }),
+            ItemKind::OpaqueTy(ref ty) => OpaqueTyItem(OpaqueTy {
+                bounds: ty.bounds.iter().map(|x| x.clean(cx)).collect(),
+                generics: ty.generics.clean(cx),
+            }),
+            ItemKind::TyAlias(hir_ty, ref generics) => {
+                let rustdoc_ty = hir_ty.clean(cx);
+                let ty = hir_ty_to_ty(cx.tcx, hir_ty).clean(cx);
+                TypedefItem(
+                    Typedef {
+                        type_: rustdoc_ty,
+                        generics: generics.clean(cx),
+                        item_type: Some(ty),
+                    },
+                    false,
+                )
+            }
+            ItemKind::Enum(ref def, ref generics) => EnumItem(Enum {
+                variants: def.variants.iter().map(|v| v.clean(cx)).collect(),
+                generics: generics.clean(cx),
+                variants_stripped: false,
+            }),
+            ItemKind::TraitAlias(ref generics, bounds) => TraitAliasItem(TraitAlias {
+                generics: generics.clean(cx),
+                bounds: bounds.iter().map(|x| x.clean(cx)).collect(),
+            }),
+            ItemKind::Union(ref variant_data, ref generics) => UnionItem(Union {
+                generics: generics.clean(cx),
+                fields: variant_data.fields().iter().map(|x| x.clean(cx)).collect(),
+                fields_stripped: false,
+            }),
+            ItemKind::Struct(ref variant_data, ref generics) => StructItem(Struct {
+                struct_type: CtorKind::from_hir(variant_data),
+                generics: generics.clean(cx),
+                fields: variant_data.fields().iter().map(|x| x.clean(cx)).collect(),
+                fields_stripped: false,
+            }),
+            ItemKind::Impl(ref impl_) => return clean_impl(impl_, item.hir_id(), cx),
+            // proc macros can have a name set by attributes
+            ItemKind::Fn(ref sig, ref generics, body_id) => {
+                clean_fn_or_proc_macro(item, sig, generics, body_id, &mut name, cx)
+            }
+            ItemKind::Macro(ref macro_def) => {
+                let ty_vis = cx.tcx.visibility(def_id).clean(cx);
+                MacroItem(Macro {
+                    source: display_macro_source(cx, name, macro_def, def_id, ty_vis),
+                })
+            }
+            ItemKind::Trait(is_auto, unsafety, ref generics, bounds, item_ids) => {
+                let items =
+                    item_ids.iter().map(|ti| cx.tcx.hir().trait_item(ti.id).clean(cx)).collect();
+                TraitItem(Trait {
+                    unsafety,
+                    items,
                     generics: generics.clean(cx),
                     bounds: bounds.iter().map(|x| x.clean(cx)).collect(),
-                }),
-                ItemKind::Union(ref variant_data, ref generics) => UnionItem(Union {
-                    generics: generics.clean(cx),
-                    fields: variant_data.fields().iter().map(|x| x.clean(cx)).collect(),
-                    fields_stripped: false,
-                }),
-                ItemKind::Struct(ref variant_data, ref generics) => StructItem(Struct {
-                    struct_type: CtorKind::from_hir(variant_data),
-                    generics: generics.clean(cx),
-                    fields: variant_data.fields().iter().map(|x| x.clean(cx)).collect(),
-                    fields_stripped: false,
-                }),
-                ItemKind::Impl(ref impl_) => return clean_impl(impl_, item.hir_id(), cx),
-                // proc macros can have a name set by attributes
-                ItemKind::Fn(ref sig, ref generics, body_id) => {
-                    clean_fn_or_proc_macro(item, sig, generics, body_id, &mut name, cx)
-                }
-                ItemKind::Macro(ref macro_def) => {
-                    let ty_vis = cx.tcx.visibility(def_id).clean(cx);
-                    MacroItem(Macro {
-                        source: display_macro_source(cx, name, macro_def, def_id, ty_vis),
-                    })
-                }
-                ItemKind::Trait(is_auto, unsafety, ref generics, bounds, item_ids) => {
-                    let items = item_ids
-                        .iter()
-                        .map(|ti| cx.tcx.hir().trait_item(ti.id).clean(cx))
-                        .collect();
-                    TraitItem(Trait {
-                        unsafety,
-                        items,
-                        generics: generics.clean(cx),
-                        bounds: bounds.iter().map(|x| x.clean(cx)).collect(),
-                        is_auto: is_auto.clean(cx),
-                    })
-                }
-                ItemKind::ExternCrate(orig_name) => {
-                    return clean_extern_crate(item, name, orig_name, cx);
-                }
-                ItemKind::Use(path, kind) => {
-                    return clean_use_statement(item, name, path, kind, cx);
-                }
-                _ => unreachable!("not yet converted"),
-            };
+                    is_auto: is_auto.clean(cx),
+                })
+            }
+            ItemKind::ExternCrate(orig_name) => {
+                return clean_extern_crate(item, name, orig_name, cx);
+            }
+            ItemKind::Use(path, kind) => {
+                return clean_use_statement(item, name, path, kind, cx);
+            }
+            _ => unreachable!("not yet converted"),
+        };
 
-            vec![Item::from_def_id_and_parts(def_id, Some(name), kind, cx)]
-        })
-    }
+        vec![Item::from_def_id_and_parts(def_id, Some(name), kind, cx)]
+    })
 }
 
 impl Clean<Item> for hir::Variant<'_> {
@@ -2029,50 +2034,51 @@ fn clean_use_statement(
     vec![Item::from_def_id_and_parts(import.def_id.to_def_id(), None, ImportItem(inner), cx)]
 }
 
-impl Clean<Item> for (&hir::ForeignItem<'_>, Option<Symbol>) {
-    fn clean(&self, cx: &mut DocContext<'_>) -> Item {
-        let (item, renamed) = self;
-        let def_id = item.def_id.to_def_id();
-        cx.with_param_env(def_id, |cx| {
-            let kind = match item.kind {
-                hir::ForeignItemKind::Fn(decl, names, ref generics) => {
-                    let abi = cx.tcx.hir().get_foreign_abi(item.hir_id());
-                    let (generics, decl) = enter_impl_trait(cx, |cx| {
-                        // NOTE: generics must be cleaned before args
-                        let generics = generics.clean(cx);
-                        let args = (decl.inputs, names).clean(cx);
-                        let decl = clean_fn_decl_with_args(cx, decl, args);
-                        (generics, decl)
-                    });
-                    ForeignFunctionItem(Function {
-                        decl,
-                        generics,
-                        header: hir::FnHeader {
-                            unsafety: if abi == Abi::RustIntrinsic {
-                                intrinsic_operation_unsafety(item.ident.name)
-                            } else {
-                                hir::Unsafety::Unsafe
-                            },
-                            abi,
-                            constness: hir::Constness::NotConst,
-                            asyncness: hir::IsAsync::NotAsync,
+fn clean_maybe_renamed_foreign_item(
+    cx: &mut DocContext<'_>,
+    item: &hir::ForeignItem<'_>,
+    renamed: Option<Symbol>,
+) -> Item {
+    let def_id = item.def_id.to_def_id();
+    cx.with_param_env(def_id, |cx| {
+        let kind = match item.kind {
+            hir::ForeignItemKind::Fn(decl, names, ref generics) => {
+                let abi = cx.tcx.hir().get_foreign_abi(item.hir_id());
+                let (generics, decl) = enter_impl_trait(cx, |cx| {
+                    // NOTE: generics must be cleaned before args
+                    let generics = generics.clean(cx);
+                    let args = clean_args_from_types_and_names(cx, decl.inputs, names);
+                    let decl = clean_fn_decl_with_args(cx, decl, args);
+                    (generics, decl)
+                });
+                ForeignFunctionItem(Function {
+                    decl,
+                    generics,
+                    header: hir::FnHeader {
+                        unsafety: if abi == Abi::RustIntrinsic {
+                            intrinsic_operation_unsafety(item.ident.name)
+                        } else {
+                            hir::Unsafety::Unsafe
                         },
-                    })
-                }
-                hir::ForeignItemKind::Static(ref ty, mutability) => {
-                    ForeignStaticItem(Static { type_: ty.clean(cx), mutability, expr: None })
-                }
-                hir::ForeignItemKind::Type => ForeignTypeItem,
-            };
+                        abi,
+                        constness: hir::Constness::NotConst,
+                        asyncness: hir::IsAsync::NotAsync,
+                    },
+                })
+            }
+            hir::ForeignItemKind::Static(ref ty, mutability) => {
+                ForeignStaticItem(Static { type_: ty.clean(cx), mutability, expr: None })
+            }
+            hir::ForeignItemKind::Type => ForeignTypeItem,
+        };
 
-            Item::from_hir_id_and_parts(
-                item.hir_id(),
-                Some(renamed.unwrap_or(item.ident.name)),
-                kind,
-                cx,
-            )
-        })
-    }
+        Item::from_hir_id_and_parts(
+            item.hir_id(),
+            Some(renamed.unwrap_or(item.ident.name)),
+            kind,
+            cx,
+        )
+    })
 }
 
 impl Clean<TypeBinding> for hir::TypeBinding<'_> {
diff --git a/src/librustdoc/html/templates/page.html b/src/librustdoc/html/templates/page.html
index 2a783c6da57..c07851da18a 100644
--- a/src/librustdoc/html/templates/page.html
+++ b/src/librustdoc/html/templates/page.html
@@ -7,6 +7,12 @@
     <meta name="description" content="{{page.description}}"> {#- -#}
     <meta name="keywords" content="{{page.keywords}}"> {#- -#}
     <title>{{page.title}}</title> {#- -#}
+    <link rel="preload" as="font" type="font/woff2" crossorigin href="{{static_root_path | safe}}SourceSerif4-Regular.ttf.woff2"> {#- -#}
+    <link rel="preload" as="font" type="font/woff2" crossorigin href="{{static_root_path | safe}}FiraSans-Regular.woff2"> {#- -#}
+    <link rel="preload" as="font" type="font/woff2" crossorigin href="{{static_root_path | safe}}FiraSans-Medium.woff2"> {#- -#}
+    <link rel="preload" as="font" type="font/woff2" crossorigin href="{{static_root_path | safe}}SourceCodePro-Regular.ttf.woff2"> {#- -#}
+    <link rel="preload" as="font" type="font/woff2" crossorigin href="{{static_root_path | safe}}SourceSerif4-Bold.ttf.woff2"> {#- -#}
+    <link rel="preload" as="font" type="font/woff2" crossorigin href="{{static_root_path | safe}}SourceCodePro-Semibold.ttf.woff2"> {#- -#}
     <link rel="stylesheet" type="text/css" {# -#}
           href="{{static_root_path | safe}}normalize{{page.resource_suffix}}.css"> {#- -#}
     <link rel="stylesheet" type="text/css" {# -#}
diff --git a/src/llvm-project b/src/llvm-project
-Subproject 01c8b654f9a01371414d1fd69cba38b289510a9
+Subproject 2b9078f4afae82f60c5ac0fdb4af42d269e2f2f
diff --git a/src/test/codegen/asm-may_unwind.rs b/src/test/codegen/asm-may_unwind.rs
new file mode 100644
index 00000000000..85cae8b2b1c
--- /dev/null
+++ b/src/test/codegen/asm-may_unwind.rs
@@ -0,0 +1,25 @@
+// min-llvm-version: 13.0.0
+// compile-flags: -O
+// only-x86_64
+
+#![crate_type = "rlib"]
+#![feature(asm, asm_unwind)]
+
+#[no_mangle]
+pub extern "C" fn panicky() {}
+
+struct Foo;
+
+impl Drop for Foo {
+    fn drop(&mut self) {
+        println!();
+    }
+}
+
+// CHECK-LABEL: @may_unwind
+#[no_mangle]
+pub unsafe fn may_unwind() {
+    let _m = Foo;
+    // CHECK: invoke void asm sideeffect alignstack inteldialect unwind ""
+    asm!("", options(may_unwind));
+}
diff --git a/src/test/codegen/auxiliary/thread_local_aux.rs b/src/test/codegen/auxiliary/thread_local_aux.rs
index 29b5e3ca244..bebaa7754dd 100644
--- a/src/test/codegen/auxiliary/thread_local_aux.rs
+++ b/src/test/codegen/auxiliary/thread_local_aux.rs
@@ -1,5 +1,4 @@
 #![crate_type = "lib"]
-#![feature(thread_local_const_init)]
 
 use std::cell::Cell;
 
diff --git a/src/test/codegen/thread-local.rs b/src/test/codegen/thread-local.rs
index f14368e3990..5ac30d949fa 100644
--- a/src/test/codegen/thread-local.rs
+++ b/src/test/codegen/thread-local.rs
@@ -6,7 +6,6 @@
 // ignore-android does not use #[thread_local]
 
 #![crate_type = "lib"]
-#![feature(thread_local_const_init)]
 
 extern crate thread_local_aux as aux;
 
diff --git a/src/test/mir-opt/early_otherwise_branch_noopt.rs b/src/test/mir-opt/early_otherwise_branch_noopt.rs
index aa9ddf485b5..d04e2a0429d 100644
--- a/src/test/mir-opt/early_otherwise_branch_noopt.rs
+++ b/src/test/mir-opt/early_otherwise_branch_noopt.rs
@@ -1,4 +1,4 @@
-// compile-flags: -Z mir-opt-level=4
+// compile-flags: -Z mir-opt-level=4 -Zunsound-mir-opts
 
 // must not optimize as it does not follow the pattern of
 // left and right hand side being the same variant
diff --git a/src/test/rustdoc/mixing-doc-comments-and-attrs.S1_top-doc.html b/src/test/rustdoc/mixing-doc-comments-and-attrs.S1_top-doc.html
new file mode 100644
index 00000000000..69d647a92e8
--- /dev/null
+++ b/src/test/rustdoc/mixing-doc-comments-and-attrs.S1_top-doc.html
@@ -0,0 +1,4 @@
+<div class="docblock"><p>Hello world!
+Goodbye!
+Hello again!</p>
+</div>
\ No newline at end of file
diff --git a/src/test/rustdoc/mixing-doc-comments-and-attrs.S2_top-doc.html b/src/test/rustdoc/mixing-doc-comments-and-attrs.S2_top-doc.html
new file mode 100644
index 00000000000..8ff114b993e
--- /dev/null
+++ b/src/test/rustdoc/mixing-doc-comments-and-attrs.S2_top-doc.html
@@ -0,0 +1,4 @@
+<div class="docblock"><p>Hello world!</p>
+<p>Goodbye!
+Hello again!</p>
+</div>
\ No newline at end of file
diff --git a/src/test/rustdoc/mixing-doc-comments-and-attrs.rs b/src/test/rustdoc/mixing-doc-comments-and-attrs.rs
index c26d3a31987..1aedd4d107c 100644
--- a/src/test/rustdoc/mixing-doc-comments-and-attrs.rs
+++ b/src/test/rustdoc/mixing-doc-comments-and-attrs.rs
@@ -1,10 +1,7 @@
 #![crate_name = "foo"]
 
 // @has 'foo/struct.S1.html'
-// @count - '//details[@class="rustdoc-toggle top-doc"]/div[@class="docblock"]/p' \
-//     1
-// @has - '//details[@class="rustdoc-toggle top-doc"]/div[@class="docblock"]/p[1]' \
-//     'Hello world! Goodbye! Hello again!'
+// @snapshot S1_top-doc - '//details[@class="rustdoc-toggle top-doc"]/div[@class="docblock"]'
 
 #[doc = "Hello world!\n\n"]
 /// Goodbye!
@@ -12,12 +9,7 @@
 pub struct S1;
 
 // @has 'foo/struct.S2.html'
-// @count - '//details[@class="rustdoc-toggle top-doc"]/div[@class="docblock"]/p' \
-//     2
-// @has - '//details[@class="rustdoc-toggle top-doc"]/div[@class="docblock"]/p[1]' \
-//     'Hello world!'
-// @has - '//details[@class="rustdoc-toggle top-doc"]/div[@class="docblock"]/p[2]' \
-//     'Goodbye! Hello again!'
+// @snapshot S2_top-doc - '//details[@class="rustdoc-toggle top-doc"]/div[@class="docblock"]'
 
 /// Hello world!
 ///
diff --git a/src/test/ui/asm/aarch64/bad-options.stderr b/src/test/ui/asm/aarch64/bad-options.stderr
index 21bcc4a9c7b..867e0433eae 100644
--- a/src/test/ui/asm/aarch64/bad-options.stderr
+++ b/src/test/ui/asm/aarch64/bad-options.stderr
@@ -36,41 +36,41 @@ LL |         asm!("{}", out(reg) foo, clobber_abi("C"));
    |                    |
    |                    generic outputs
 
-error: expected one of `)`, `att_syntax`, or `raw`, found `nomem`
+error: expected one of `)`, `att_syntax`, `may_unwind`, or `raw`, found `nomem`
   --> $DIR/bad-options.rs:28:25
    |
 LL | global_asm!("", options(nomem));
-   |                         ^^^^^ expected one of `)`, `att_syntax`, or `raw`
+   |                         ^^^^^ expected one of `)`, `att_syntax`, `may_unwind`, or `raw`
 
-error: expected one of `)`, `att_syntax`, or `raw`, found `readonly`
+error: expected one of `)`, `att_syntax`, `may_unwind`, or `raw`, found `readonly`
   --> $DIR/bad-options.rs:30:25
    |
 LL | global_asm!("", options(readonly));
-   |                         ^^^^^^^^ expected one of `)`, `att_syntax`, or `raw`
+   |                         ^^^^^^^^ expected one of `)`, `att_syntax`, `may_unwind`, or `raw`
 
-error: expected one of `)`, `att_syntax`, or `raw`, found `noreturn`
+error: expected one of `)`, `att_syntax`, `may_unwind`, or `raw`, found `noreturn`
   --> $DIR/bad-options.rs:32:25
    |
 LL | global_asm!("", options(noreturn));
-   |                         ^^^^^^^^ expected one of `)`, `att_syntax`, or `raw`
+   |                         ^^^^^^^^ expected one of `)`, `att_syntax`, `may_unwind`, or `raw`
 
-error: expected one of `)`, `att_syntax`, or `raw`, found `pure`
+error: expected one of `)`, `att_syntax`, `may_unwind`, or `raw`, found `pure`
   --> $DIR/bad-options.rs:34:25
    |
 LL | global_asm!("", options(pure));
-   |                         ^^^^ expected one of `)`, `att_syntax`, or `raw`
+   |                         ^^^^ expected one of `)`, `att_syntax`, `may_unwind`, or `raw`
 
-error: expected one of `)`, `att_syntax`, or `raw`, found `nostack`
+error: expected one of `)`, `att_syntax`, `may_unwind`, or `raw`, found `nostack`
   --> $DIR/bad-options.rs:36:25
    |
 LL | global_asm!("", options(nostack));
-   |                         ^^^^^^^ expected one of `)`, `att_syntax`, or `raw`
+   |                         ^^^^^^^ expected one of `)`, `att_syntax`, `may_unwind`, or `raw`
 
-error: expected one of `)`, `att_syntax`, or `raw`, found `preserves_flags`
+error: expected one of `)`, `att_syntax`, `may_unwind`, or `raw`, found `preserves_flags`
   --> $DIR/bad-options.rs:38:25
    |
 LL | global_asm!("", options(preserves_flags));
-   |                         ^^^^^^^^^^^^^^^ expected one of `)`, `att_syntax`, or `raw`
+   |                         ^^^^^^^^^^^^^^^ expected one of `)`, `att_syntax`, `may_unwind`, or `raw`
 
 error: invalid ABI for `clobber_abi`
   --> $DIR/bad-options.rs:20:18
diff --git a/src/test/ui/asm/aarch64/may_unwind.rs b/src/test/ui/asm/aarch64/may_unwind.rs
new file mode 100644
index 00000000000..94cc7d75049
--- /dev/null
+++ b/src/test/ui/asm/aarch64/may_unwind.rs
@@ -0,0 +1,37 @@
+// min-llvm-version: 13.0.0
+// only-aarch64
+// run-pass
+// needs-asm-support
+
+#![feature(asm, asm_sym, asm_unwind)]
+
+use std::panic::{catch_unwind, resume_unwind, AssertUnwindSafe};
+
+struct Foo<'a>(&'a mut bool);
+
+impl Drop for Foo<'_> {
+    fn drop(&mut self) {
+        *self.0 = false;
+    }
+}
+
+extern "C" fn panicky() {
+    resume_unwind(Box::new(()));
+}
+
+fn main() {
+    let flag = &mut true;
+    catch_unwind(AssertUnwindSafe(|| {
+        let _foo = Foo(flag);
+        unsafe {
+            asm!(
+                "bl {}",
+                sym panicky,
+                clobber_abi("C"),
+                options(may_unwind)
+            );
+        }
+    }))
+    .expect_err("expected a panic");
+    assert_eq!(*flag, false);
+}
diff --git a/src/test/ui/asm/aarch64/parse-error.stderr b/src/test/ui/asm/aarch64/parse-error.stderr
index 3d88cef5c7d..a143c3b2b28 100644
--- a/src/test/ui/asm/aarch64/parse-error.stderr
+++ b/src/test/ui/asm/aarch64/parse-error.stderr
@@ -64,11 +64,11 @@ error: argument to `sym` must be a path expression
 LL |         asm!("{}", sym foo + bar);
    |                        ^^^^^^^^^
 
-error: expected one of `)`, `att_syntax`, `nomem`, `noreturn`, `nostack`, `preserves_flags`, `pure`, `raw`, or `readonly`, found `foo`
+error: expected one of `)`, `att_syntax`, `may_unwind`, `nomem`, `noreturn`, `nostack`, `preserves_flags`, `pure`, `raw`, or `readonly`, found `foo`
   --> $DIR/parse-error.rs:31:26
    |
 LL |         asm!("", options(foo));
-   |                          ^^^ expected one of 9 possible tokens
+   |                          ^^^ expected one of 10 possible tokens
 
 error: expected one of `)` or `,`, found `foo`
   --> $DIR/parse-error.rs:33:32
@@ -76,11 +76,11 @@ error: expected one of `)` or `,`, found `foo`
 LL |         asm!("", options(nomem foo));
    |                                ^^^ expected one of `)` or `,`
 
-error: expected one of `)`, `att_syntax`, `nomem`, `noreturn`, `nostack`, `preserves_flags`, `pure`, `raw`, or `readonly`, found `foo`
+error: expected one of `)`, `att_syntax`, `may_unwind`, `nomem`, `noreturn`, `nostack`, `preserves_flags`, `pure`, `raw`, or `readonly`, found `foo`
   --> $DIR/parse-error.rs:35:33
    |
 LL |         asm!("", options(nomem, foo));
-   |                                 ^^^ expected one of 9 possible tokens
+   |                                 ^^^ expected one of 10 possible tokens
 
 error: arguments are not allowed after options
   --> $DIR/parse-error.rs:37:31
@@ -260,23 +260,23 @@ error: expected one of `,`, `.`, `?`, or an operator, found `FOO`
 LL | global_asm!("{}", const(reg) FOO);
    |                              ^^^ expected one of `,`, `.`, `?`, or an operator
 
-error: expected one of `)`, `att_syntax`, or `raw`, found `FOO`
+error: expected one of `)`, `att_syntax`, `may_unwind`, or `raw`, found `FOO`
   --> $DIR/parse-error.rs:100:25
    |
 LL | global_asm!("", options(FOO));
-   |                         ^^^ expected one of `)`, `att_syntax`, or `raw`
+   |                         ^^^ expected one of `)`, `att_syntax`, `may_unwind`, or `raw`
 
-error: expected one of `)`, `att_syntax`, or `raw`, found `nomem`
+error: expected one of `)`, `att_syntax`, `may_unwind`, or `raw`, found `nomem`
   --> $DIR/parse-error.rs:102:25
    |
 LL | global_asm!("", options(nomem FOO));
-   |                         ^^^^^ expected one of `)`, `att_syntax`, or `raw`
+   |                         ^^^^^ expected one of `)`, `att_syntax`, `may_unwind`, or `raw`
 
-error: expected one of `)`, `att_syntax`, or `raw`, found `nomem`
+error: expected one of `)`, `att_syntax`, `may_unwind`, or `raw`, found `nomem`
   --> $DIR/parse-error.rs:104:25
    |
 LL | global_asm!("", options(nomem, FOO));
-   |                         ^^^^^ expected one of `)`, `att_syntax`, or `raw`
+   |                         ^^^^^ expected one of `)`, `att_syntax`, `may_unwind`, or `raw`
 
 error: arguments are not allowed after options
   --> $DIR/parse-error.rs:106:30
diff --git a/src/test/ui/asm/may_unwind.rs b/src/test/ui/asm/may_unwind.rs
new file mode 100644
index 00000000000..436e8b9d95a
--- /dev/null
+++ b/src/test/ui/asm/may_unwind.rs
@@ -0,0 +1,9 @@
+// min-llvm-version: 13.0.0
+// run-pass
+// needs-asm-support
+
+#![feature(asm, asm_unwind)]
+
+fn main() {
+    unsafe { asm!("", options(may_unwind)) };
+}
diff --git a/src/test/ui/asm/x86_64/bad-options.stderr b/src/test/ui/asm/x86_64/bad-options.stderr
index e2351840eef..a63c42aac27 100644
--- a/src/test/ui/asm/x86_64/bad-options.stderr
+++ b/src/test/ui/asm/x86_64/bad-options.stderr
@@ -45,41 +45,41 @@ LL |         asm!("{}", out(reg) foo, clobber_abi("C"), clobber_abi("C"));
    |                    |             clobber_abi
    |                    generic outputs
 
-error: expected one of `)`, `att_syntax`, or `raw`, found `nomem`
+error: expected one of `)`, `att_syntax`, `may_unwind`, or `raw`, found `nomem`
   --> $DIR/bad-options.rs:31:25
    |
 LL | global_asm!("", options(nomem));
-   |                         ^^^^^ expected one of `)`, `att_syntax`, or `raw`
+   |                         ^^^^^ expected one of `)`, `att_syntax`, `may_unwind`, or `raw`
 
-error: expected one of `)`, `att_syntax`, or `raw`, found `readonly`
+error: expected one of `)`, `att_syntax`, `may_unwind`, or `raw`, found `readonly`
   --> $DIR/bad-options.rs:33:25
    |
 LL | global_asm!("", options(readonly));
-   |                         ^^^^^^^^ expected one of `)`, `att_syntax`, or `raw`
+   |                         ^^^^^^^^ expected one of `)`, `att_syntax`, `may_unwind`, or `raw`
 
-error: expected one of `)`, `att_syntax`, or `raw`, found `noreturn`
+error: expected one of `)`, `att_syntax`, `may_unwind`, or `raw`, found `noreturn`
   --> $DIR/bad-options.rs:35:25
    |
 LL | global_asm!("", options(noreturn));
-   |                         ^^^^^^^^ expected one of `)`, `att_syntax`, or `raw`
+   |                         ^^^^^^^^ expected one of `)`, `att_syntax`, `may_unwind`, or `raw`
 
-error: expected one of `)`, `att_syntax`, or `raw`, found `pure`
+error: expected one of `)`, `att_syntax`, `may_unwind`, or `raw`, found `pure`
   --> $DIR/bad-options.rs:37:25
    |
 LL | global_asm!("", options(pure));
-   |                         ^^^^ expected one of `)`, `att_syntax`, or `raw`
+   |                         ^^^^ expected one of `)`, `att_syntax`, `may_unwind`, or `raw`
 
-error: expected one of `)`, `att_syntax`, or `raw`, found `nostack`
+error: expected one of `)`, `att_syntax`, `may_unwind`, or `raw`, found `nostack`
   --> $DIR/bad-options.rs:39:25
    |
 LL | global_asm!("", options(nostack));
-   |                         ^^^^^^^ expected one of `)`, `att_syntax`, or `raw`
+   |                         ^^^^^^^ expected one of `)`, `att_syntax`, `may_unwind`, or `raw`
 
-error: expected one of `)`, `att_syntax`, or `raw`, found `preserves_flags`
+error: expected one of `)`, `att_syntax`, `may_unwind`, or `raw`, found `preserves_flags`
   --> $DIR/bad-options.rs:41:25
    |
 LL | global_asm!("", options(preserves_flags));
-   |                         ^^^^^^^^^^^^^^^ expected one of `)`, `att_syntax`, or `raw`
+   |                         ^^^^^^^^^^^^^^^ expected one of `)`, `att_syntax`, `may_unwind`, or `raw`
 
 error: invalid ABI for `clobber_abi`
   --> $DIR/bad-options.rs:20:18
diff --git a/src/test/ui/asm/x86_64/may_unwind.rs b/src/test/ui/asm/x86_64/may_unwind.rs
new file mode 100644
index 00000000000..5ac4dd9b956
--- /dev/null
+++ b/src/test/ui/asm/x86_64/may_unwind.rs
@@ -0,0 +1,37 @@
+// min-llvm-version: 13.0.0
+// only-x86_64
+// run-pass
+// needs-asm-support
+
+#![feature(asm, asm_sym, asm_unwind)]
+
+use std::panic::{catch_unwind, resume_unwind, AssertUnwindSafe};
+
+struct Foo<'a>(&'a mut bool);
+
+impl Drop for Foo<'_> {
+    fn drop(&mut self) {
+        *self.0 = false;
+    }
+}
+
+extern "C" fn panicky() {
+    resume_unwind(Box::new(()));
+}
+
+fn main() {
+    let flag = &mut true;
+    catch_unwind(AssertUnwindSafe(|| {
+        let _foo = Foo(flag);
+        unsafe {
+            asm!(
+                "call {}",
+                sym panicky,
+                clobber_abi("C"),
+                options(may_unwind)
+            );
+        }
+    }))
+    .expect_err("expected a panic");
+    assert_eq!(*flag, false);
+}
diff --git a/src/test/ui/asm/x86_64/parse-error.stderr b/src/test/ui/asm/x86_64/parse-error.stderr
index 018df9826c6..4f16c15af38 100644
--- a/src/test/ui/asm/x86_64/parse-error.stderr
+++ b/src/test/ui/asm/x86_64/parse-error.stderr
@@ -64,11 +64,11 @@ error: argument to `sym` must be a path expression
 LL |         asm!("{}", sym foo + bar);
    |                        ^^^^^^^^^
 
-error: expected one of `)`, `att_syntax`, `nomem`, `noreturn`, `nostack`, `preserves_flags`, `pure`, `raw`, or `readonly`, found `foo`
+error: expected one of `)`, `att_syntax`, `may_unwind`, `nomem`, `noreturn`, `nostack`, `preserves_flags`, `pure`, `raw`, or `readonly`, found `foo`
   --> $DIR/parse-error.rs:31:26
    |
 LL |         asm!("", options(foo));
-   |                          ^^^ expected one of 9 possible tokens
+   |                          ^^^ expected one of 10 possible tokens
 
 error: expected one of `)` or `,`, found `foo`
   --> $DIR/parse-error.rs:33:32
@@ -76,11 +76,11 @@ error: expected one of `)` or `,`, found `foo`
 LL |         asm!("", options(nomem foo));
    |                                ^^^ expected one of `)` or `,`
 
-error: expected one of `)`, `att_syntax`, `nomem`, `noreturn`, `nostack`, `preserves_flags`, `pure`, `raw`, or `readonly`, found `foo`
+error: expected one of `)`, `att_syntax`, `may_unwind`, `nomem`, `noreturn`, `nostack`, `preserves_flags`, `pure`, `raw`, or `readonly`, found `foo`
   --> $DIR/parse-error.rs:35:33
    |
 LL |         asm!("", options(nomem, foo));
-   |                                 ^^^ expected one of 9 possible tokens
+   |                                 ^^^ expected one of 10 possible tokens
 
 error: arguments are not allowed after options
   --> $DIR/parse-error.rs:37:31
@@ -266,23 +266,23 @@ error: expected one of `,`, `.`, `?`, or an operator, found `FOO`
 LL | global_asm!("{}", const(reg) FOO);
    |                              ^^^ expected one of `,`, `.`, `?`, or an operator
 
-error: expected one of `)`, `att_syntax`, or `raw`, found `FOO`
+error: expected one of `)`, `att_syntax`, `may_unwind`, or `raw`, found `FOO`
   --> $DIR/parse-error.rs:102:25
    |
 LL | global_asm!("", options(FOO));
-   |                         ^^^ expected one of `)`, `att_syntax`, or `raw`
+   |                         ^^^ expected one of `)`, `att_syntax`, `may_unwind`, or `raw`
 
-error: expected one of `)`, `att_syntax`, or `raw`, found `nomem`
+error: expected one of `)`, `att_syntax`, `may_unwind`, or `raw`, found `nomem`
   --> $DIR/parse-error.rs:104:25
    |
 LL | global_asm!("", options(nomem FOO));
-   |                         ^^^^^ expected one of `)`, `att_syntax`, or `raw`
+   |                         ^^^^^ expected one of `)`, `att_syntax`, `may_unwind`, or `raw`
 
-error: expected one of `)`, `att_syntax`, or `raw`, found `nomem`
+error: expected one of `)`, `att_syntax`, `may_unwind`, or `raw`, found `nomem`
   --> $DIR/parse-error.rs:106:25
    |
 LL | global_asm!("", options(nomem, FOO));
-   |                         ^^^^^ expected one of `)`, `att_syntax`, or `raw`
+   |                         ^^^^^ expected one of `)`, `att_syntax`, `may_unwind`, or `raw`
 
 error: arguments are not allowed after options
   --> $DIR/parse-error.rs:108:30
diff --git a/src/test/ui/async-await/async-error-span.stderr b/src/test/ui/async-await/async-error-span.stderr
index 994bfd33ba4..2e3f8bb5256 100644
--- a/src/test/ui/async-await/async-error-span.stderr
+++ b/src/test/ui/async-await/async-error-span.stderr
@@ -5,6 +5,7 @@ LL | fn get_future() -> impl Future<Output = ()> {
    |                    ^^^^^^^^^^^^^^^^^^^^^^^^ `()` is not a future
    |
    = help: the trait `Future` is not implemented for `()`
+   = note: () must be a future or must implement `IntoFuture` to be awaited
 
 error[E0698]: type inside `async fn` body must be known in this context
   --> $DIR/async-error-span.rs:13:9
diff --git a/src/test/ui/async-await/async-fn-size-moved-locals.rs b/src/test/ui/async-await/async-fn-size-moved-locals.rs
index 636fafc2bc4..a603ebd6e85 100644
--- a/src/test/ui/async-await/async-fn-size-moved-locals.rs
+++ b/src/test/ui/async-await/async-fn-size-moved-locals.rs
@@ -112,7 +112,7 @@ async fn mixed_sizes() {
 fn main() {
     assert_eq!(1025, std::mem::size_of_val(&single()));
     assert_eq!(1026, std::mem::size_of_val(&single_with_noop()));
-    assert_eq!(3078, std::mem::size_of_val(&joined()));
-    assert_eq!(3079, std::mem::size_of_val(&joined_with_noop()));
-    assert_eq!(7181, std::mem::size_of_val(&mixed_sizes()));
+    assert_eq!(3076, std::mem::size_of_val(&joined()));
+    assert_eq!(3076, std::mem::size_of_val(&joined_with_noop()));
+    assert_eq!(6157, std::mem::size_of_val(&mixed_sizes()));
 }
diff --git a/src/test/ui/async-await/await-into-future.rs b/src/test/ui/async-await/await-into-future.rs
new file mode 100644
index 00000000000..b74b1684440
--- /dev/null
+++ b/src/test/ui/async-await/await-into-future.rs
@@ -0,0 +1,30 @@
+// run-pass
+// aux-build: issue-72470-lib.rs
+// edition:2021
+#![feature(into_future)]
+
+extern crate issue_72470_lib;
+use std::{future::{Future, IntoFuture}, pin::Pin};
+
+struct AwaitMe;
+
+impl IntoFuture for AwaitMe {
+    type Output = i32;
+    type Future = Pin<Box<dyn Future<Output = i32>>>;
+
+    fn into_future(self) -> Self::Future {
+        Box::pin(me())
+    }
+}
+
+async fn me() -> i32 {
+    41
+}
+
+async fn run() {
+    assert_eq!(AwaitMe.await, 41);
+}
+
+fn main() {
+    issue_72470_lib::run(run());
+}
diff --git a/src/test/ui/async-await/issue-70594.stderr b/src/test/ui/async-await/issue-70594.stderr
index eb24040404b..ab05251526b 100644
--- a/src/test/ui/async-await/issue-70594.stderr
+++ b/src/test/ui/async-await/issue-70594.stderr
@@ -25,6 +25,8 @@ LL |     [1; ().await];
    |         ^^^^^^^^ `()` is not a future
    |
    = help: the trait `Future` is not implemented for `()`
+   = note: () must be a future or must implement `IntoFuture` to be awaited
+   = note: required because of the requirements on the impl of `IntoFuture` for `()`
 
 error: aborting due to 4 previous errors
 
diff --git a/src/test/ui/async-await/issues/issue-62009-1.stderr b/src/test/ui/async-await/issues/issue-62009-1.stderr
index e2ea72a1e61..19d6f9bc438 100644
--- a/src/test/ui/async-await/issues/issue-62009-1.stderr
+++ b/src/test/ui/async-await/issues/issue-62009-1.stderr
@@ -34,6 +34,8 @@ LL |     (|_| 2333).await;
    |     ^^^^^^^^^^^^^^^^ `[closure@$DIR/issue-62009-1.rs:12:5: 12:15]` is not a future
    |
    = help: the trait `Future` is not implemented for `[closure@$DIR/issue-62009-1.rs:12:5: 12:15]`
+   = note: [closure@$DIR/issue-62009-1.rs:12:5: 12:15] must be a future or must implement `IntoFuture` to be awaited
+   = note: required because of the requirements on the impl of `IntoFuture` for `[closure@$DIR/issue-62009-1.rs:12:5: 12:15]`
 
 error: aborting due to 4 previous errors
 
diff --git a/src/test/ui/async-await/unresolved_type_param.rs b/src/test/ui/async-await/unresolved_type_param.rs
index d313691b388..85d868c2703 100644
--- a/src/test/ui/async-await/unresolved_type_param.rs
+++ b/src/test/ui/async-await/unresolved_type_param.rs
@@ -10,12 +10,20 @@ async fn foo() {
     //~^ ERROR type inside `async fn` body must be known in this context
     //~| ERROR type inside `async fn` body must be known in this context
     //~| ERROR type inside `async fn` body must be known in this context
+    //~| ERROR type inside `async fn` body must be known in this context
+    //~| ERROR type inside `async fn` body must be known in this context
+    //~| NOTE cannot infer type for type parameter `T`
+    //~| NOTE cannot infer type for type parameter `T`
     //~| NOTE cannot infer type for type parameter `T`
     //~| NOTE cannot infer type for type parameter `T`
     //~| NOTE cannot infer type for type parameter `T`
     //~| NOTE the type is part of the `async fn` body because of this `await`
     //~| NOTE the type is part of the `async fn` body because of this `await`
     //~| NOTE the type is part of the `async fn` body because of this `await`
+    //~| NOTE the type is part of the `async fn` body because of this `await`
+    //~| NOTE the type is part of the `async fn` body because of this `await`
+    //~| NOTE in this expansion of desugaring of `await`
+    //~| NOTE in this expansion of desugaring of `await`
     //~| NOTE in this expansion of desugaring of `await`
     //~| NOTE in this expansion of desugaring of `await`
     //~| NOTE in this expansion of desugaring of `await`
diff --git a/src/test/ui/async-await/unresolved_type_param.stderr b/src/test/ui/async-await/unresolved_type_param.stderr
index 6b9e960ca1a..130667a49c5 100644
--- a/src/test/ui/async-await/unresolved_type_param.stderr
+++ b/src/test/ui/async-await/unresolved_type_param.stderr
@@ -34,6 +34,30 @@ note: the type is part of the `async fn` body because of this `await`
 LL |     bar().await;
    |     ^^^^^^^^^^^
 
-error: aborting due to 3 previous errors
+error[E0698]: type inside `async fn` body must be known in this context
+  --> $DIR/unresolved_type_param.rs:9:5
+   |
+LL |     bar().await;
+   |     ^^^ cannot infer type for type parameter `T` declared on the function `bar`
+   |
+note: the type is part of the `async fn` body because of this `await`
+  --> $DIR/unresolved_type_param.rs:9:5
+   |
+LL |     bar().await;
+   |     ^^^^^^^^^^^
+
+error[E0698]: type inside `async fn` body must be known in this context
+  --> $DIR/unresolved_type_param.rs:9:5
+   |
+LL |     bar().await;
+   |     ^^^ cannot infer type for type parameter `T` declared on the function `bar`
+   |
+note: the type is part of the `async fn` body because of this `await`
+  --> $DIR/unresolved_type_param.rs:9:5
+   |
+LL |     bar().await;
+   |     ^^^^^^^^^^^
+
+error: aborting due to 5 previous errors
 
 For more information about this error, try `rustc --explain E0698`.
diff --git a/src/test/ui/const-generics/generic_const_exprs/const_eval_resolve_canonical.rs b/src/test/ui/const-generics/generic_const_exprs/const_eval_resolve_canonical.rs
index b79bc262d2b..18f33acaabb 100644
--- a/src/test/ui/const-generics/generic_const_exprs/const_eval_resolve_canonical.rs
+++ b/src/test/ui/const-generics/generic_const_exprs/const_eval_resolve_canonical.rs
@@ -1,4 +1,3 @@
-// run-pass
 #![feature(generic_const_exprs)]
 #![allow(incomplete_features)]
 
@@ -22,8 +21,11 @@ where
 }
 
 fn main() {
-    // Test that we can correctly infer `T` which requires evaluating
-    // `{ N + 1 }` which has substs containing an inference var
+    // FIXME(generic_const_exprs): We can't correctly infer `T` which requires
+    // evaluating `{ N + 1 }` which has substs containing an inference var
     let mut _q = Default::default();
+    //~^ ERROR type annotations needed
+
     _q = foo::<_, 2>(_q);
+    //~^ ERROR type annotations needed
 }
diff --git a/src/test/ui/const-generics/generic_const_exprs/const_eval_resolve_canonical.stderr b/src/test/ui/const-generics/generic_const_exprs/const_eval_resolve_canonical.stderr
new file mode 100644
index 00000000000..e59f1ac8027
--- /dev/null
+++ b/src/test/ui/const-generics/generic_const_exprs/const_eval_resolve_canonical.stderr
@@ -0,0 +1,33 @@
+error[E0282]: type annotations needed
+  --> $DIR/const_eval_resolve_canonical.rs:26:9
+   |
+LL |     let mut _q = Default::default();
+   |         ^^^^^^ consider giving `_q` a type
+
+error[E0283]: type annotations needed
+  --> $DIR/const_eval_resolve_canonical.rs:29:10
+   |
+LL |     _q = foo::<_, 2>(_q);
+   |          ^^^^^^^^^^^ cannot infer type
+   |
+note: multiple `impl`s satisfying `(): Foo<{ N + 1 }>` found
+  --> $DIR/const_eval_resolve_canonical.rs:8:1
+   |
+LL | impl Foo<0> for () {
+   | ^^^^^^^^^^^^^^^^^^
+...
+LL | impl Foo<3> for () {
+   | ^^^^^^^^^^^^^^^^^^
+note: required by a bound in `foo`
+  --> $DIR/const_eval_resolve_canonical.rs:18:9
+   |
+LL | fn foo<T, const N: usize>(_: T) -> <() as Foo<{ N + 1 }>>::Assoc
+   |    --- required by a bound in this
+LL | where
+LL |     (): Foo<{ N + 1 }>,
+   |         ^^^^^^^^^^^^^^ required by this bound in `foo`
+
+error: aborting due to 2 previous errors
+
+Some errors have detailed explanations: E0282, E0283.
+For more information about an error, try `rustc --explain E0282`.
diff --git a/src/test/ui/const-generics/issues/issue-83249.rs b/src/test/ui/const-generics/issues/issue-83249.rs
new file mode 100644
index 00000000000..65148c55ee5
--- /dev/null
+++ b/src/test/ui/const-generics/issues/issue-83249.rs
@@ -0,0 +1,23 @@
+#![allow(incomplete_features)]
+#![feature(generic_const_exprs)]
+
+trait Foo {
+    const N: usize;
+}
+
+impl Foo for u8 {
+    const N: usize = 1;
+}
+
+fn foo<T: Foo>(_: [u8; T::N]) -> T {
+    todo!()
+}
+
+pub fn bar() {
+    let _: u8 = foo([0; 1]);
+
+    let _ = foo([0; 1]);
+    //~^ ERROR type annotations needed
+}
+
+fn main() {}
diff --git a/src/test/ui/const-generics/issues/issue-83249.stderr b/src/test/ui/const-generics/issues/issue-83249.stderr
new file mode 100644
index 00000000000..402b3aa2d61
--- /dev/null
+++ b/src/test/ui/const-generics/issues/issue-83249.stderr
@@ -0,0 +1,11 @@
+error[E0282]: type annotations needed
+  --> $DIR/issue-83249.rs:19:13
+   |
+LL |     let _ = foo([0; 1]);
+   |         -   ^^^ cannot infer type for type parameter `T` declared on the function `foo`
+   |         |
+   |         consider giving this pattern a type
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0282`.
diff --git a/src/test/ui/const-generics/issues/issue-83288.rs b/src/test/ui/const-generics/issues/issue-83288.rs
new file mode 100644
index 00000000000..a24596d242e
--- /dev/null
+++ b/src/test/ui/const-generics/issues/issue-83288.rs
@@ -0,0 +1,69 @@
+// build-pass
+
+#![allow(incomplete_features)]
+#![feature(generic_const_exprs)]
+
+use std::{marker::PhantomData, ops::Mul};
+
+pub enum Nil {}
+pub struct Cons<T, L> {
+    _phantom: PhantomData<(T, L)>,
+}
+
+pub trait Indices<const N: usize> {
+    const RANK: usize;
+    const NUM_ELEMS: usize;
+}
+
+impl<const N: usize> Indices<N> for Nil {
+    const RANK: usize = 0;
+    const NUM_ELEMS: usize = 1;
+}
+
+impl<T, I: Indices<N>, const N: usize> Indices<N> for Cons<T, I> {
+    const RANK: usize = I::RANK + 1;
+    const NUM_ELEMS: usize = I::NUM_ELEMS * N;
+}
+
+pub trait Concat<J> {
+    type Output;
+}
+
+impl<J> Concat<J> for Nil {
+    type Output = J;
+}
+
+impl<T, I, J> Concat<J> for Cons<T, I>
+where
+    I: Concat<J>,
+{
+    type Output = Cons<T, <I as Concat<J>>::Output>;
+}
+
+pub struct Tensor<I: Indices<N>, const N: usize>
+where
+    [u8; I::NUM_ELEMS]: Sized,
+{
+    pub data: [u8; I::NUM_ELEMS],
+    _phantom: PhantomData<I>,
+}
+
+impl<I: Indices<N>, J: Indices<N>, const N: usize> Mul<Tensor<J, N>> for Tensor<I, N>
+where
+    I: Concat<J>,
+    <I as Concat<J>>::Output: Indices<N>,
+    [u8; I::NUM_ELEMS]: Sized,
+    [u8; J::NUM_ELEMS]: Sized,
+    [u8; <I as Concat<J>>::Output::NUM_ELEMS]: Sized,
+{
+    type Output = Tensor<<I as Concat<J>>::Output, N>;
+
+    fn mul(self, _rhs: Tensor<J, N>) -> Self::Output {
+        Tensor {
+            data: [0u8; <I as Concat<J>>::Output::NUM_ELEMS],
+            _phantom: PhantomData,
+        }
+    }
+}
+
+fn main() {}
diff --git a/src/test/ui/const-generics/issues/issue-87470.rs b/src/test/ui/const-generics/issues/issue-87470.rs
new file mode 100644
index 00000000000..d60181a418a
--- /dev/null
+++ b/src/test/ui/const-generics/issues/issue-87470.rs
@@ -0,0 +1,24 @@
+// build-pass
+
+#![feature(generic_const_exprs)]
+#![allow(incomplete_features)]
+
+pub trait TraitWithConst {
+    const SOME_CONST: usize;
+}
+
+pub trait OtherTrait: TraitWithConst {
+    fn some_fn(self) -> [u8 ; <Self as TraitWithConst>::SOME_CONST];
+}
+
+impl TraitWithConst for f32 {
+    const SOME_CONST: usize = 32;
+}
+
+impl OtherTrait for f32 {
+    fn some_fn(self) -> [u8 ; <Self as TraitWithConst>::SOME_CONST] {
+        [0; 32]
+    }
+}
+
+fn main() {}
diff --git a/src/test/ui/const-generics/issues/issue-87964.rs b/src/test/ui/const-generics/issues/issue-87964.rs
new file mode 100644
index 00000000000..116686abb9e
--- /dev/null
+++ b/src/test/ui/const-generics/issues/issue-87964.rs
@@ -0,0 +1,29 @@
+// build-pass
+
+#![feature(generic_const_exprs)]
+#![allow(incomplete_features)]
+
+pub trait Target {
+    const LENGTH: usize;
+}
+
+
+pub struct Container<T: Target>
+where
+    [(); T::LENGTH]: Sized,
+{
+    _target: T,
+}
+
+impl<T: Target> Container<T>
+where
+    [(); T::LENGTH]: Sized,
+{
+    pub fn start(
+        _target: T,
+    ) -> Container<T> {
+        Container { _target }
+    }
+}
+
+fn main() {}
diff --git a/src/test/ui/const-generics/issues/issue-89146.rs b/src/test/ui/const-generics/issues/issue-89146.rs
new file mode 100644
index 00000000000..e3540f46f1e
--- /dev/null
+++ b/src/test/ui/const-generics/issues/issue-89146.rs
@@ -0,0 +1,26 @@
+// build-pass
+
+#![allow(incomplete_features)]
+#![feature(generic_const_exprs)]
+
+pub trait Foo {
+    const SIZE: usize;
+
+    fn to_bytes(&self) -> [u8; Self::SIZE];
+}
+
+pub fn bar<G: Foo>(a: &G) -> u8
+where
+    [(); G::SIZE]: Sized,
+{
+    deeper_bar(a)
+}
+
+fn deeper_bar<G: Foo>(a: &G) -> u8
+where
+    [(); G::SIZE]: Sized,
+{
+    a.to_bytes()[0]
+}
+
+fn main() {}
diff --git a/src/test/ui/const-generics/issues/issue-89320.rs b/src/test/ui/const-generics/issues/issue-89320.rs
new file mode 100644
index 00000000000..afa5c8fab74
--- /dev/null
+++ b/src/test/ui/const-generics/issues/issue-89320.rs
@@ -0,0 +1,19 @@
+// build-pass
+
+#![feature(generic_const_exprs)]
+#![allow(incomplete_features)]
+
+pub trait Enumerable {
+    const N: usize;
+}
+
+#[derive(Clone)]
+pub struct SymmetricGroup<S>
+where
+    S: Enumerable,
+    [(); S::N]: Sized,
+{
+    _phantom: std::marker::PhantomData<S>,
+}
+
+fn main() {}
diff --git a/src/test/ui/derives/issue-36617.rs b/src/test/ui/derives/issue-36617.rs
index 08fc82e91f6..08f293d2ebb 100644
--- a/src/test/ui/derives/issue-36617.rs
+++ b/src/test/ui/derives/issue-36617.rs
@@ -1,3 +1,16 @@
 #![derive(Copy)] //~ ERROR cannot determine resolution for the attribute macro `derive`
+//~^ ERROR `derive` attribute cannot be used at crate level
+
+#![test]//~ ERROR cannot determine resolution for the attribute macro `test`
+//~^ ERROR `test` attribute cannot be used at crate level
+
+#![test_case]//~ ERROR cannot determine resolution for the attribute macro `test_case`
+//~^ ERROR `test_case` attribute cannot be used at crate level
+
+#![bench]//~ ERROR cannot determine resolution for the attribute macro `bench`
+//~^ ERROR `bench` attribute cannot be used at crate level
+
+#![global_allocator]//~ ERROR cannot determine resolution for the attribute macro `global_allocator`
+//~^ ERROR `global_allocator` attribute cannot be used at crate level
 
 fn main() {}
diff --git a/src/test/ui/derives/issue-36617.stderr b/src/test/ui/derives/issue-36617.stderr
index 0716764b427..9cc0a29b065 100644
--- a/src/test/ui/derives/issue-36617.stderr
+++ b/src/test/ui/derives/issue-36617.stderr
@@ -6,5 +6,92 @@ LL | #![derive(Copy)]
    |
    = note: import resolution is stuck, try simplifying macro imports
 
-error: aborting due to previous error
+error: cannot determine resolution for the attribute macro `test`
+  --> $DIR/issue-36617.rs:4:4
+   |
+LL | #![test]
+   |    ^^^^
+   |
+   = note: import resolution is stuck, try simplifying macro imports
+
+error: cannot determine resolution for the attribute macro `test_case`
+  --> $DIR/issue-36617.rs:7:4
+   |
+LL | #![test_case]
+   |    ^^^^^^^^^
+   |
+   = note: import resolution is stuck, try simplifying macro imports
+
+error: cannot determine resolution for the attribute macro `bench`
+  --> $DIR/issue-36617.rs:10:4
+   |
+LL | #![bench]
+   |    ^^^^^
+   |
+   = note: import resolution is stuck, try simplifying macro imports
+
+error: cannot determine resolution for the attribute macro `global_allocator`
+  --> $DIR/issue-36617.rs:13:4
+   |
+LL | #![global_allocator]
+   |    ^^^^^^^^^^^^^^^^
+   |
+   = note: import resolution is stuck, try simplifying macro imports
+
+error: `derive` attribute cannot be used at crate level
+  --> $DIR/issue-36617.rs:1:1
+   |
+LL | #![derive(Copy)]
+   | ^^^^^^^^^^^^^^^^
+   |
+help: perhaps you meant to use an outer attribute
+   |
+LL | #[derive(Copy)]
+   | ~~~~~~~~~~~~~~~
+
+error: `test` attribute cannot be used at crate level
+  --> $DIR/issue-36617.rs:4:1
+   |
+LL | #![test]
+   | ^^^^^^^^
+   |
+help: perhaps you meant to use an outer attribute
+   |
+LL | #[test]
+   | ~~~~~~~
+
+error: `test_case` attribute cannot be used at crate level
+  --> $DIR/issue-36617.rs:7:1
+   |
+LL | #![test_case]
+   | ^^^^^^^^^^^^^
+   |
+help: perhaps you meant to use an outer attribute
+   |
+LL | #[test_case]
+   | ~~~~~~~~~~~~
+
+error: `bench` attribute cannot be used at crate level
+  --> $DIR/issue-36617.rs:10:1
+   |
+LL | #![bench]
+   | ^^^^^^^^^
+   |
+help: perhaps you meant to use an outer attribute
+   |
+LL | #[bench]
+   | ~~~~~~~~
+
+error: `global_allocator` attribute cannot be used at crate level
+  --> $DIR/issue-36617.rs:13:1
+   |
+LL | #![global_allocator]
+   | ^^^^^^^^^^^^^^^^^^^^
+   |
+help: perhaps you meant to use an outer attribute
+   |
+LL | #[global_allocator]
+   | ~~~~~~~~~~~~~~~~~~~
+
+error: aborting due to 10 previous errors
 
diff --git a/src/test/ui/feature-gates/feature-gate-asm_unwind.rs b/src/test/ui/feature-gates/feature-gate-asm_unwind.rs
new file mode 100644
index 00000000000..c9957ff91d5
--- /dev/null
+++ b/src/test/ui/feature-gates/feature-gate-asm_unwind.rs
@@ -0,0 +1,10 @@
+// only-x86_64
+
+#![feature(asm)]
+
+fn main() {
+    unsafe {
+        asm!("", options(may_unwind));
+        //~^ ERROR the `may_unwind` option is unstable
+    }
+}
diff --git a/src/test/ui/feature-gates/feature-gate-asm_unwind.stderr b/src/test/ui/feature-gates/feature-gate-asm_unwind.stderr
new file mode 100644
index 00000000000..6b5bf286e7b
--- /dev/null
+++ b/src/test/ui/feature-gates/feature-gate-asm_unwind.stderr
@@ -0,0 +1,12 @@
+error[E0658]: the `may_unwind` option is unstable
+  --> $DIR/feature-gate-asm_unwind.rs:7:9
+   |
+LL |         asm!("", options(may_unwind));
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: see issue #72016 <https://github.com/rust-lang/rust/issues/72016> for more information
+   = help: add `#![feature(asm_unwind)]` 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/feature-gates/issue-43106-gating-of-bench.rs b/src/test/ui/feature-gates/issue-43106-gating-of-bench.rs
index 31eee88d1fa..796325b79af 100644
--- a/src/test/ui/feature-gates/issue-43106-gating-of-bench.rs
+++ b/src/test/ui/feature-gates/issue-43106-gating-of-bench.rs
@@ -6,5 +6,5 @@
 
 #![bench                   = "4100"]
 //~^ ERROR cannot determine resolution for the attribute macro `bench`
-
+//~^^ ERROR `bench` attribute cannot be used at crate level
 fn main() {}
diff --git a/src/test/ui/feature-gates/issue-43106-gating-of-bench.stderr b/src/test/ui/feature-gates/issue-43106-gating-of-bench.stderr
index d0305c5160f..6b332211942 100644
--- a/src/test/ui/feature-gates/issue-43106-gating-of-bench.stderr
+++ b/src/test/ui/feature-gates/issue-43106-gating-of-bench.stderr
@@ -6,5 +6,16 @@ LL | #![bench                   = "4100"]
    |
    = note: import resolution is stuck, try simplifying macro imports
 
-error: aborting due to previous error
+error: `bench` attribute cannot be used at crate level
+  --> $DIR/issue-43106-gating-of-bench.rs:7:1
+   |
+LL | #![bench                   = "4100"]
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+help: perhaps you meant to use an outer attribute
+   |
+LL | #[bench                   = "4100"]
+   |
+
+error: aborting due to 2 previous errors
 
diff --git a/src/test/ui/feature-gates/issue-43106-gating-of-builtin-attrs-error.stderr b/src/test/ui/feature-gates/issue-43106-gating-of-builtin-attrs-error.stderr
index 9e2e2d4137d..f94ec7d4704 100644
--- a/src/test/ui/feature-gates/issue-43106-gating-of-builtin-attrs-error.stderr
+++ b/src/test/ui/feature-gates/issue-43106-gating-of-builtin-attrs-error.stderr
@@ -129,36 +129,66 @@ error: `macro_export` attribute cannot be used at crate level
    |
 LL | #![macro_export]
    | ^^^^^^^^^^^^^^^^
+   |
+help: perhaps you meant to use an outer attribute
+   |
+LL | #[macro_export]
+   |
 
 error: `rustc_main` attribute cannot be used at crate level
   --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:14:1
    |
 LL | #![rustc_main]
    | ^^^^^^^^^^^^^^
+   |
+help: perhaps you meant to use an outer attribute
+   |
+LL | #[rustc_main]
+   | ~~~~~~~~~~~~~
 
 error: `start` attribute cannot be used at crate level
   --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:16:1
    |
 LL | #![start]
    | ^^^^^^^^^
+   |
+help: perhaps you meant to use an outer attribute
+   |
+LL | #[start]
+   |
 
 error: `repr` attribute cannot be used at crate level
   --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:18:1
    |
 LL | #![repr()]
    | ^^^^^^^^^^
+   |
+help: perhaps you meant to use an outer attribute
+   |
+LL | #[repr()]
+   |
 
 error: `path` attribute cannot be used at crate level
   --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:20:1
    |
 LL | #![path = "3800"]
    | ^^^^^^^^^^^^^^^^^
+   |
+help: perhaps you meant to use an outer attribute
+   |
+LL | #[path = "3800"]
+   |
 
 error: `automatically_derived` attribute cannot be used at crate level
   --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:22:1
    |
 LL | #![automatically_derived]
    | ^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+help: perhaps you meant to use an outer attribute
+   |
+LL | #[automatically_derived]
+   |
 
 error[E0518]: attribute should be applied to function or closure
   --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:36:17
diff --git a/src/test/ui/feature-gates/issue-43106-gating-of-test.rs b/src/test/ui/feature-gates/issue-43106-gating-of-test.rs
index ee3fe712e36..39835c9268e 100644
--- a/src/test/ui/feature-gates/issue-43106-gating-of-test.rs
+++ b/src/test/ui/feature-gates/issue-43106-gating-of-test.rs
@@ -3,5 +3,5 @@
 #![allow(soft_unstable)]
 #![test                    = "4200"]
 //~^ ERROR cannot determine resolution for the attribute macro `test`
-
+//~^^ ERROR `test` attribute cannot be used at crate level
 fn main() {}
diff --git a/src/test/ui/feature-gates/issue-43106-gating-of-test.stderr b/src/test/ui/feature-gates/issue-43106-gating-of-test.stderr
index 335af5e7905..300a9966dd8 100644
--- a/src/test/ui/feature-gates/issue-43106-gating-of-test.stderr
+++ b/src/test/ui/feature-gates/issue-43106-gating-of-test.stderr
@@ -6,5 +6,16 @@ LL | #![test                    = "4200"]
    |
    = note: import resolution is stuck, try simplifying macro imports
 
-error: aborting due to previous error
+error: `test` attribute cannot be used at crate level
+  --> $DIR/issue-43106-gating-of-test.rs:4:1
+   |
+LL | #![test                    = "4200"]
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+help: perhaps you meant to use an outer attribute
+   |
+LL | #[test                    = "4200"]
+   |
+
+error: aborting due to 2 previous errors
 
diff --git a/src/test/ui/feature-gates/thread-local-const-init.rs b/src/test/ui/feature-gates/thread-local-const-init.rs
deleted file mode 100644
index 6584ffa7cf9..00000000000
--- a/src/test/ui/feature-gates/thread-local-const-init.rs
+++ /dev/null
@@ -1,4 +0,0 @@
-thread_local!(static X: u32 = const { 0 });
-//~^ ERROR: use of unstable library feature 'thread_local_const_init'
-
-fn main() {}
diff --git a/src/test/ui/feature-gates/thread-local-const-init.stderr b/src/test/ui/feature-gates/thread-local-const-init.stderr
deleted file mode 100644
index f80506831b4..00000000000
--- a/src/test/ui/feature-gates/thread-local-const-init.stderr
+++ /dev/null
@@ -1,13 +0,0 @@
-error[E0658]: use of unstable library feature 'thread_local_const_init'
-  --> $DIR/thread-local-const-init.rs:1:1
-   |
-LL | thread_local!(static X: u32 = const { 0 });
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   |
-   = note: see issue #84223 <https://github.com/rust-lang/rust/issues/84223> for more information
-   = help: add `#![feature(thread_local_const_init)]` to the crate attributes to enable
-   = note: this error originates in the macro `$crate::__thread_local_inner` (in Nightly builds, run with -Z macro-backtrace for more info)
-
-error: aborting due to previous error
-
-For more information about this error, try `rustc --explain E0658`.
diff --git a/src/test/ui/generator/issue-91477.rs b/src/test/ui/generator/issue-91477.rs
new file mode 100644
index 00000000000..6c027feb422
--- /dev/null
+++ b/src/test/ui/generator/issue-91477.rs
@@ -0,0 +1,7 @@
+#![feature(generators)]
+
+fn foo() -> impl Sized {
+    yield 1; //~ ERROR E0627
+}
+
+fn main() {}
diff --git a/src/test/ui/generator/issue-91477.stderr b/src/test/ui/generator/issue-91477.stderr
new file mode 100644
index 00000000000..4597dc1bcdf
--- /dev/null
+++ b/src/test/ui/generator/issue-91477.stderr
@@ -0,0 +1,9 @@
+error[E0627]: yield expression outside of generator literal
+  --> $DIR/issue-91477.rs:4:5
+   |
+LL |     yield 1;
+   |     ^^^^^^^
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0627`.
diff --git a/src/test/ui/imports/issue-28134.rs b/src/test/ui/imports/issue-28134.rs
index 1ed2d330b51..ef2a5d634a6 100644
--- a/src/test/ui/imports/issue-28134.rs
+++ b/src/test/ui/imports/issue-28134.rs
@@ -2,3 +2,4 @@
 
 #![allow(soft_unstable)]
 #![test] //~ ERROR cannot determine resolution for the attribute macro `test`
+//~^ ERROR 4:1: 4:9: `test` attribute cannot be used at crate level
diff --git a/src/test/ui/imports/issue-28134.stderr b/src/test/ui/imports/issue-28134.stderr
index 8ed4d015f32..33cb53f202a 100644
--- a/src/test/ui/imports/issue-28134.stderr
+++ b/src/test/ui/imports/issue-28134.stderr
@@ -6,5 +6,16 @@ LL | #![test]
    |
    = note: import resolution is stuck, try simplifying macro imports
 
-error: aborting due to previous error
+error: `test` attribute cannot be used at crate level
+  --> $DIR/issue-28134.rs:4:1
+   |
+LL | #![test]
+   | ^^^^^^^^
+   |
+help: perhaps you meant to use an outer attribute
+   |
+LL | #[test]
+   | ~~~~~~~
+
+error: aborting due to 2 previous errors
 
diff --git a/src/test/ui/infinite/infinite-struct.stderr b/src/test/ui/infinite/infinite-struct.stderr
index 383e13fd4b0..369645f9030 100644
--- a/src/test/ui/infinite/infinite-struct.stderr
+++ b/src/test/ui/infinite/infinite-struct.stderr
@@ -19,7 +19,7 @@ LL | struct Take(Take);
    | ^^^^^^^^^^^^^^^^^^
    |
    = note: ...which immediately requires computing drop-check constraints for `Take` again
-   = note: cycle used when computing dropck types for `Canonical { max_universe: U0, variables: [], value: ParamEnvAnd { param_env: ParamEnv { caller_bounds: [], reveal: UserFacing, constness: NotConst }, value: Take } }`
+   = note: cycle used when computing dropck types for `Canonical { max_universe: U0, variables: [], value: ParamEnvAnd { param_env: ParamEnv { caller_bounds: [], reveal: UserFacing }, value: Take } }`
 
 error: aborting due to 2 previous errors
 
diff --git a/src/test/ui/infinite/infinite-tag-type-recursion.stderr b/src/test/ui/infinite/infinite-tag-type-recursion.stderr
index 1802c7599a3..61b5e946775 100644
--- a/src/test/ui/infinite/infinite-tag-type-recursion.stderr
+++ b/src/test/ui/infinite/infinite-tag-type-recursion.stderr
@@ -18,7 +18,7 @@ LL | enum MList { Cons(isize, MList), Nil }
    | ^^^^^^^^^^
    |
    = note: ...which immediately requires computing drop-check constraints for `MList` again
-   = note: cycle used when computing dropck types for `Canonical { max_universe: U0, variables: [], value: ParamEnvAnd { param_env: ParamEnv { caller_bounds: [], reveal: UserFacing, constness: NotConst }, value: MList } }`
+   = note: cycle used when computing dropck types for `Canonical { max_universe: U0, variables: [], value: ParamEnvAnd { param_env: ParamEnv { caller_bounds: [], reveal: UserFacing }, value: MList } }`
 
 error: aborting due to 2 previous errors
 
diff --git a/src/test/ui/issues-71798.stderr b/src/test/ui/issues-71798.stderr
index bbcdd3e37a9..bc4dc9ebf9e 100644
--- a/src/test/ui/issues-71798.stderr
+++ b/src/test/ui/issues-71798.stderr
@@ -11,6 +11,7 @@ LL | fn test_ref(x: &u32) -> impl std::future::Future<Output = u32> + '_ {
    |                         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `u32` is not a future
    |
    = help: the trait `Future` is not implemented for `u32`
+   = note: u32 must be a future or must implement `IntoFuture` to be awaited
 
 error: aborting due to 2 previous errors
 
diff --git a/src/test/ui/issues/issue-38821.stderr b/src/test/ui/issues/issue-38821.stderr
index e53a543f3a0..cdf1f0dfc53 100644
--- a/src/test/ui/issues/issue-38821.stderr
+++ b/src/test/ui/issues/issue-38821.stderr
@@ -10,6 +10,10 @@ note: required because of the requirements on the impl of `IntoNullable` for `<C
 LL | impl<T: NotNull> IntoNullable for T {
    |                  ^^^^^^^^^^^^     ^
    = note: this error originates in the derive macro `Copy` (in Nightly builds, run with -Z macro-backtrace for more info)
+help: consider further restricting the associated type
+   |
+LL |     Expr: Expression<SqlType=<Col::SqlType as IntoNullable>::Nullable>, <Col as Expression>::SqlType: NotNull,
+   |                                                                       +++++++++++++++++++++++++++++++++++++++
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/issues/issue-50480.rs b/src/test/ui/issues/issue-50480.rs
index deb63872f69..10597caf5b2 100644
--- a/src/test/ui/issues/issue-50480.rs
+++ b/src/test/ui/issues/issue-50480.rs
@@ -1,8 +1,17 @@
 #[derive(Clone, Copy)]
 //~^ ERROR the trait `Copy` may not be implemented for this type
-struct Foo(NotDefined, <i32 as Iterator>::Item, Vec<i32>, String);
+struct Foo(N, NotDefined, <i32 as Iterator>::Item, Vec<i32>, String);
 //~^ ERROR cannot find type `NotDefined` in this scope
 //~| ERROR cannot find type `NotDefined` in this scope
+//~| ERROR cannot find type `N` in this scope
+//~| ERROR cannot find type `N` in this scope
+//~| ERROR `i32` is not an iterator
+
+#[derive(Clone, Copy)]
+//~^ ERROR the trait `Copy` may not be implemented for this type
+struct Bar<T>(T, N, NotDefined, <i32 as Iterator>::Item, Vec<i32>, String);
+//~^ ERROR cannot find type `NotDefined` in this scope
+//~| ERROR cannot find type `N` in this scope
 //~| ERROR `i32` is not an iterator
 
 fn main() {}
diff --git a/src/test/ui/issues/issue-50480.stderr b/src/test/ui/issues/issue-50480.stderr
index 15f38c89267..0bb1f9ae035 100644
--- a/src/test/ui/issues/issue-50480.stderr
+++ b/src/test/ui/issues/issue-50480.stderr
@@ -1,20 +1,61 @@
-error[E0412]: cannot find type `NotDefined` in this scope
+error[E0412]: cannot find type `N` in this scope
   --> $DIR/issue-50480.rs:3:12
    |
-LL | struct Foo(NotDefined, <i32 as Iterator>::Item, Vec<i32>, String);
-   |            ^^^^^^^^^^ not found in this scope
+LL | struct Foo(N, NotDefined, <i32 as Iterator>::Item, Vec<i32>, String);
+   |           -^ not found in this scope
+   |           |
+   |           help: you might be missing a type parameter: `<N>`
 
 error[E0412]: cannot find type `NotDefined` in this scope
+  --> $DIR/issue-50480.rs:3:15
+   |
+LL | struct Foo(N, NotDefined, <i32 as Iterator>::Item, Vec<i32>, String);
+   |               ^^^^^^^^^^ not found in this scope
+
+error[E0412]: cannot find type `N` in this scope
   --> $DIR/issue-50480.rs:3:12
    |
-LL | struct Foo(NotDefined, <i32 as Iterator>::Item, Vec<i32>, String);
-   |            ^^^^^^^^^^ not found in this scope
+LL | struct Foo(N, NotDefined, <i32 as Iterator>::Item, Vec<i32>, String);
+   |           -^ not found in this scope
+   |           |
+   |           help: you might be missing a type parameter: `<N>`
+
+error[E0412]: cannot find type `NotDefined` in this scope
+  --> $DIR/issue-50480.rs:3:15
+   |
+LL | struct Foo(N, NotDefined, <i32 as Iterator>::Item, Vec<i32>, String);
+   |           -   ^^^^^^^^^^ not found in this scope
+   |           |
+   |           help: you might be missing a type parameter: `<NotDefined>`
+
+error[E0412]: cannot find type `N` in this scope
+  --> $DIR/issue-50480.rs:12:18
+   |
+LL | struct Bar<T>(T, N, NotDefined, <i32 as Iterator>::Item, Vec<i32>, String);
+   |            -     ^
+   |            |
+   |            similarly named type parameter `T` defined here
+   |
+help: a type parameter with a similar name exists
+   |
+LL | struct Bar<T>(T, T, NotDefined, <i32 as Iterator>::Item, Vec<i32>, String);
+   |                  ~
+help: you might be missing a type parameter
+   |
+LL | struct Bar<T, N>(T, N, NotDefined, <i32 as Iterator>::Item, Vec<i32>, String);
+   |             +++
+
+error[E0412]: cannot find type `NotDefined` in this scope
+  --> $DIR/issue-50480.rs:12:21
+   |
+LL | struct Bar<T>(T, N, NotDefined, <i32 as Iterator>::Item, Vec<i32>, String);
+   |                     ^^^^^^^^^^ not found in this scope
 
 error[E0277]: `i32` is not an iterator
-  --> $DIR/issue-50480.rs:3:24
+  --> $DIR/issue-50480.rs:3:27
    |
-LL | struct Foo(NotDefined, <i32 as Iterator>::Item, Vec<i32>, String);
-   |                        ^^^^^^^^^^^^^^^^^^^^^^^ `i32` is not an iterator
+LL | struct Foo(N, NotDefined, <i32 as Iterator>::Item, Vec<i32>, String);
+   |                           ^^^^^^^^^^^^^^^^^^^^^^^ `i32` is not an iterator
    |
    = help: the trait `Iterator` is not implemented for `i32`
    = note: if you want to iterate between `start` until a value `end`, use the exclusive range syntax `start..end` or the inclusive range syntax `start..=end`
@@ -25,14 +66,36 @@ error[E0204]: the trait `Copy` may not be implemented for this type
 LL | #[derive(Clone, Copy)]
    |                 ^^^^
 LL |
-LL | struct Foo(NotDefined, <i32 as Iterator>::Item, Vec<i32>, String);
-   |                                                 --------  ------ this field does not implement `Copy`
-   |                                                 |
-   |                                                 this field does not implement `Copy`
+LL | struct Foo(N, NotDefined, <i32 as Iterator>::Item, Vec<i32>, String);
+   |                                                    --------  ------ this field does not implement `Copy`
+   |                                                    |
+   |                                                    this field does not implement `Copy`
+   |
+   = note: this error originates in the derive macro `Copy` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error[E0277]: `i32` is not an iterator
+  --> $DIR/issue-50480.rs:12:33
+   |
+LL | struct Bar<T>(T, N, NotDefined, <i32 as Iterator>::Item, Vec<i32>, String);
+   |                                 ^^^^^^^^^^^^^^^^^^^^^^^ `i32` is not an iterator
+   |
+   = help: the trait `Iterator` is not implemented for `i32`
+   = note: if you want to iterate between `start` until a value `end`, use the exclusive range syntax `start..end` or the inclusive range syntax `start..=end`
+
+error[E0204]: the trait `Copy` may not be implemented for this type
+  --> $DIR/issue-50480.rs:10:17
+   |
+LL | #[derive(Clone, Copy)]
+   |                 ^^^^
+LL |
+LL | struct Bar<T>(T, N, NotDefined, <i32 as Iterator>::Item, Vec<i32>, String);
+   |                                                          --------  ------ this field does not implement `Copy`
+   |                                                          |
+   |                                                          this field does not implement `Copy`
    |
    = note: this error originates in the derive macro `Copy` (in Nightly builds, run with -Z macro-backtrace for more info)
 
-error: aborting due to 4 previous errors
+error: aborting due to 10 previous errors
 
 Some errors have detailed explanations: E0204, E0277, E0412.
 For more information about an error, try `rustc --explain E0204`.
diff --git a/src/test/ui/issues/issue-88150.rs b/src/test/ui/issues/issue-88150.rs
new file mode 100644
index 00000000000..555a38637a4
--- /dev/null
+++ b/src/test/ui/issues/issue-88150.rs
@@ -0,0 +1,21 @@
+// run-pass
+// compile-flags:-C debuginfo=2
+// edition:2018
+
+use core::marker::PhantomData;
+
+pub struct Foo<T: ?Sized, A>(
+    PhantomData<(A, T)>,
+);
+
+enum Never {}
+
+impl<T: ?Sized> Foo<T, Never> {
+    fn new_foo() -> Foo<T, Never> {
+        Foo(PhantomData)
+    }
+}
+
+fn main() {
+    let _ = Foo::<[()], Never>::new_foo();
+}
diff --git a/src/test/ui/keyword/keyword-self-as-type-param.rs b/src/test/ui/keyword/keyword-self-as-type-param.rs
index 785d64ec8ea..55c7ac128ff 100644
--- a/src/test/ui/keyword/keyword-self-as-type-param.rs
+++ b/src/test/ui/keyword/keyword-self-as-type-param.rs
@@ -1,10 +1,10 @@
 // Regression test of #36638.
 
 struct Foo<Self>(Self);
-//~^ ERROR expected identifier, found keyword `Self`
-//~^^ ERROR E0392
+//~^ ERROR unexpected keyword `Self` in generic parameters
+//~| ERROR recursive type `Foo` has infinite size
 
 trait Bar<Self> {}
-//~^ ERROR expected identifier, found keyword `Self`
+//~^ ERROR unexpected keyword `Self` in generic parameters
 
 fn main() {}
diff --git a/src/test/ui/keyword/keyword-self-as-type-param.stderr b/src/test/ui/keyword/keyword-self-as-type-param.stderr
index cc3df2e36f7..fd101b32b4c 100644
--- a/src/test/ui/keyword/keyword-self-as-type-param.stderr
+++ b/src/test/ui/keyword/keyword-self-as-type-param.stderr
@@ -1,24 +1,33 @@
-error: expected identifier, found keyword `Self`
+error: unexpected keyword `Self` in generic parameters
   --> $DIR/keyword-self-as-type-param.rs:3:12
    |
 LL | struct Foo<Self>(Self);
-   |            ^^^^ expected identifier, found keyword
+   |            ^^^^
+   |
+   = note: you cannot use `Self` as a generic parameter because it is reserved for associated items
 
-error: expected identifier, found keyword `Self`
+error: unexpected keyword `Self` in generic parameters
   --> $DIR/keyword-self-as-type-param.rs:7:11
    |
 LL | trait Bar<Self> {}
-   |           ^^^^ expected identifier, found keyword
+   |           ^^^^
+   |
+   = note: you cannot use `Self` as a generic parameter because it is reserved for associated items
 
-error[E0392]: parameter `Self` is never used
-  --> $DIR/keyword-self-as-type-param.rs:3:12
+error[E0072]: recursive type `Foo` has infinite size
+  --> $DIR/keyword-self-as-type-param.rs:3:1
    |
 LL | struct Foo<Self>(Self);
-   |            ^^^^ unused parameter
+   | ^^^^^^^^^^^^^^^^^----^^
+   | |                |
+   | |                recursive without indirection
+   | recursive type has infinite size
+   |
+help: insert some indirection (e.g., a `Box`, `Rc`, or `&`) to make `Foo` representable
    |
-   = help: consider removing `Self`, referring to it in a field, or using a marker such as `PhantomData`
-   = help: if you intended `Self` to be a const parameter, use `const Self: usize` instead
+LL | struct Foo<Self>(Box<Self>);
+   |                  ++++    +
 
 error: aborting due to 3 previous errors
 
-For more information about this error, try `rustc --explain E0392`.
+For more information about this error, try `rustc --explain E0072`.
diff --git a/src/test/ui/lifetimes/undeclared-lifetime-used-in-debug-macro-issue-70152.stderr b/src/test/ui/lifetimes/undeclared-lifetime-used-in-debug-macro-issue-70152.stderr
index e18d725faef..a2086895234 100644
--- a/src/test/ui/lifetimes/undeclared-lifetime-used-in-debug-macro-issue-70152.stderr
+++ b/src/test/ui/lifetimes/undeclared-lifetime-used-in-debug-macro-issue-70152.stderr
@@ -11,9 +11,8 @@ LL |     a: &'b str,
 error[E0261]: use of undeclared lifetime name `'b`
   --> $DIR/undeclared-lifetime-used-in-debug-macro-issue-70152.rs:3:9
    |
-LL | #[derive(Eq, PartialEq)]
-   |          -- lifetime `'b` is missing in item created through this procedural macro
 LL | struct Test {
+   |            - help: consider introducing lifetime `'b` here: `<'b>`
 LL |     a: &'b str,
    |         ^^ undeclared lifetime
    |
diff --git a/src/test/ui/macros/macro-pat-pattern-followed-by-or-in-2021.stderr b/src/test/ui/macros/macro-pat-pattern-followed-by-or-in-2021.stderr
index a5987a25551..a06487be3d6 100644
--- a/src/test/ui/macros/macro-pat-pattern-followed-by-or-in-2021.stderr
+++ b/src/test/ui/macros/macro-pat-pattern-followed-by-or-in-2021.stderr
@@ -2,7 +2,9 @@ error: `$x:pat` is followed by `|`, which is not allowed for `pat` fragments
   --> $DIR/macro-pat-pattern-followed-by-or-in-2021.rs:3:28
    |
 LL | macro_rules! foo { ($x:pat | $y:pat) => {} }
-   |                            ^ not allowed after `pat` fragments
+   |                     ------ ^ not allowed after `pat` fragments
+   |                     |
+   |                     help: try a `pat_param` fragment specifier instead: `$x:pat_param`
    |
    = note: allowed there are: `=>`, `,`, `=`, `if` or `in`
 
@@ -10,7 +12,9 @@ error: `$x:pat` is followed by `|`, which is not allowed for `pat` fragments
   --> $DIR/macro-pat-pattern-followed-by-or-in-2021.rs:4:32
    |
 LL | macro_rules! bar { ($($x:pat)+ | $($y:pat)+) => {} }
-   |                                ^ not allowed after `pat` fragments
+   |                       ------   ^ not allowed after `pat` fragments
+   |                       |
+   |                       help: try a `pat_param` fragment specifier instead: `$x:pat_param`
    |
    = note: allowed there are: `=>`, `,`, `=`, `if` or `in`
 
@@ -18,7 +22,9 @@ error: `$pat:pat` may be followed by `|`, which is not allowed for `pat` fragmen
   --> $DIR/macro-pat-pattern-followed-by-or-in-2021.rs:7:36
    |
 LL |     ( $expr:expr , $( $( $pat:pat )|+ => $expr_arm:expr ),+ ) => {
-   |                                    ^ not allowed after `pat` fragments
+   |                          --------  ^ not allowed after `pat` fragments
+   |                          |
+   |                          help: try a `pat_param` fragment specifier instead: `$pat:pat_param`
    |
    = note: allowed there are: `=>`, `,`, `=`, `if` or `in`
 
diff --git a/src/test/ui/macros/macro-pat2021-pattern-followed-by-or.stderr b/src/test/ui/macros/macro-pat2021-pattern-followed-by-or.stderr
index 8aebe98515f..c3754dde080 100644
--- a/src/test/ui/macros/macro-pat2021-pattern-followed-by-or.stderr
+++ b/src/test/ui/macros/macro-pat2021-pattern-followed-by-or.stderr
@@ -2,7 +2,9 @@ error: `$x:pat` is followed by `|`, which is not allowed for `pat` fragments
   --> $DIR/macro-pat2021-pattern-followed-by-or.rs:4:28
    |
 LL | macro_rules! foo { ($x:pat | $y:pat) => {} }
-   |                            ^ not allowed after `pat` fragments
+   |                     ------ ^ not allowed after `pat` fragments
+   |                     |
+   |                     help: try a `pat_param` fragment specifier instead: `$x:pat_param`
    |
    = note: allowed there are: `=>`, `,`, `=`, `if` or `in`
 
@@ -10,7 +12,9 @@ error: `$x:pat` is followed by `|`, which is not allowed for `pat` fragments
   --> $DIR/macro-pat2021-pattern-followed-by-or.rs:7:28
    |
 LL | macro_rules! ogg { ($x:pat | $y:pat_param) => {} }
-   |                            ^ not allowed after `pat` fragments
+   |                     ------ ^ not allowed after `pat` fragments
+   |                     |
+   |                     help: try a `pat_param` fragment specifier instead: `$x:pat_param`
    |
    = note: allowed there are: `=>`, `,`, `=`, `if` or `in`
 
@@ -18,7 +22,9 @@ error: `$pat:pat` may be followed by `|`, which is not allowed for `pat` fragmen
   --> $DIR/macro-pat2021-pattern-followed-by-or.rs:9:35
    |
 LL |     ( $expr:expr , $( $( $pat:pat)|+ => $expr_arm:pat),+ ) => {
-   |                                   ^ not allowed after `pat` fragments
+   |                          -------- ^ not allowed after `pat` fragments
+   |                          |
+   |                          help: try a `pat_param` fragment specifier instead: `$pat:pat_param`
    |
    = note: allowed there are: `=>`, `,`, `=`, `if` or `in`
 
diff --git a/src/test/ui/numeric/numeric-cast.stderr b/src/test/ui/numeric/numeric-cast.stderr
index 3e2bc5bc82d..b8f2d88ab49 100644
--- a/src/test/ui/numeric/numeric-cast.stderr
+++ b/src/test/ui/numeric/numeric-cast.stderr
@@ -994,8 +994,8 @@ error[E0308]: mismatched types
 LL |     foo::<f64>(x_usize);
    |                ^^^^^^^ expected `f64`, found `usize`
    |
-help: you can cast a `usize` to an `f64`, producing the floating point representation of the integer,
-   |                                              rounded if necessary
+help: you can cast a `usize` to an `f64`, producing the floating point representation of the integer, rounded if necessary
+   |
 LL |     foo::<f64>(x_usize as f64);
    |                        ++++++
 
@@ -1005,8 +1005,8 @@ error[E0308]: mismatched types
 LL |     foo::<f64>(x_u64);
    |                ^^^^^ expected `f64`, found `u64`
    |
-help: you can cast a `u64` to an `f64`, producing the floating point representation of the integer,
-   |                                              rounded if necessary
+help: you can cast a `u64` to an `f64`, producing the floating point representation of the integer, rounded if necessary
+   |
 LL |     foo::<f64>(x_u64 as f64);
    |                      ++++++
 
@@ -1115,8 +1115,8 @@ error[E0308]: mismatched types
 LL |     foo::<f32>(x_usize);
    |                ^^^^^^^ expected `f32`, found `usize`
    |
-help: you can cast a `usize` to an `f32`, producing the floating point representation of the integer,
-   |                                              rounded if necessary
+help: you can cast a `usize` to an `f32`, producing the floating point representation of the integer, rounded if necessary
+   |
 LL |     foo::<f32>(x_usize as f32);
    |                        ++++++
 
@@ -1126,8 +1126,8 @@ error[E0308]: mismatched types
 LL |     foo::<f32>(x_u64);
    |                ^^^^^ expected `f32`, found `u64`
    |
-help: you can cast a `u64` to an `f32`, producing the floating point representation of the integer,
-   |                                              rounded if necessary
+help: you can cast a `u64` to an `f32`, producing the floating point representation of the integer, rounded if necessary
+   |
 LL |     foo::<f32>(x_u64 as f32);
    |                      ++++++
 
@@ -1137,8 +1137,8 @@ error[E0308]: mismatched types
 LL |     foo::<f32>(x_u32);
    |                ^^^^^ expected `f32`, found `u32`
    |
-help: you can cast a `u32` to an `f32`, producing the floating point representation of the integer,
-   |                                              rounded if necessary
+help: you can cast a `u32` to an `f32`, producing the floating point representation of the integer, rounded if necessary
+   |
 LL |     foo::<f32>(x_u32 as f32);
    |                      ++++++
 
diff --git a/src/test/ui/rfc-2632-const-trait-impl/assoc-type.rs b/src/test/ui/rfc-2632-const-trait-impl/assoc-type.rs
index 7b012083c5a..228b5ed71e8 100644
--- a/src/test/ui/rfc-2632-const-trait-impl/assoc-type.rs
+++ b/src/test/ui/rfc-2632-const-trait-impl/assoc-type.rs
@@ -1,5 +1,6 @@
 // FIXME(fee1-dead): this should have a better error message
 #![feature(const_trait_impl)]
+
 struct NonConstAdd(i32);
 
 impl std::ops::Add for NonConstAdd {
diff --git a/src/test/ui/rfc-2632-const-trait-impl/assoc-type.stderr b/src/test/ui/rfc-2632-const-trait-impl/assoc-type.stderr
index d1e55e12d6f..b894092205e 100644
--- a/src/test/ui/rfc-2632-const-trait-impl/assoc-type.stderr
+++ b/src/test/ui/rfc-2632-const-trait-impl/assoc-type.stderr
@@ -1,12 +1,12 @@
 error[E0277]: cannot add `NonConstAdd` to `NonConstAdd`
-  --> $DIR/assoc-type.rs:18:5
+  --> $DIR/assoc-type.rs:19:5
    |
 LL |     type Bar = NonConstAdd;
    |     ^^^^^^^^^^^^^^^^^^^^^^^ no implementation for `NonConstAdd + NonConstAdd`
    |
    = help: the trait `Add` is not implemented for `NonConstAdd`
 note: required by a bound in `Foo::Bar`
-  --> $DIR/assoc-type.rs:14:15
+  --> $DIR/assoc-type.rs:15:15
    |
 LL |     type Bar: ~const std::ops::Add;
    |               ^^^^^^^^^^^^^^^^^^^^ required by this bound in `Foo::Bar`
diff --git a/src/test/ui/span/issue-43927-non-ADT-derive.rs b/src/test/ui/span/issue-43927-non-ADT-derive.rs
index 840c12e16e1..935bfa001bf 100644
--- a/src/test/ui/span/issue-43927-non-ADT-derive.rs
+++ b/src/test/ui/span/issue-43927-non-ADT-derive.rs
@@ -1,5 +1,6 @@
 #![derive(Debug, PartialEq, Eq)] // should be an outer attribute!
 //~^ ERROR cannot determine resolution for the attribute macro `derive`
+//~^^ ERROR `derive` attribute cannot be used at crate level
 struct DerivedOn;
 
 fn main() {}
diff --git a/src/test/ui/span/issue-43927-non-ADT-derive.stderr b/src/test/ui/span/issue-43927-non-ADT-derive.stderr
index 9ef81c5150a..e3ae37e3689 100644
--- a/src/test/ui/span/issue-43927-non-ADT-derive.stderr
+++ b/src/test/ui/span/issue-43927-non-ADT-derive.stderr
@@ -6,5 +6,16 @@ LL | #![derive(Debug, PartialEq, Eq)] // should be an outer attribute!
    |
    = note: import resolution is stuck, try simplifying macro imports
 
-error: aborting due to previous error
+error: `derive` attribute cannot be used at crate level
+  --> $DIR/issue-43927-non-ADT-derive.rs:1:1
+   |
+LL | #![derive(Debug, PartialEq, Eq)] // should be an outer attribute!
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+help: perhaps you meant to use an outer attribute
+   |
+LL | #[derive(Debug, PartialEq, Eq)] // should be an outer attribute!
+   | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+error: aborting due to 2 previous errors
 
diff --git a/src/test/ui/suggestions/async-fn-ctor-passed-as-arg-where-it-should-have-been-called.stderr b/src/test/ui/suggestions/async-fn-ctor-passed-as-arg-where-it-should-have-been-called.stderr
index 4759ebea0e9..766db2a8356 100644
--- a/src/test/ui/suggestions/async-fn-ctor-passed-as-arg-where-it-should-have-been-called.stderr
+++ b/src/test/ui/suggestions/async-fn-ctor-passed-as-arg-where-it-should-have-been-called.stderr
@@ -10,6 +10,7 @@ LL |     bar(foo);
    |     required by a bound introduced by this call
    |
    = help: the trait `Future` is not implemented for `fn() -> impl Future<Output = ()> {foo}`
+   = note: fn() -> impl Future<Output = ()> {foo} must be a future or must implement `IntoFuture` to be awaited
 note: required by a bound in `bar`
   --> $DIR/async-fn-ctor-passed-as-arg-where-it-should-have-been-called.rs:7:16
    |
@@ -31,6 +32,7 @@ LL |     bar(async_closure);
    |     required by a bound introduced by this call
    |
    = help: the trait `Future` is not implemented for `[closure@$DIR/async-fn-ctor-passed-as-arg-where-it-should-have-been-called.rs:11:25: 11:36]`
+   = note: [closure@$DIR/async-fn-ctor-passed-as-arg-where-it-should-have-been-called.rs:11:25: 11:36] must be a future or must implement `IntoFuture` to be awaited
 note: required by a bound in `bar`
   --> $DIR/async-fn-ctor-passed-as-arg-where-it-should-have-been-called.rs:7:16
    |
diff --git a/src/test/ui/suggestions/derive-macro-missing-bounds.rs b/src/test/ui/suggestions/derive-macro-missing-bounds.rs
new file mode 100644
index 00000000000..56c218f97eb
--- /dev/null
+++ b/src/test/ui/suggestions/derive-macro-missing-bounds.rs
@@ -0,0 +1,89 @@
+mod a {
+    use std::fmt::{Debug, Formatter, Result};
+    struct Inner<T>(T);
+
+    impl Debug for Inner<()> {
+        fn fmt(&self, f: &mut Formatter<'_>) -> Result {
+            todo!()
+        }
+    }
+
+    #[derive(Debug)]
+    struct Outer<T>(Inner<T>); //~ ERROR `a::Inner<T>` doesn't implement `Debug`
+}
+
+mod b {
+    use std::fmt::{Debug, Formatter, Result};
+    struct Inner<T>(T);
+
+    impl<T: Debug> Debug for Inner<T> {
+        fn fmt(&self, f: &mut Formatter<'_>) -> Result {
+            todo!()
+        }
+    }
+
+    #[derive(Debug)]
+    struct Outer<T>(Inner<T>);
+}
+
+mod c {
+    use std::fmt::{Debug, Formatter, Result};
+    struct Inner<T>(T);
+    trait Trait {}
+
+    impl<T: Debug + Trait> Debug for Inner<T> {
+        fn fmt(&self, f: &mut Formatter<'_>) -> Result {
+            todo!()
+        }
+    }
+
+    #[derive(Debug)]
+    struct Outer<T>(Inner<T>); //~ ERROR the trait bound `T: c::Trait` is not satisfied
+}
+
+mod d {
+    use std::fmt::{Debug, Formatter, Result};
+    struct Inner<T>(T);
+    trait Trait {}
+
+    impl<T> Debug for Inner<T> where T: Debug, T: Trait {
+        fn fmt(&self, f: &mut Formatter<'_>) -> Result {
+            todo!()
+        }
+    }
+
+    #[derive(Debug)]
+    struct Outer<T>(Inner<T>); //~ ERROR the trait bound `T: d::Trait` is not satisfied
+}
+
+mod e {
+    use std::fmt::{Debug, Formatter, Result};
+    struct Inner<T>(T);
+    trait Trait {}
+
+    impl<T> Debug for Inner<T> where T: Debug + Trait {
+        fn fmt(&self, f: &mut Formatter<'_>) -> Result {
+            todo!()
+        }
+    }
+
+    #[derive(Debug)]
+    struct Outer<T>(Inner<T>); //~ ERROR the trait bound `T: e::Trait` is not satisfied
+}
+
+mod f {
+    use std::fmt::{Debug, Formatter, Result};
+    struct Inner<T>(T);
+    trait Trait {}
+
+    impl<T: Debug> Debug for Inner<T> where T: Trait {
+        fn fmt(&self, f: &mut Formatter<'_>) -> Result {
+            todo!()
+        }
+    }
+
+    #[derive(Debug)]
+    struct Outer<T>(Inner<T>); //~ ERROR the trait bound `T: f::Trait` is not satisfied
+}
+
+fn main() {}
diff --git a/src/test/ui/suggestions/derive-macro-missing-bounds.stderr b/src/test/ui/suggestions/derive-macro-missing-bounds.stderr
new file mode 100644
index 00000000000..7a4f7e209c1
--- /dev/null
+++ b/src/test/ui/suggestions/derive-macro-missing-bounds.stderr
@@ -0,0 +1,107 @@
+error[E0277]: `a::Inner<T>` doesn't implement `Debug`
+  --> $DIR/derive-macro-missing-bounds.rs:12:21
+   |
+LL |     #[derive(Debug)]
+   |              ----- in this derive macro expansion
+LL |     struct Outer<T>(Inner<T>);
+   |                     ^^^^^^^^ `a::Inner<T>` cannot be formatted using `{:?}`
+   |
+   = help: the trait `Debug` is not implemented for `a::Inner<T>`
+   = note: add `#[derive(Debug)]` to `a::Inner<T>` or manually `impl Debug for a::Inner<T>`
+   = note: this error originates in the derive macro `Debug` (in Nightly builds, run with -Z macro-backtrace for more info)
+help: consider introducing a `where` bound, but there might be an alternative better way to express this requirement
+   |
+LL |     struct Outer<T>(Inner<T>) where a::Inner<T>: Debug;
+   |                               ++++++++++++++++++++++++
+
+error[E0277]: the trait bound `T: c::Trait` is not satisfied
+  --> $DIR/derive-macro-missing-bounds.rs:41:21
+   |
+LL |     #[derive(Debug)]
+   |              ----- in this derive macro expansion
+LL |     struct Outer<T>(Inner<T>);
+   |                     ^^^^^^^^ the trait `c::Trait` is not implemented for `T`
+   |
+note: required because of the requirements on the impl of `Debug` for `c::Inner<T>`
+  --> $DIR/derive-macro-missing-bounds.rs:34:28
+   |
+LL |     impl<T: Debug + Trait> Debug for Inner<T> {
+   |                            ^^^^^     ^^^^^^^^
+   = note: 1 redundant requirement hidden
+   = note: required because of the requirements on the impl of `Debug` for `&c::Inner<T>`
+   = note: required for the cast to the object type `dyn Debug`
+   = note: this error originates in the derive macro `Debug` (in Nightly builds, run with -Z macro-backtrace for more info)
+help: consider restricting type parameter `T`
+   |
+LL |     struct Outer<T: c::Trait>(Inner<T>);
+   |                   ++++++++++
+
+error[E0277]: the trait bound `T: d::Trait` is not satisfied
+  --> $DIR/derive-macro-missing-bounds.rs:56:21
+   |
+LL |     #[derive(Debug)]
+   |              ----- in this derive macro expansion
+LL |     struct Outer<T>(Inner<T>);
+   |                     ^^^^^^^^ the trait `d::Trait` is not implemented for `T`
+   |
+note: required because of the requirements on the impl of `Debug` for `d::Inner<T>`
+  --> $DIR/derive-macro-missing-bounds.rs:49:13
+   |
+LL |     impl<T> Debug for Inner<T> where T: Debug, T: Trait {
+   |             ^^^^^     ^^^^^^^^
+   = note: 1 redundant requirement hidden
+   = note: required because of the requirements on the impl of `Debug` for `&d::Inner<T>`
+   = note: required for the cast to the object type `dyn Debug`
+   = note: this error originates in the derive macro `Debug` (in Nightly builds, run with -Z macro-backtrace for more info)
+help: consider restricting type parameter `T`
+   |
+LL |     struct Outer<T: d::Trait>(Inner<T>);
+   |                   ++++++++++
+
+error[E0277]: the trait bound `T: e::Trait` is not satisfied
+  --> $DIR/derive-macro-missing-bounds.rs:71:21
+   |
+LL |     #[derive(Debug)]
+   |              ----- in this derive macro expansion
+LL |     struct Outer<T>(Inner<T>);
+   |                     ^^^^^^^^ the trait `e::Trait` is not implemented for `T`
+   |
+note: required because of the requirements on the impl of `Debug` for `e::Inner<T>`
+  --> $DIR/derive-macro-missing-bounds.rs:64:13
+   |
+LL |     impl<T> Debug for Inner<T> where T: Debug + Trait {
+   |             ^^^^^     ^^^^^^^^
+   = note: 1 redundant requirement hidden
+   = note: required because of the requirements on the impl of `Debug` for `&e::Inner<T>`
+   = note: required for the cast to the object type `dyn Debug`
+   = note: this error originates in the derive macro `Debug` (in Nightly builds, run with -Z macro-backtrace for more info)
+help: consider restricting type parameter `T`
+   |
+LL |     struct Outer<T: e::Trait>(Inner<T>);
+   |                   ++++++++++
+
+error[E0277]: the trait bound `T: f::Trait` is not satisfied
+  --> $DIR/derive-macro-missing-bounds.rs:86:21
+   |
+LL |     #[derive(Debug)]
+   |              ----- in this derive macro expansion
+LL |     struct Outer<T>(Inner<T>);
+   |                     ^^^^^^^^ the trait `f::Trait` is not implemented for `T`
+   |
+note: required because of the requirements on the impl of `Debug` for `f::Inner<T>`
+  --> $DIR/derive-macro-missing-bounds.rs:79:20
+   |
+LL |     impl<T: Debug> Debug for Inner<T> where T: Trait {
+   |                    ^^^^^     ^^^^^^^^
+   = note: 1 redundant requirement hidden
+   = note: required because of the requirements on the impl of `Debug` for `&f::Inner<T>`
+   = note: required for the cast to the object type `dyn Debug`
+   = note: this error originates in the derive macro `Debug` (in Nightly builds, run with -Z macro-backtrace for more info)
+help: consider restricting type parameter `T`
+   |
+LL |     struct Outer<T: f::Trait>(Inner<T>);
+   |                   ++++++++++
+
+error: aborting due to 5 previous errors
+
+For more information about this error, try `rustc --explain E0277`.
diff --git a/src/test/ui/type/issue-91268.rs b/src/test/ui/type/issue-91268.rs
new file mode 100644
index 00000000000..fd2733c1c54
--- /dev/null
+++ b/src/test/ui/type/issue-91268.rs
@@ -0,0 +1,9 @@
+// error-pattern: this file contains an unclosed delimiter
+// error-pattern: cannot find type `Å£` in this scope
+// error-pattern: parenthesized type parameters may only be used with a `Fn` trait
+// error-pattern: type arguments are not allowed for this type
+// error-pattern: mismatched types
+// ignore-tidy-trailing-newlines
+// `Å£` must be the last character in this file, it cannot be followed by a newline
+fn main() {
+    0: u8(Å£
\ No newline at end of file
diff --git a/src/test/ui/type/issue-91268.stderr b/src/test/ui/type/issue-91268.stderr
new file mode 100644
index 00000000000..2fe6ba6248c
--- /dev/null
+++ b/src/test/ui/type/issue-91268.stderr
@@ -0,0 +1,50 @@
+error: this file contains an unclosed delimiter
+  --> $DIR/issue-91268.rs:9:12
+   |
+LL | fn main() {
+   |           - unclosed delimiter
+LL |     0: u8(Å£
+   |          - ^
+   |          |
+   |          unclosed delimiter
+
+error: this file contains an unclosed delimiter
+  --> $DIR/issue-91268.rs:9:12
+   |
+LL | fn main() {
+   |           - unclosed delimiter
+LL |     0: u8(Å£
+   |          - ^
+   |          |
+   |          unclosed delimiter
+
+error[E0412]: cannot find type `Å£` in this scope
+  --> $DIR/issue-91268.rs:9:11
+   |
+LL |     0: u8(Å£
+   |           ^ expecting a type here because of type ascription
+
+error[E0214]: parenthesized type parameters may only be used with a `Fn` trait
+  --> $DIR/issue-91268.rs:9:8
+   |
+LL |     0: u8(Å£
+   |        ^^^^ only `Fn` traits may use parentheses
+
+error[E0109]: type arguments are not allowed for this type
+  --> $DIR/issue-91268.rs:9:11
+   |
+LL |     0: u8(Å£
+   |           ^ type argument not allowed
+
+error[E0308]: mismatched types
+  --> $DIR/issue-91268.rs:9:5
+   |
+LL | fn main() {
+   |           - expected `()` because of default return type
+LL |     0: u8(Å£
+   |     ^^^^^^^ expected `()`, found `u8`
+
+error: aborting due to 6 previous errors
+
+Some errors have detailed explanations: E0109, E0214, E0308, E0412.
+For more information about an error, try `rustc --explain E0109`.
diff --git a/src/test/ui/union/issue-81199.rs b/src/test/ui/union/issue-81199.rs
new file mode 100644
index 00000000000..628e7c6ed5d
--- /dev/null
+++ b/src/test/ui/union/issue-81199.rs
@@ -0,0 +1,21 @@
+#[repr(C)]
+union PtrRepr<T: ?Sized> {
+    const_ptr: *const T,
+    mut_ptr: *mut T,
+    components: PtrComponents<T>,
+    //~^ ERROR the trait bound
+}
+
+#[repr(C)]
+struct PtrComponents<T: Pointee + ?Sized> {
+    data_address: *const (),
+    metadata: <T as Pointee>::Metadata,
+}
+
+
+
+pub trait Pointee {
+   type Metadata;
+}
+
+fn main() {}
diff --git a/src/test/ui/union/issue-81199.stderr b/src/test/ui/union/issue-81199.stderr
new file mode 100644
index 00000000000..f26bfe3a0b0
--- /dev/null
+++ b/src/test/ui/union/issue-81199.stderr
@@ -0,0 +1,29 @@
+error[E0277]: the trait bound `T: Pointee` is not satisfied in `PtrComponents<T>`
+  --> $DIR/issue-81199.rs:5:17
+   |
+LL |     components: PtrComponents<T>,
+   |                 ^^^^^^^^^^^^^^^^ within `PtrComponents<T>`, the trait `Pointee` is not implemented for `T`
+   |
+note: required because it appears within the type `PtrComponents<T>`
+  --> $DIR/issue-81199.rs:10:8
+   |
+LL | struct PtrComponents<T: Pointee + ?Sized> {
+   |        ^^^^^^^^^^^^^
+   = note: no field of a union may have a dynamically sized type
+   = help: change the field's type to have a statically known size
+help: consider further restricting this bound
+   |
+LL | union PtrRepr<T: ?Sized + Pointee> {
+   |                         +++++++++
+help: borrowed types always have a statically known size
+   |
+LL |     components: &PtrComponents<T>,
+   |                 +
+help: the `Box` type always has a statically known size and allocates its contents in the heap
+   |
+LL |     components: Box<PtrComponents<T>>,
+   |                 ++++                +
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0277`.
diff --git a/src/tools/clippy/clippy_lints/src/future_not_send.rs b/src/tools/clippy/clippy_lints/src/future_not_send.rs
index a9297adb426..6b2ac985555 100644
--- a/src/tools/clippy/clippy_lints/src/future_not_send.rs
+++ b/src/tools/clippy/clippy_lints/src/future_not_send.rs
@@ -67,8 +67,8 @@ impl<'tcx> LateLintPass<'tcx> for FutureNotSend {
             let mut is_future = false;
             for &(p, _span) in preds {
                 let p = p.subst(cx.tcx, subst);
-                if let Some(trait_pred) = p.to_opt_poly_trait_pred() {
-                    if Some(trait_pred.skip_binder().trait_ref.def_id) == cx.tcx.lang_items().future_trait() {
+                if let Some(trait_ref) = p.to_opt_poly_trait_ref() {
+                    if Some(trait_ref.value.def_id()) == cx.tcx.lang_items().future_trait() {
                         is_future = true;
                         break;
                     }
diff --git a/src/tools/clippy/clippy_lints/src/redundant_clone.rs b/src/tools/clippy/clippy_lints/src/redundant_clone.rs
index f7711b6fe94..0eba6633ee1 100644
--- a/src/tools/clippy/clippy_lints/src/redundant_clone.rs
+++ b/src/tools/clippy/clippy_lints/src/redundant_clone.rs
@@ -15,7 +15,7 @@ use rustc_middle::mir::{
     Mutability,
 };
 use rustc_middle::ty::{self, fold::TypeVisitor, Ty, TyCtxt};
-use rustc_mir_dataflow::{Analysis, AnalysisDomain, GenKill, GenKillAnalysis, ResultsCursor};
+use rustc_mir_dataflow::{Analysis, AnalysisDomain, CallReturnPlaces, GenKill, GenKillAnalysis, ResultsCursor};
 use rustc_session::{declare_lint_pass, declare_tool_lint};
 use rustc_span::source_map::{BytePos, Span};
 use rustc_span::sym;
@@ -499,11 +499,9 @@ impl<'tcx> GenKillAnalysis<'tcx> for MaybeStorageLive {
 
     fn call_return_effect(
         &self,
-        _in_out: &mut impl GenKill<Self::Idx>,
+        _trans: &mut impl GenKill<Self::Idx>,
         _block: mir::BasicBlock,
-        _func: &mir::Operand<'tcx>,
-        _args: &[mir::Operand<'tcx>],
-        _return_place: mir::Place<'tcx>,
+        _return_places: CallReturnPlaces<'_, 'tcx>,
     ) {
         // Nothing to do when a call returns successfully
     }
diff --git a/src/tools/compiletest/src/runtest.rs b/src/tools/compiletest/src/runtest.rs
index 727eecbb732..4bf74c1508b 100644
--- a/src/tools/compiletest/src/runtest.rs
+++ b/src/tools/compiletest/src/runtest.rs
@@ -2219,12 +2219,12 @@ impl<'test> TestCx<'test> {
             self.check_rustdoc_test_option(proc_res);
         } else {
             let root = self.config.find_rust_src_root().unwrap();
-            let res = self.cmd2procres(
-                Command::new(&self.config.docck_python)
-                    .arg(root.join("src/etc/htmldocck.py"))
-                    .arg(&out_dir)
-                    .arg(&self.testpaths.file),
-            );
+            let mut cmd = Command::new(&self.config.docck_python);
+            cmd.arg(root.join("src/etc/htmldocck.py")).arg(&out_dir).arg(&self.testpaths.file);
+            if self.config.bless {
+                cmd.arg("--bless");
+            }
+            let res = self.cmd2procres(&mut cmd);
             if !res.status.success() {
                 self.fatal_proc_rec_with_ctx("htmldocck failed!", &res, |mut this| {
                     this.compare_to_default_rustdoc(&out_dir)
diff --git a/src/tools/rustfmt/.github/workflows/linux.yml b/src/tools/rustfmt/.github/workflows/linux.yml
index 6eaae69c708..db497941642 100644
--- a/src/tools/rustfmt/.github/workflows/linux.yml
+++ b/src/tools/rustfmt/.github/workflows/linux.yml
@@ -8,7 +8,9 @@ on:
 jobs:
   test:
     runs-on: ubuntu-latest
-    name: (${{ matrix.target }}, nightly)
+    name: (${{ matrix.target }}, ${{ matrix.cfg_release_channel }})
+    env:
+      CFG_RELEASE_CHANNEL: ${{ matrix.cfg_release_channel }}
     strategy:
       # https://help.github.com/en/actions/getting-started-with-github-actions/about-github-actions#usage-limits
       # There's a limit of 60 concurrent jobs across all repos in the rust-lang organization.
@@ -20,6 +22,7 @@ jobs:
         target: [
           x86_64-unknown-linux-gnu,
         ]
+        cfg_release_channel: [nightly, stable]
 
     steps:
     - name: checkout
diff --git a/src/tools/rustfmt/.github/workflows/mac.yml b/src/tools/rustfmt/.github/workflows/mac.yml
index 79e4f69163e..55e1cc9539b 100644
--- a/src/tools/rustfmt/.github/workflows/mac.yml
+++ b/src/tools/rustfmt/.github/workflows/mac.yml
@@ -10,13 +10,16 @@ jobs:
     # https://help.github.com/en/actions/automating-your-workflow-with-github-actions/virtual-environments-for-github-hosted-runners#supported-runners-and-hardware-resources
     # macOS Catalina 10.15
     runs-on: macos-latest
-    name: (${{ matrix.target }}, nightly)
+    name: (${{ matrix.target }}, ${{ matrix.cfg_release_channel }})
+    env:
+      CFG_RELEASE_CHANNEL: ${{ matrix.cfg_release_channel }}
     strategy:
       fail-fast: false
       matrix:
         target: [
           x86_64-apple-darwin,
         ]
+        cfg_release_channel: [nightly, stable]
 
     steps:
     - name: checkout
diff --git a/src/tools/rustfmt/.github/workflows/windows.yml b/src/tools/rustfmt/.github/workflows/windows.yml
index c05e8d4896a..dcb08b5412e 100644
--- a/src/tools/rustfmt/.github/workflows/windows.yml
+++ b/src/tools/rustfmt/.github/workflows/windows.yml
@@ -8,7 +8,9 @@ on:
 jobs:
   test:
     runs-on: windows-latest
-    name: (${{ matrix.target }}, nightly)
+    name: (${{ matrix.target }}, ${{ matrix.cfg_release_channel }})
+    env:
+      CFG_RELEASE_CHANNEL: ${{ matrix.cfg_release_channel }}
     strategy:
       # https://help.github.com/en/actions/getting-started-with-github-actions/about-github-actions#usage-limits
       # There's a limit of 60 concurrent jobs across all repos in the rust-lang organization.
@@ -23,6 +25,7 @@ jobs:
           x86_64-pc-windows-gnu,
           x86_64-pc-windows-msvc,
         ]
+        cfg_release_channel: [nightly, stable]
 
     steps:
     # The Windows runners have autocrlf enabled by default
diff --git a/src/tools/rustfmt/Configurations.md b/src/tools/rustfmt/Configurations.md
index 13826883d2f..a89fbe863e6 100644
--- a/src/tools/rustfmt/Configurations.md
+++ b/src/tools/rustfmt/Configurations.md
@@ -47,7 +47,7 @@ Where to put a binary operator when a binary expression goes multiline.
 
 - **Default value**: `"Front"`
 - **Possible values**: `"Front"`, `"Back"`
-- **Stable**: No (tracking issue: #3368)
+- **Stable**: No (tracking issue: [#3368](https://github.com/rust-lang/rustfmt/issues/3368))
 
 #### `"Front"` (default):
 
@@ -88,7 +88,7 @@ them, additional blank lines are inserted.
 
 - **Default value**: `0`
 - **Possible values**: *unsigned integer*
-- **Stable**: No (tracking issue: #3382)
+- **Stable**: No (tracking issue: [#3382](https://github.com/rust-lang/rustfmt/issues/3382))
 
 ### Example
 Original Code (rustfmt will not change it with the default value of `0`):
@@ -128,7 +128,7 @@ lines are found, they are trimmed down to match this integer.
 
 - **Default value**: `1`
 - **Possible values**: any non-negative integer
-- **Stable**: No (tracking issue: #3381)
+- **Stable**: No (tracking issue: [#3381](https://github.com/rust-lang/rustfmt/issues/3381))
 
 ### Example
 Original Code:
@@ -186,7 +186,7 @@ Brace style for items
 
 - **Default value**: `"SameLineWhere"`
 - **Possible values**: `"AlwaysNextLine"`, `"PreferSameLine"`, `"SameLineWhere"`
-- **Stable**: No (tracking issue: #3376)
+- **Stable**: No (tracking issue: [#3376](https://github.com/rust-lang/rustfmt/issues/3376))
 
 ### Functions
 
@@ -313,7 +313,7 @@ Whether to use colored output or not.
 
 - **Default value**: `"Auto"`
 - **Possible values**: "Auto", "Always", "Never"
-- **Stable**: No (tracking issue: #3385)
+- **Stable**: No (tracking issue: [#3385](https://github.com/rust-lang/rustfmt/issues/3385))
 
 ## `combine_control_expr`
 
@@ -321,7 +321,7 @@ Combine control expressions with function calls.
 
 - **Default value**: `true`
 - **Possible values**: `true`, `false`
-- **Stable**: No (tracking issue: #3369)
+- **Stable**: No (tracking issue: [#3369](https://github.com/rust-lang/rustfmt/issues/3369))
 
 #### `true` (default):
 
@@ -429,7 +429,7 @@ Maximum length of comments. No effect unless`wrap_comments = true`.
 
 - **Default value**: `80`
 - **Possible values**: any positive integer
-- **Stable**: No (tracking issue: #3349)
+- **Stable**: No (tracking issue: [#3349](https://github.com/rust-lang/rustfmt/issues/3349))
 
 **Note:** A value of `0` results in [`wrap_comments`](#wrap_comments) being applied regardless of a line's width.
 
@@ -452,7 +452,7 @@ Replace strings of _ wildcards by a single .. in tuple patterns
 
 - **Default value**: `false`
 - **Possible values**: `true`, `false`
-- **Stable**: No (tracking issue: #3384)
+- **Stable**: No (tracking issue: [#3384](https://github.com/rust-lang/rustfmt/issues/3384))
 
 #### `false` (default):
 
@@ -477,7 +477,7 @@ Brace style for control flow constructs
 
 - **Default value**: `"AlwaysSameLine"`
 - **Possible values**: `"AlwaysNextLine"`, `"AlwaysSameLine"`, `"ClosingNextLine"`
-- **Stable**: No (tracking issue: #3377)
+- **Stable**: No (tracking issue: [#3377](https://github.com/rust-lang/rustfmt/issues/3377))
 
 #### `"AlwaysSameLine"` (default):
 
@@ -551,7 +551,7 @@ Put empty-body functions and impls on a single line
 
 - **Default value**: `true`
 - **Possible values**: `true`, `false`
-- **Stable**: No (tracking issue: #3356)
+- **Stable**: No (tracking issue: [#3356](https://github.com/rust-lang/rustfmt/issues/3356))
 
 #### `true` (default):
 
@@ -584,7 +584,7 @@ doesn't get ignored when aligning.
 
 - **Default value** : 0
 - **Possible values**: any positive integer
-- **Stable**: No (tracking issue: #3372)
+- **Stable**: No (tracking issue: [#3372](https://github.com/rust-lang/rustfmt/issues/3372))
 
 #### `0` (default):
 
@@ -630,7 +630,7 @@ using a shorter name.
 
 - **Default value**: `false`
 - **Possible values**: `true`, `false`
-- **Stable**: No (tracking issue: #3391)
+- **Stable**: No (tracking issue: [#3391](https://github.com/rust-lang/rustfmt/issues/3391))
 
 See also [`max_width`](#max_width).
 
@@ -641,7 +641,7 @@ trailing whitespaces.
 
 - **Default value**: `false`
 - **Possible values**: `true`, `false`
-- **Stable**: No (tracking issue: #3392)
+- **Stable**: No (tracking issue: [#3392](https://github.com/rust-lang/rustfmt/issues/3392))
 
 ## `fn_args_layout`
 
@@ -771,7 +771,7 @@ Put single-expression functions on a single line
 
 - **Default value**: `false`
 - **Possible values**: `true`, `false`
-- **Stable**: No (tracking issue: #3358)
+- **Stable**: No (tracking issue: [#3358](https://github.com/rust-lang/rustfmt/issues/3358))
 
 #### `false` (default):
 
@@ -832,7 +832,7 @@ Force multiline closure and match arm bodies to be wrapped in a block
 
 - **Default value**: `false`
 - **Possible values**: `false`, `true`
-- **Stable**: No (tracking issue: #3374)
+- **Stable**: No (tracking issue: [#3374](https://github.com/rust-lang/rustfmt/issues/3374))
 
 #### `false` (default):
 
@@ -881,7 +881,7 @@ Format code snippet included in doc comments.
 
 - **Default value**: `false`
 - **Possible values**: `true`, `false`
-- **Stable**: No (tracking issue: #3348)
+- **Stable**: No (tracking issue: [#3348](https://github.com/rust-lang/rustfmt/issues/3348))
 
 #### `false` (default):
 
@@ -933,7 +933,7 @@ if any of the first five lines contains `@generated` marker.
 
 - **Default value**: `false`
 - **Possible values**: `true`, `false`
-- **Stable**: No
+- **Stable**: No (tracking issue: [#5080](https://github.com/rust-lang/rustfmt/issues/5080))
 
 ## `format_macro_matchers`
 
@@ -941,7 +941,7 @@ Format the metavariable matching patterns in macros.
 
 - **Default value**: `false`
 - **Possible values**: `true`, `false`
-- **Stable**: No (tracking issue: #3354)
+- **Stable**: No (tracking issue: [#3354](https://github.com/rust-lang/rustfmt/issues/3354))
 
 #### `false` (default):
 
@@ -978,7 +978,7 @@ Format the bodies of macros.
 
 - **Default value**: `true`
 - **Possible values**: `true`, `false`
-- **Stable**: No (tracking issue: #3355)
+- **Stable**: No (tracking issue: [#3355](https://github.com/rust-lang/rustfmt/issues/3355))
 
 #### `true` (default):
 
@@ -1011,7 +1011,7 @@ Format string literals where necessary
 
 - **Default value**: `false`
 - **Possible values**: `true`, `false`
-- **Stable**: No (tracking issue: #3353)
+- **Stable**: No (tracking issue: [#3353](https://github.com/rust-lang/rustfmt/issues/3353))
 
 #### `false` (default):
 
@@ -1064,7 +1064,7 @@ Control the case of the letters in hexadecimal literal values
 
 - **Default value**: `Preserve`
 - **Possible values**: `Upper`, `Lower`
-- **Stable**: No
+- **Stable**: No (tracking issue: [#5081](https://github.com/rust-lang/rustfmt/issues/5081))
 
 ## `hide_parse_errors`
 
@@ -1072,7 +1072,7 @@ Do not show parse errors if the parser failed to parse files.
 
 - **Default value**: `false`
 - **Possible values**: `true`, `false`
-- **Stable**: No (tracking issue: #3390)
+- **Stable**: No (tracking issue: [#3390](https://github.com/rust-lang/rustfmt/issues/3390))
 
 ## `ignore`
 
@@ -1081,7 +1081,7 @@ The pattern format is the same as [.gitignore](https://git-scm.com/docs/gitignor
 
 - **Default value**: format every file
 - **Possible values**: See an example below
-- **Stable**: No (tracking issue: #3395)
+- **Stable**: No (tracking issue: [#3395](https://github.com/rust-lang/rustfmt/issues/3395))
 
 ### Example
 
@@ -1114,7 +1114,7 @@ Indent style of imports
 
 - **Default Value**: `"Block"`
 - **Possible values**: `"Block"`, `"Visual"`
-- **Stable**: No (tracking issue: #3360)
+- **Stable**: No (tracking issue: [#3360](https://github.com/rust-lang/rustfmt/issues/3360))
 
 #### `"Block"` (default):
 
@@ -1140,7 +1140,7 @@ Item layout inside a imports block
 
 - **Default value**: "Mixed"
 - **Possible values**: "Horizontal", "HorizontalVertical", "Mixed", "Vertical"
-- **Stable**: No (tracking issue: #3361)
+- **Stable**: No (tracking issue: [#3361](https://github.com/rust-lang/rustfmt/issues/3361))
 
 #### `"Mixed"` (default):
 
@@ -1203,7 +1203,7 @@ Indent on expressions or items.
 
 - **Default value**: `"Block"`
 - **Possible values**: `"Block"`, `"Visual"`
-- **Stable**: No (tracking issue: #3346)
+- **Stable**: No (tracking issue: [#3346](https://github.com/rust-lang/rustfmt/issues/3346))
 
 ### Array
 
@@ -1456,7 +1456,7 @@ Write an item and its attribute on the same line if their combined width is belo
 
 - **Default value**: 0
 - **Possible values**: any positive integer
-- **Stable**: No (tracking issue: #3343)
+- **Stable**: No (tracking issue: [#3343](https://github.com/rust-lang/rustfmt/issues/3343))
 
 ### Example
 
@@ -1477,7 +1477,7 @@ Check whether beginnings of files match a license template.
 
 - **Default value**: `""`
 - **Possible values**: path to a license template file
-- **Stable**: No (tracking issue: #3352)
+- **Stable**: No (tracking issue: [#3352](https://github.com/rust-lang/rustfmt/issues/3352))
 
 A license template is a plain text file which is matched literally against the
 beginning of each source file, except for `{}`-delimited blocks, which are
@@ -1499,7 +1499,7 @@ The Style Guide requires that bodies are block wrapped by default if a line brea
 
 - **Default value**: `true`
 - **Possible values**: `true`, `false`
-- **Stable**: No (tracking issue: #3373)
+- **Stable**: No (tracking issue: [#3373](https://github.com/rust-lang/rustfmt/issues/3373))
 
 #### `true` (default):
 
@@ -1701,7 +1701,7 @@ How imports should be grouped into `use` statements. Imports will be merged or s
 
 - **Default value**: `Preserve`
 - **Possible values**: `Preserve`, `Crate`, `Module`, `Item`, `One`
-- **Stable**: No
+- **Stable**: No (tracking issue: [#4991](https://github.com/rust-lang/rustfmt/issues/4991))
 
 #### `Preserve` (default):
 
@@ -1826,7 +1826,7 @@ Convert /* */ comments to // comments where possible
 
 - **Default value**: `false`
 - **Possible values**: `true`, `false`
-- **Stable**: No (tracking issue: #3350)
+- **Stable**: No (tracking issue: [#3350](https://github.com/rust-lang/rustfmt/issues/3350))
 
 #### `false` (default):
 
@@ -1854,7 +1854,7 @@ Convert `#![doc]` and `#[doc]` attributes to `//!` and `///` doc comments.
 
 - **Default value**: `false`
 - **Possible values**: `true`, `false`
-- **Stable**: No (tracking issue: #3351)
+- **Stable**: No (tracking issue: [#3351](https://github.com/rust-lang/rustfmt/issues/3351))
 
 #### `false` (default):
 
@@ -1885,7 +1885,7 @@ instead of being indented on a new line.
 
 - **Default value**: `false`
 - **Possible values**: `true`, `false`
-- **Stable**: No (tracking issue: #3370)
+- **Stable**: No (tracking issue: [#3370](https://github.com/rust-lang/rustfmt/issues/3370))
 
 #### `false` (default):
 
@@ -1992,7 +1992,7 @@ Reorder impl items. `type` and `const` are put first, then macros and methods.
 
 - **Default value**: `false`
 - **Possible values**: `true`, `false`
-- **Stable**: No (tracking issue: #3363)
+- **Stable**: No (tracking issue: [#3363](https://github.com/rust-lang/rustfmt/issues/3363))
 
 #### `false` (default)
 
@@ -2063,7 +2063,7 @@ Controls the strategy for how imports are grouped together.
 
 - **Default value**: `Preserve`
 - **Possible values**: `Preserve`, `StdExternalCrate`, `One`
-- **Stable**: No
+- **Stable**: No (tracking issue: [#5083](https://github.com/rust-lang/rustfmt/issues/5083))
 
 #### `Preserve` (default):
 
@@ -2166,7 +2166,7 @@ Report `FIXME` items in comments.
 
 - **Default value**: `"Never"`
 - **Possible values**: `"Always"`, `"Unnumbered"`, `"Never"`
-- **Stable**: No (tracking issue: #3394)
+- **Stable**: No (tracking issue: [#3394](https://github.com/rust-lang/rustfmt/issues/3394))
 
 Warns about any comments containing `FIXME` in them when set to `"Always"`. If
 it contains a `#X` (with `X` being a number) in parentheses following the
@@ -2181,7 +2181,7 @@ Report `TODO` items in comments.
 
 - **Default value**: `"Never"`
 - **Possible values**: `"Always"`, `"Unnumbered"`, `"Never"`
-- **Stable**: No (tracking issue: #3393)
+- **Stable**: No (tracking issue: [#3393](https://github.com/rust-lang/rustfmt/issues/3393))
 
 Warns about any comments containing `TODO` in them when set to `"Always"`. If
 it contains a `#X` (with `X` being a number) in parentheses following the
@@ -2196,7 +2196,7 @@ specific version of rustfmt is used in your CI, use this option.
 
 - **Default value**: `CARGO_PKG_VERSION`
 - **Possible values**: any published version (e.g. `"0.3.8"`)
-- **Stable**: No (tracking issue: #3386)
+- **Stable**: No (tracking issue: [#3386](https://github.com/rust-lang/rustfmt/issues/3386))
 
 ## `skip_children`
 
@@ -2204,7 +2204,7 @@ Don't reformat out of line modules
 
 - **Default value**: `false`
 - **Possible values**: `true`, `false`
-- **Stable**: No (tracking issue: #3389)
+- **Stable**: No (tracking issue: [#3389](https://github.com/rust-lang/rustfmt/issues/3386))
 
 ## `single_line_if_else_max_width`
 
@@ -2224,7 +2224,7 @@ Leave a space after the colon.
 
 - **Default value**: `true`
 - **Possible values**: `true`, `false`
-- **Stable**: No (tracking issue: #3366)
+- **Stable**: No (tracking issue: [#3366](https://github.com/rust-lang/rustfmt/issues/3366))
 
 #### `true` (default):
 
@@ -2256,7 +2256,7 @@ Leave a space before the colon.
 
 - **Default value**: `false`
 - **Possible values**: `true`, `false`
-- **Stable**: No (tracking issue: #3365)
+- **Stable**: No (tracking issue: [#3365](https://github.com/rust-lang/rustfmt/issues/3365))
 
 #### `false` (default):
 
@@ -2288,7 +2288,7 @@ Put spaces around the .., ..=, and ... range operators
 
 - **Default value**: `false`
 - **Possible values**: `true`, `false`
-- **Stable**: No (tracking issue: #3367)
+- **Stable**: No (tracking issue: [#3367](https://github.com/rust-lang/rustfmt/issues/3367))
 
 #### `false` (default):
 
@@ -2344,7 +2344,7 @@ The maximum diff of width between struct fields to be aligned with each other.
 
 - **Default value** : 0
 - **Possible values**: any non-negative integer
-- **Stable**: No (tracking issue: #3371)
+- **Stable**: No (tracking issue: [#3371](https://github.com/rust-lang/rustfmt/issues/3371))
 
 #### `0` (default):
 
@@ -2372,7 +2372,7 @@ Put small struct literals on a single line
 
 - **Default value**: `true`
 - **Possible values**: `true`, `false`
-- **Stable**: No (tracking issue: #3357)
+- **Stable**: No (tracking issue: [#3357](https://github.com/rust-lang/rustfmt/issues/3357))
 
 #### `true` (default):
 
@@ -2460,7 +2460,7 @@ How to handle trailing commas for lists
 
 - **Default value**: `"Vertical"`
 - **Possible values**: `"Always"`, `"Never"`, `"Vertical"`
-- **Stable**: No (tracking issue: #3379)
+- **Stable**: No (tracking issue: [#3379](https://github.com/rust-lang/rustfmt/issues/3379))
 
 #### `"Vertical"` (default):
 
@@ -2518,7 +2518,7 @@ Add trailing semicolon after break, continue and return
 
 - **Default value**: `true`
 - **Possible values**: `true`, `false`
-- **Stable**: No (tracking issue: #3378)
+- **Stable**: No (tracking issue: [#3378](https://github.com/rust-lang/rustfmt/issues/3378))
 
 #### `true` (default):
 ```rust
@@ -2540,7 +2540,7 @@ Determines if `+` or `=` are wrapped in spaces in the punctuation of types
 
 - **Default value**: `"Wide"`
 - **Possible values**: `"Compressed"`, `"Wide"`
-- **Stable**: No (tracking issue: #3364)
+- **Stable**: No (tracking issue: [#3364](https://github.com/rust-lang/rustfmt/issues/3364))
 
 #### `"Wide"` (default):
 
@@ -2564,7 +2564,7 @@ Enable unstable features on the unstable channel.
 
 - **Default value**: `false`
 - **Possible values**: `true`, `false`
-- **Stable**: No (tracking issue: #3387)
+- **Stable**: No (tracking issue: [#3387](https://github.com/rust-lang/rustfmt/issues/3387))
 
 ## `use_field_init_shorthand`
 
@@ -2779,7 +2779,7 @@ version number.
 
 - **Default value**: `One`
 - **Possible values**: `One`, `Two`
-- **Stable**: No (tracking issue: #3383)
+- **Stable**: No (tracking issue: [#3383](https://github.com/rust-lang/rustfmt/issues/3383))
 
 ### Example
 
@@ -2793,7 +2793,7 @@ Forces the `where` clause to be laid out on a single line.
 
 - **Default value**: `false`
 - **Possible values**: `true`, `false`
-- **Stable**: No (tracking issue: #3359)
+- **Stable**: No (tracking issue: [#3359](https://github.com/rust-lang/rustfmt/issues/3359))
 
 #### `false` (default):
 
@@ -2825,7 +2825,7 @@ Break comments to fit on the line
 
 - **Default value**: `false`
 - **Possible values**: `true`, `false`
-- **Stable**: No (tracking issue: #3347)
+- **Stable**: No (tracking issue: [#3347](https://github.com/rust-lang/rustfmt/issues/3347))
 
 #### `false` (default):
 
diff --git a/src/tools/rustfmt/README.md b/src/tools/rustfmt/README.md
index b3d21e6fb87..b3a968f0c04 100644
--- a/src/tools/rustfmt/README.md
+++ b/src/tools/rustfmt/README.md
@@ -48,12 +48,11 @@ cargo +nightly fmt
 ## Limitations
 
 Rustfmt tries to work on as much Rust code as possible. Sometimes, the code
-doesn't even need to compile! As we approach a 1.0 release we are also looking
-to limit areas of instability; in particular, post-1.0, the formatting of most
-code should not change as Rustfmt improves. However, there are some things that
-Rustfmt can't do or can't do well (and thus where formatting might change
-significantly, even post-1.0). We would like to reduce the list of limitations
-over time.
+doesn't even need to compile! In general, we are looking to limit areas of
+instability; in particular, post-1.0, the formatting of most code should not
+change as Rustfmt improves. However, there are some things that Rustfmt can't
+do or can't do well (and thus where formatting might change significantly,
+even post-1.0). We would like to reduce the list of limitations over time.
 
 The following list enumerates areas where Rustfmt does not work or where the
 stability guarantees do not apply (we don't make a distinction between the two
diff --git a/src/tools/rustfmt/config_proc_macro/src/lib.rs b/src/tools/rustfmt/config_proc_macro/src/lib.rs
index 78e7e098ed9..51301821319 100644
--- a/src/tools/rustfmt/config_proc_macro/src/lib.rs
+++ b/src/tools/rustfmt/config_proc_macro/src/lib.rs
@@ -8,6 +8,8 @@ mod item_enum;
 mod item_struct;
 mod utils;
 
+use std::str::FromStr;
+
 use proc_macro::TokenStream;
 use syn::parse_macro_input;
 
@@ -23,3 +25,43 @@ pub fn config_type(_args: TokenStream, input: TokenStream) -> TokenStream {
 
     TokenStream::from(output)
 }
+
+/// Used to conditionally output the TokenStream for tests that need to be run on nightly only.
+///
+/// ```rust
+/// #[nightly_only_test]
+/// #[test]
+/// fn test_needs_nightly_rustfmt() {
+///   assert!(true);
+/// }
+/// ```
+#[proc_macro_attribute]
+pub fn nightly_only_test(_args: TokenStream, input: TokenStream) -> TokenStream {
+    // if CFG_RELEASE_CHANNEL is not set we default to nightly, hence why the default is true
+    if option_env!("CFG_RELEASE_CHANNEL").map_or(true, |c| c == "nightly" || c == "dev") {
+        input
+    } else {
+        // output an empty token stream if CFG_RELEASE_CHANNEL is not set to "nightly" or "dev"
+        TokenStream::from_str("").unwrap()
+    }
+}
+
+/// Used to conditionally output the TokenStream for tests that need to be run on stable only.
+///
+/// ```rust
+/// #[stable_only_test]
+/// #[test]
+/// fn test_needs_stable_rustfmt() {
+///   assert!(true);
+/// }
+/// ```
+#[proc_macro_attribute]
+pub fn stable_only_test(_args: TokenStream, input: TokenStream) -> TokenStream {
+    // if CFG_RELEASE_CHANNEL is not set we default to nightly, hence why the default is false
+    if option_env!("CFG_RELEASE_CHANNEL").map_or(false, |c| c == "stable") {
+        input
+    } else {
+        // output an empty token stream if CFG_RELEASE_CHANNEL is not set or is not 'stable'
+        TokenStream::from_str("").unwrap()
+    }
+}
diff --git a/src/tools/rustfmt/src/comment.rs b/src/tools/rustfmt/src/comment.rs
index 7b76c232937..0f850b9b2f2 100644
--- a/src/tools/rustfmt/src/comment.rs
+++ b/src/tools/rustfmt/src/comment.rs
@@ -3,6 +3,8 @@
 use std::{self, borrow::Cow, iter};
 
 use itertools::{multipeek, MultiPeek};
+use lazy_static::lazy_static;
+use regex::Regex;
 use rustc_span::Span;
 
 use crate::config::Config;
@@ -15,6 +17,17 @@ use crate::utils::{
 };
 use crate::{ErrorKind, FormattingError};
 
+lazy_static! {
+    /// A regex matching reference doc links.
+    ///
+    /// ```markdown
+    /// /// An [example].
+    /// ///
+    /// /// [example]: this::is::a::link
+    /// ```
+    static ref REFERENCE_LINK_URL: Regex = Regex::new(r"^\[.+\]\s?:").unwrap();
+}
+
 fn is_custom_comment(comment: &str) -> bool {
     if !comment.starts_with("//") {
         false
@@ -506,6 +519,7 @@ struct CommentRewrite<'a> {
     opener: String,
     closer: String,
     line_start: String,
+    style: CommentStyle<'a>,
 }
 
 impl<'a> CommentRewrite<'a> {
@@ -515,10 +529,14 @@ impl<'a> CommentRewrite<'a> {
         shape: Shape,
         config: &'a Config,
     ) -> CommentRewrite<'a> {
-        let (opener, closer, line_start) = if block_style {
-            CommentStyle::SingleBullet.to_str_tuplet()
+        let ((opener, closer, line_start), style) = if block_style {
+            (
+                CommentStyle::SingleBullet.to_str_tuplet(),
+                CommentStyle::SingleBullet,
+            )
         } else {
-            comment_style(orig, config.normalize_comments()).to_str_tuplet()
+            let style = comment_style(orig, config.normalize_comments());
+            (style.to_str_tuplet(), style)
         };
 
         let max_width = shape
@@ -551,6 +569,7 @@ impl<'a> CommentRewrite<'a> {
             opener: opener.to_owned(),
             closer: closer.to_owned(),
             line_start: line_start.to_owned(),
+            style,
         };
         cr.result.push_str(opener);
         cr
@@ -570,6 +589,15 @@ impl<'a> CommentRewrite<'a> {
         result
     }
 
+    /// Check if any characters were written to the result buffer after the start of the comment.
+    /// when calling [`CommentRewrite::new()`] the result buffer is initiazlied with the opening
+    /// characters for the comment.
+    fn buffer_contains_comment(&self) -> bool {
+        // if self.result.len() < self.opener.len() then an empty comment is in the buffer
+        // if self.result.len() > self.opener.len() then a non empty comment is in the buffer
+        self.result.len() != self.opener.len()
+    }
+
     fn finish(mut self) -> String {
         if !self.code_block_buffer.is_empty() {
             // There is a code block that is not properly enclosed by backticks.
@@ -585,7 +613,12 @@ impl<'a> CommentRewrite<'a> {
             // the last few lines are part of an itemized block
             self.fmt.shape = Shape::legacy(self.max_width, self.fmt_indent);
             let item_fmt = ib.create_string_format(&self.fmt);
-            self.result.push_str(&self.comment_line_separator);
+
+            // only push a comment_line_separator for ItemizedBlocks if the comment is not empty
+            if self.buffer_contains_comment() {
+                self.result.push_str(&self.comment_line_separator);
+            }
+
             self.result.push_str(&ib.opener);
             match rewrite_string(
                 &ib.trimmed_block_as_string(),
@@ -619,7 +652,13 @@ impl<'a> CommentRewrite<'a> {
         line: &'a str,
         has_leading_whitespace: bool,
     ) -> bool {
-        let is_last = i == count_newlines(orig);
+        let num_newlines = count_newlines(orig);
+        let is_last = i == num_newlines;
+        let needs_new_comment_line = if self.style.is_block_comment() {
+            num_newlines > 0 || self.buffer_contains_comment()
+        } else {
+            self.buffer_contains_comment()
+        };
 
         if let Some(ref mut ib) = self.item_block {
             if ib.add_line(line) {
@@ -628,7 +667,12 @@ impl<'a> CommentRewrite<'a> {
             self.is_prev_line_multi_line = false;
             self.fmt.shape = Shape::legacy(self.max_width, self.fmt_indent);
             let item_fmt = ib.create_string_format(&self.fmt);
-            self.result.push_str(&self.comment_line_separator);
+
+            // only push a comment_line_separator if we need to start a new comment line
+            if needs_new_comment_line {
+                self.result.push_str(&self.comment_line_separator);
+            }
+
             self.result.push_str(&ib.opener);
             match rewrite_string(
                 &ib.trimmed_block_as_string(),
@@ -842,7 +886,11 @@ fn trim_custom_comment_prefix(s: &str) -> String {
 /// Returns `true` if the given string MAY include URLs or alike.
 fn has_url(s: &str) -> bool {
     // This function may return false positive, but should get its job done in most cases.
-    s.contains("https://") || s.contains("http://") || s.contains("ftp://") || s.contains("file://")
+    s.contains("https://")
+        || s.contains("http://")
+        || s.contains("ftp://")
+        || s.contains("file://")
+        || REFERENCE_LINK_URL.is_match(s)
 }
 
 /// Given the span, rewrite the missing comment inside it if available.
diff --git a/src/tools/rustfmt/src/config/mod.rs b/src/tools/rustfmt/src/config/mod.rs
index c5419d860c9..5dbe532ac38 100644
--- a/src/tools/rustfmt/src/config/mod.rs
+++ b/src/tools/rustfmt/src/config/mod.rs
@@ -405,6 +405,8 @@ mod test {
     use super::*;
     use std::str;
 
+    use rustfmt_config_proc_macro::{nightly_only_test, stable_only_test};
+
     #[allow(dead_code)]
     mod mock {
         use super::super::*;
@@ -525,21 +527,17 @@ mod test {
         assert!(config.license_template.is_none());
     }
 
+    #[nightly_only_test]
     #[test]
     fn test_valid_license_template_path() {
-        if !crate::is_nightly_channel!() {
-            return;
-        }
         let toml = r#"license_template_path = "tests/license-template/lt.txt""#;
         let config = Config::from_toml(toml, Path::new("")).unwrap();
         assert!(config.license_template.is_some());
     }
 
+    #[nightly_only_test]
     #[test]
     fn test_override_existing_license_with_no_license() {
-        if !crate::is_nightly_channel!() {
-            return;
-        }
         let toml = r#"license_template_path = "tests/license-template/lt.txt""#;
         let mut config = Config::from_toml(toml, Path::new("")).unwrap();
         assert!(config.license_template.is_some());
@@ -634,48 +632,42 @@ make_backup = false
         assert_eq!(&toml, &default_config);
     }
 
-    // FIXME(#2183): these tests cannot be run in parallel because they use env vars.
-    // #[test]
-    // fn test_as_not_nightly_channel() {
-    //     let mut config = Config::default();
-    //     assert_eq!(config.was_set().unstable_features(), false);
-    //     config.set().unstable_features(true);
-    //     assert_eq!(config.was_set().unstable_features(), false);
-    // }
-
-    // #[test]
-    // fn test_as_nightly_channel() {
-    //     let v = ::std::env::var("CFG_RELEASE_CHANNEL").unwrap_or(String::from(""));
-    //     ::std::env::set_var("CFG_RELEASE_CHANNEL", "nightly");
-    //     let mut config = Config::default();
-    //     config.set().unstable_features(true);
-    //     assert_eq!(config.was_set().unstable_features(), false);
-    //     config.set().unstable_features(true);
-    //     assert_eq!(config.unstable_features(), true);
-    //     ::std::env::set_var("CFG_RELEASE_CHANNEL", v);
-    // }
-
-    // #[test]
-    // fn test_unstable_from_toml() {
-    //     let mut config = Config::from_toml("unstable_features = true").unwrap();
-    //     assert_eq!(config.was_set().unstable_features(), false);
-    //     let v = ::std::env::var("CFG_RELEASE_CHANNEL").unwrap_or(String::from(""));
-    //     ::std::env::set_var("CFG_RELEASE_CHANNEL", "nightly");
-    //     config = Config::from_toml("unstable_features = true").unwrap();
-    //     assert_eq!(config.was_set().unstable_features(), true);
-    //     assert_eq!(config.unstable_features(), true);
-    //     ::std::env::set_var("CFG_RELEASE_CHANNEL", v);
-    // }
+    #[stable_only_test]
+    #[test]
+    fn test_as_not_nightly_channel() {
+        let mut config = Config::default();
+        assert_eq!(config.was_set().unstable_features(), false);
+        config.set().unstable_features(true);
+        assert_eq!(config.was_set().unstable_features(), false);
+    }
+
+    #[nightly_only_test]
+    #[test]
+    fn test_as_nightly_channel() {
+        let mut config = Config::default();
+        config.set().unstable_features(true);
+        // When we don't set the config from toml or command line options it
+        // doesn't get marked as set by the user.
+        assert_eq!(config.was_set().unstable_features(), false);
+        config.set().unstable_features(true);
+        assert_eq!(config.unstable_features(), true);
+    }
+
+    #[nightly_only_test]
+    #[test]
+    fn test_unstable_from_toml() {
+        let config = Config::from_toml("unstable_features = true", Path::new("")).unwrap();
+        assert_eq!(config.was_set().unstable_features(), true);
+        assert_eq!(config.unstable_features(), true);
+    }
 
     #[cfg(test)]
     mod deprecated_option_merge_imports {
         use super::*;
 
+        #[nightly_only_test]
         #[test]
         fn test_old_option_set() {
-            if !crate::is_nightly_channel!() {
-                return;
-            }
             let toml = r#"
                 unstable_features = true
                 merge_imports = true
@@ -684,11 +676,9 @@ make_backup = false
             assert_eq!(config.imports_granularity(), ImportGranularity::Crate);
         }
 
+        #[nightly_only_test]
         #[test]
         fn test_both_set() {
-            if !crate::is_nightly_channel!() {
-                return;
-            }
             let toml = r#"
                 unstable_features = true
                 merge_imports = true
@@ -698,11 +688,9 @@ make_backup = false
             assert_eq!(config.imports_granularity(), ImportGranularity::Preserve);
         }
 
+        #[nightly_only_test]
         #[test]
         fn test_new_overridden() {
-            if !crate::is_nightly_channel!() {
-                return;
-            }
             let toml = r#"
                 unstable_features = true
                 merge_imports = true
@@ -712,11 +700,9 @@ make_backup = false
             assert_eq!(config.imports_granularity(), ImportGranularity::Preserve);
         }
 
+        #[nightly_only_test]
         #[test]
         fn test_old_overridden() {
-            if !crate::is_nightly_channel!() {
-                return;
-            }
             let toml = r#"
                 unstable_features = true
                 imports_granularity = "Module"
diff --git a/src/tools/rustfmt/src/expr.rs b/src/tools/rustfmt/src/expr.rs
index 58942e442de..5fd86c1a4ea 100644
--- a/src/tools/rustfmt/src/expr.rs
+++ b/src/tools/rustfmt/src/expr.rs
@@ -196,9 +196,10 @@ pub(crate) fn format_expr(
                 capture, is_async, movability, fn_decl, body, expr.span, context, shape,
             )
         }
-        ast::ExprKind::Try(..) | ast::ExprKind::Field(..) | ast::ExprKind::MethodCall(..) => {
-            rewrite_chain(expr, context, shape)
-        }
+        ast::ExprKind::Try(..)
+        | ast::ExprKind::Field(..)
+        | ast::ExprKind::MethodCall(..)
+        | ast::ExprKind::Await(_) => rewrite_chain(expr, context, shape),
         ast::ExprKind::MacCall(ref mac) => {
             rewrite_macro(mac, None, context, shape, MacroPosition::Expression).or_else(|| {
                 wrap_str(
@@ -377,7 +378,6 @@ pub(crate) fn format_expr(
                 ))
             }
         }
-        ast::ExprKind::Await(_) => rewrite_chain(expr, context, shape),
         ast::ExprKind::Underscore => Some("_".to_owned()),
         ast::ExprKind::Err => None,
     };
@@ -829,6 +829,7 @@ impl<'a> ControlFlow<'a> {
                 &format!("{}{}{}", matcher, pat_string, self.connector),
                 expr,
                 cond_shape,
+                &RhsAssignKind::Expr(&expr.kind, expr.span),
                 RhsTactics::Default,
                 comments_span,
                 true,
@@ -1839,6 +1840,34 @@ fn rewrite_unary_op(
     rewrite_unary_prefix(context, ast::UnOp::to_string(op), expr, shape)
 }
 
+pub(crate) enum RhsAssignKind<'ast> {
+    Expr(&'ast ast::ExprKind, Span),
+    Bounds,
+    Ty,
+}
+
+impl<'ast> RhsAssignKind<'ast> {
+    // TODO(calebcartwright)
+    // Preemptive addition for handling RHS with chains, not yet utilized.
+    // It may make more sense to construct the chain first and then check
+    // whether there are actually chain elements.
+    #[allow(dead_code)]
+    fn is_chain(&self) -> bool {
+        match self {
+            RhsAssignKind::Expr(kind, _) => {
+                matches!(
+                    kind,
+                    ast::ExprKind::Try(..)
+                        | ast::ExprKind::Field(..)
+                        | ast::ExprKind::MethodCall(..)
+                        | ast::ExprKind::Await(_)
+                )
+            }
+            _ => false,
+        }
+    }
+}
+
 fn rewrite_assignment(
     context: &RewriteContext<'_>,
     lhs: &ast::Expr,
@@ -1855,7 +1884,13 @@ fn rewrite_assignment(
     let lhs_shape = shape.sub_width(operator_str.len() + 1)?;
     let lhs_str = format!("{} {}", lhs.rewrite(context, lhs_shape)?, operator_str);
 
-    rewrite_assign_rhs(context, lhs_str, rhs, shape)
+    rewrite_assign_rhs(
+        context,
+        lhs_str,
+        rhs,
+        &RhsAssignKind::Expr(&rhs.kind, rhs.span),
+        shape,
+    )
 }
 
 /// Controls where to put the rhs.
@@ -1876,9 +1911,10 @@ pub(crate) fn rewrite_assign_rhs<S: Into<String>, R: Rewrite>(
     context: &RewriteContext<'_>,
     lhs: S,
     ex: &R,
+    rhs_kind: &RhsAssignKind<'_>,
     shape: Shape,
 ) -> Option<String> {
-    rewrite_assign_rhs_with(context, lhs, ex, shape, RhsTactics::Default)
+    rewrite_assign_rhs_with(context, lhs, ex, shape, rhs_kind, RhsTactics::Default)
 }
 
 pub(crate) fn rewrite_assign_rhs_expr<R: Rewrite>(
@@ -1886,6 +1922,7 @@ pub(crate) fn rewrite_assign_rhs_expr<R: Rewrite>(
     lhs: &str,
     ex: &R,
     shape: Shape,
+    rhs_kind: &RhsAssignKind<'_>,
     rhs_tactics: RhsTactics,
 ) -> Option<String> {
     let last_line_width = last_line_width(lhs).saturating_sub(if lhs.contains('\n') {
@@ -1910,6 +1947,7 @@ pub(crate) fn rewrite_assign_rhs_expr<R: Rewrite>(
         ex,
         orig_shape,
         ex.rewrite(context, orig_shape),
+        rhs_kind,
         rhs_tactics,
         has_rhs_comment,
     )
@@ -1920,10 +1958,11 @@ pub(crate) fn rewrite_assign_rhs_with<S: Into<String>, R: Rewrite>(
     lhs: S,
     ex: &R,
     shape: Shape,
+    rhs_kind: &RhsAssignKind<'_>,
     rhs_tactics: RhsTactics,
 ) -> Option<String> {
     let lhs = lhs.into();
-    let rhs = rewrite_assign_rhs_expr(context, &lhs, ex, shape, rhs_tactics)?;
+    let rhs = rewrite_assign_rhs_expr(context, &lhs, ex, shape, rhs_kind, rhs_tactics)?;
     Some(lhs + &rhs)
 }
 
@@ -1932,6 +1971,7 @@ pub(crate) fn rewrite_assign_rhs_with_comments<S: Into<String>, R: Rewrite>(
     lhs: S,
     ex: &R,
     shape: Shape,
+    rhs_kind: &RhsAssignKind<'_>,
     rhs_tactics: RhsTactics,
     between_span: Span,
     allow_extend: bool,
@@ -1943,7 +1983,7 @@ pub(crate) fn rewrite_assign_rhs_with_comments<S: Into<String>, R: Rewrite>(
     } else {
         shape
     };
-    let rhs = rewrite_assign_rhs_expr(context, &lhs, ex, shape, rhs_tactics)?;
+    let rhs = rewrite_assign_rhs_expr(context, &lhs, ex, shape, rhs_kind, rhs_tactics)?;
 
     if contains_comment {
         let rhs = rhs.trim_start();
@@ -1958,6 +1998,7 @@ fn choose_rhs<R: Rewrite>(
     expr: &R,
     shape: Shape,
     orig_rhs: Option<String>,
+    _rhs_kind: &RhsAssignKind<'_>,
     rhs_tactics: RhsTactics,
     has_rhs_comment: bool,
 ) -> Option<String> {
diff --git a/src/tools/rustfmt/src/ignore_path.rs b/src/tools/rustfmt/src/ignore_path.rs
index d8974e12b8f..7738eee0a76 100644
--- a/src/tools/rustfmt/src/ignore_path.rs
+++ b/src/tools/rustfmt/src/ignore_path.rs
@@ -37,21 +37,17 @@ mod test {
     use crate::config::{Config, FileName};
     use crate::ignore_path::IgnorePathSet;
 
+    use rustfmt_config_proc_macro::nightly_only_test;
+
+    #[nightly_only_test]
     #[test]
     fn test_ignore_path_set() {
-        match option_env!("CFG_RELEASE_CHANNEL") {
-            // this test requires nightly
-            None | Some("nightly") => {
-                let config =
-                    Config::from_toml(r#"ignore = ["foo.rs", "bar_dir/*"]"#, Path::new(""))
-                        .unwrap();
-                let ignore_path_set = IgnorePathSet::from_ignore_list(&config.ignore()).unwrap();
-
-                assert!(ignore_path_set.is_match(&FileName::Real(PathBuf::from("src/foo.rs"))));
-                assert!(ignore_path_set.is_match(&FileName::Real(PathBuf::from("bar_dir/baz.rs"))));
-                assert!(!ignore_path_set.is_match(&FileName::Real(PathBuf::from("src/bar.rs"))));
-            }
-            _ => (),
-        };
+        let config =
+            Config::from_toml(r#"ignore = ["foo.rs", "bar_dir/*"]"#, Path::new("")).unwrap();
+        let ignore_path_set = IgnorePathSet::from_ignore_list(&config.ignore()).unwrap();
+
+        assert!(ignore_path_set.is_match(&FileName::Real(PathBuf::from("src/foo.rs"))));
+        assert!(ignore_path_set.is_match(&FileName::Real(PathBuf::from("bar_dir/baz.rs"))));
+        assert!(!ignore_path_set.is_match(&FileName::Real(PathBuf::from("src/bar.rs"))));
     }
 }
diff --git a/src/tools/rustfmt/src/items.rs b/src/tools/rustfmt/src/items.rs
index acc91f861e4..f36bdba26e9 100644
--- a/src/tools/rustfmt/src/items.rs
+++ b/src/tools/rustfmt/src/items.rs
@@ -18,7 +18,7 @@ use crate::config::lists::*;
 use crate::config::{BraceStyle, Config, IndentStyle, Version};
 use crate::expr::{
     is_empty_block, is_simple_block_stmt, rewrite_assign_rhs, rewrite_assign_rhs_with,
-    rewrite_assign_rhs_with_comments, RhsTactics,
+    rewrite_assign_rhs_with_comments, RhsAssignKind, RhsTactics,
 };
 use crate::lists::{definitive_tactic, itemize_list, write_list, ListFormatting, Separator};
 use crate::macros::{rewrite_macro, MacroPosition};
@@ -28,6 +28,7 @@ use crate::shape::{Indent, Shape};
 use crate::source_map::{LineRangeUtils, SpanUtils};
 use crate::spanned::Spanned;
 use crate::stmt::Stmt;
+use crate::types::opaque_ty;
 use crate::utils::*;
 use crate::vertical::rewrite_with_alignment;
 use crate::visitor::FmtVisitor;
@@ -115,7 +116,13 @@ impl Rewrite for ast::Local {
             // 1 = trailing semicolon;
             let nested_shape = shape.sub_width(1)?;
 
-            result = rewrite_assign_rhs(context, result, init, nested_shape)?;
+            result = rewrite_assign_rhs(
+                context,
+                result,
+                init,
+                &RhsAssignKind::Expr(&init.kind, init.span),
+                nested_shape,
+            )?;
             // todo else
         }
 
@@ -563,11 +570,13 @@ impl<'a> FmtVisitor<'a> {
 
         let variant_body = if let Some(ref expr) = field.disr_expr {
             let lhs = format!("{:1$} =", variant_body, pad_discrim_ident_to);
+            let ex = &*expr.value;
             rewrite_assign_rhs_with(
                 &context,
                 lhs,
-                &*expr.value,
+                ex,
                 shape,
+                &RhsAssignKind::Expr(&ex.kind, ex.span),
                 RhsTactics::AllowOverflow,
             )?
         } else {
@@ -579,6 +588,22 @@ impl<'a> FmtVisitor<'a> {
 
     fn visit_impl_items(&mut self, items: &[ptr::P<ast::AssocItem>]) {
         if self.get_context().config.reorder_impl_items() {
+            type TyOpt = Option<ptr::P<ast::Ty>>;
+            use crate::ast::AssocItemKind::*;
+            let is_type = |ty: &TyOpt| opaque_ty(ty).is_none();
+            let is_opaque = |ty: &TyOpt| opaque_ty(ty).is_some();
+            let both_type = |l: &TyOpt, r: &TyOpt| is_type(l) && is_type(r);
+            let both_opaque = |l: &TyOpt, r: &TyOpt| is_opaque(l) && is_opaque(r);
+            let need_empty_line = |a: &ast::AssocItemKind, b: &ast::AssocItemKind| match (a, b) {
+                (TyAlias(lty), TyAlias(rty))
+                    if both_type(&lty.ty, &rty.ty) || both_opaque(&lty.ty, &rty.ty) =>
+                {
+                    false
+                }
+                (Const(..), Const(..)) => false,
+                _ => true,
+            };
+
             // Create visitor for each items, then reorder them.
             let mut buffer = vec![];
             for item in items {
@@ -587,50 +612,6 @@ impl<'a> FmtVisitor<'a> {
                 self.buffer.clear();
             }
 
-            fn is_type(ty: &Option<rustc_ast::ptr::P<ast::Ty>>) -> bool {
-                if let Some(lty) = ty {
-                    if let ast::TyKind::ImplTrait(..) = lty.kind {
-                        return false;
-                    }
-                }
-                true
-            }
-
-            fn is_opaque(ty: &Option<rustc_ast::ptr::P<ast::Ty>>) -> bool {
-                !is_type(ty)
-            }
-
-            fn both_type(
-                a: &Option<rustc_ast::ptr::P<ast::Ty>>,
-                b: &Option<rustc_ast::ptr::P<ast::Ty>>,
-            ) -> bool {
-                is_type(a) && is_type(b)
-            }
-
-            fn both_opaque(
-                a: &Option<rustc_ast::ptr::P<ast::Ty>>,
-                b: &Option<rustc_ast::ptr::P<ast::Ty>>,
-            ) -> bool {
-                is_opaque(a) && is_opaque(b)
-            }
-
-            // In rustc-ap-v638 the `OpaqueTy` AssocItemKind variant was removed but
-            // we still need to differentiate to maintain sorting order.
-
-            // type -> opaque -> const -> macro -> method
-            use crate::ast::AssocItemKind::*;
-            fn need_empty_line(a: &ast::AssocItemKind, b: &ast::AssocItemKind) -> bool {
-                match (a, b) {
-                    (TyAlias(lty), TyAlias(rty))
-                        if both_type(&lty.ty, &rty.ty) || both_opaque(&lty.ty, &rty.ty) =>
-                    {
-                        false
-                    }
-                    (Const(..), Const(..)) => false,
-                    _ => true,
-                }
-            }
-
             buffer.sort_by(|(_, a), (_, b)| match (&a.kind, &b.kind) {
                 (TyAlias(lty), TyAlias(rty))
                     if both_type(&lty.ty, &rty.ty) || both_opaque(&lty.ty, &rty.ty) =>
@@ -676,136 +657,133 @@ impl<'a> FmtVisitor<'a> {
 pub(crate) fn format_impl(
     context: &RewriteContext<'_>,
     item: &ast::Item,
+    iimpl: &ast::Impl,
     offset: Indent,
 ) -> Option<String> {
-    if let ast::ItemKind::Impl(impl_kind) = &item.kind {
-        let ast::Impl {
-            ref generics,
-            ref self_ty,
-            ref items,
-            ..
-        } = **impl_kind;
-        let mut result = String::with_capacity(128);
-        let ref_and_type = format_impl_ref_and_type(context, item, offset)?;
-        let sep = offset.to_string_with_newline(context.config);
-        result.push_str(&ref_and_type);
+    let ast::Impl {
+        generics,
+        self_ty,
+        items,
+        ..
+    } = iimpl;
+    let mut result = String::with_capacity(128);
+    let ref_and_type = format_impl_ref_and_type(context, item, iimpl, offset)?;
+    let sep = offset.to_string_with_newline(context.config);
+    result.push_str(&ref_and_type);
 
-        let where_budget = if result.contains('\n') {
-            context.config.max_width()
-        } else {
-            context.budget(last_line_width(&result))
-        };
+    let where_budget = if result.contains('\n') {
+        context.config.max_width()
+    } else {
+        context.budget(last_line_width(&result))
+    };
 
-        let mut option = WhereClauseOption::snuggled(&ref_and_type);
-        let snippet = context.snippet(item.span);
-        let open_pos = snippet.find_uncommented("{")? + 1;
-        if !contains_comment(&snippet[open_pos..])
-            && items.is_empty()
-            && generics.where_clause.predicates.len() == 1
-            && !result.contains('\n')
-        {
-            option.suppress_comma();
-            option.snuggle();
-            option.allow_single_line();
-        }
+    let mut option = WhereClauseOption::snuggled(&ref_and_type);
+    let snippet = context.snippet(item.span);
+    let open_pos = snippet.find_uncommented("{")? + 1;
+    if !contains_comment(&snippet[open_pos..])
+        && items.is_empty()
+        && generics.where_clause.predicates.len() == 1
+        && !result.contains('\n')
+    {
+        option.suppress_comma();
+        option.snuggle();
+        option.allow_single_line();
+    }
 
-        let missing_span = mk_sp(self_ty.span.hi(), item.span.hi());
-        let where_span_end = context.snippet_provider.opt_span_before(missing_span, "{");
-        let where_clause_str = rewrite_where_clause(
-            context,
-            &generics.where_clause,
-            context.config.brace_style(),
-            Shape::legacy(where_budget, offset.block_only()),
-            false,
-            "{",
-            where_span_end,
-            self_ty.span.hi(),
-            option,
-        )?;
+    let missing_span = mk_sp(self_ty.span.hi(), item.span.hi());
+    let where_span_end = context.snippet_provider.opt_span_before(missing_span, "{");
+    let where_clause_str = rewrite_where_clause(
+        context,
+        &generics.where_clause,
+        context.config.brace_style(),
+        Shape::legacy(where_budget, offset.block_only()),
+        false,
+        "{",
+        where_span_end,
+        self_ty.span.hi(),
+        option,
+    )?;
 
-        // If there is no where-clause, we may have missing comments between the trait name and
-        // the opening brace.
-        if generics.where_clause.predicates.is_empty() {
-            if let Some(hi) = where_span_end {
-                match recover_missing_comment_in_span(
-                    mk_sp(self_ty.span.hi(), hi),
-                    Shape::indented(offset, context.config),
-                    context,
-                    last_line_width(&result),
-                ) {
-                    Some(ref missing_comment) if !missing_comment.is_empty() => {
-                        result.push_str(missing_comment);
-                    }
-                    _ => (),
+    // If there is no where-clause, we may have missing comments between the trait name and
+    // the opening brace.
+    if generics.where_clause.predicates.is_empty() {
+        if let Some(hi) = where_span_end {
+            match recover_missing_comment_in_span(
+                mk_sp(self_ty.span.hi(), hi),
+                Shape::indented(offset, context.config),
+                context,
+                last_line_width(&result),
+            ) {
+                Some(ref missing_comment) if !missing_comment.is_empty() => {
+                    result.push_str(missing_comment);
                 }
+                _ => (),
             }
         }
+    }
 
-        if is_impl_single_line(context, items.as_slice(), &result, &where_clause_str, item)? {
-            result.push_str(&where_clause_str);
-            if where_clause_str.contains('\n') || last_line_contains_single_line_comment(&result) {
-                // if the where_clause contains extra comments AND
-                // there is only one where-clause predicate
-                // recover the suppressed comma in single line where_clause formatting
-                if generics.where_clause.predicates.len() == 1 {
-                    result.push(',');
-                }
-                result.push_str(&format!("{}{{{}}}", sep, sep));
-            } else {
-                result.push_str(" {}");
+    if is_impl_single_line(context, items.as_slice(), &result, &where_clause_str, item)? {
+        result.push_str(&where_clause_str);
+        if where_clause_str.contains('\n') || last_line_contains_single_line_comment(&result) {
+            // if the where_clause contains extra comments AND
+            // there is only one where-clause predicate
+            // recover the suppressed comma in single line where_clause formatting
+            if generics.where_clause.predicates.len() == 1 {
+                result.push(',');
             }
-            return Some(result);
+            result.push_str(&format!("{}{{{}}}", sep, sep));
+        } else {
+            result.push_str(" {}");
         }
+        return Some(result);
+    }
 
-        result.push_str(&where_clause_str);
+    result.push_str(&where_clause_str);
 
-        let need_newline = last_line_contains_single_line_comment(&result) || result.contains('\n');
-        match context.config.brace_style() {
-            _ if need_newline => result.push_str(&sep),
-            BraceStyle::AlwaysNextLine => result.push_str(&sep),
-            BraceStyle::PreferSameLine => result.push(' '),
-            BraceStyle::SameLineWhere => {
-                if !where_clause_str.is_empty() {
-                    result.push_str(&sep);
-                } else {
-                    result.push(' ');
-                }
+    let need_newline = last_line_contains_single_line_comment(&result) || result.contains('\n');
+    match context.config.brace_style() {
+        _ if need_newline => result.push_str(&sep),
+        BraceStyle::AlwaysNextLine => result.push_str(&sep),
+        BraceStyle::PreferSameLine => result.push(' '),
+        BraceStyle::SameLineWhere => {
+            if !where_clause_str.is_empty() {
+                result.push_str(&sep);
+            } else {
+                result.push(' ');
             }
         }
+    }
 
-        result.push('{');
-        // this is an impl body snippet(impl SampleImpl { /* here */ })
-        let lo = max(self_ty.span.hi(), generics.where_clause.span.hi());
-        let snippet = context.snippet(mk_sp(lo, item.span.hi()));
-        let open_pos = snippet.find_uncommented("{")? + 1;
+    result.push('{');
+    // this is an impl body snippet(impl SampleImpl { /* here */ })
+    let lo = max(self_ty.span.hi(), generics.where_clause.span.hi());
+    let snippet = context.snippet(mk_sp(lo, item.span.hi()));
+    let open_pos = snippet.find_uncommented("{")? + 1;
 
-        if !items.is_empty() || contains_comment(&snippet[open_pos..]) {
-            let mut visitor = FmtVisitor::from_context(context);
-            let item_indent = offset.block_only().block_indent(context.config);
-            visitor.block_indent = item_indent;
-            visitor.last_pos = lo + BytePos(open_pos as u32);
+    if !items.is_empty() || contains_comment(&snippet[open_pos..]) {
+        let mut visitor = FmtVisitor::from_context(context);
+        let item_indent = offset.block_only().block_indent(context.config);
+        visitor.block_indent = item_indent;
+        visitor.last_pos = lo + BytePos(open_pos as u32);
 
-            visitor.visit_attrs(&item.attrs, ast::AttrStyle::Inner);
-            visitor.visit_impl_items(items);
+        visitor.visit_attrs(&item.attrs, ast::AttrStyle::Inner);
+        visitor.visit_impl_items(items);
 
-            visitor.format_missing(item.span.hi() - BytePos(1));
+        visitor.format_missing(item.span.hi() - BytePos(1));
 
-            let inner_indent_str = visitor.block_indent.to_string_with_newline(context.config);
-            let outer_indent_str = offset.block_only().to_string_with_newline(context.config);
+        let inner_indent_str = visitor.block_indent.to_string_with_newline(context.config);
+        let outer_indent_str = offset.block_only().to_string_with_newline(context.config);
 
-            result.push_str(&inner_indent_str);
-            result.push_str(visitor.buffer.trim());
-            result.push_str(&outer_indent_str);
-        } else if need_newline || !context.config.empty_item_single_line() {
-            result.push_str(&sep);
-        }
+        result.push_str(&inner_indent_str);
+        result.push_str(visitor.buffer.trim());
+        result.push_str(&outer_indent_str);
+    } else if need_newline || !context.config.empty_item_single_line() {
+        result.push_str(&sep);
+    }
 
-        result.push('}');
+    result.push('}');
 
-        Some(result)
-    } else {
-        unreachable!();
-    }
+    Some(result)
 }
 
 fn is_impl_single_line(
@@ -830,111 +808,106 @@ fn is_impl_single_line(
 fn format_impl_ref_and_type(
     context: &RewriteContext<'_>,
     item: &ast::Item,
+    iimpl: &ast::Impl,
     offset: Indent,
 ) -> Option<String> {
-    if let ast::ItemKind::Impl(impl_kind) = &item.kind {
-        let ast::Impl {
-            unsafety,
-            polarity,
-            defaultness,
-            constness,
-            ref generics,
-            of_trait: ref trait_ref,
-            ref self_ty,
-            ..
-        } = **impl_kind;
-        let mut result = String::with_capacity(128);
+    let ast::Impl {
+        unsafety,
+        polarity,
+        defaultness,
+        constness,
+        ref generics,
+        of_trait: ref trait_ref,
+        ref self_ty,
+        ..
+    } = *iimpl;
+    let mut result = String::with_capacity(128);
 
-        result.push_str(&format_visibility(context, &item.vis));
-        result.push_str(format_defaultness(defaultness));
-        result.push_str(format_unsafety(unsafety));
+    result.push_str(&format_visibility(context, &item.vis));
+    result.push_str(format_defaultness(defaultness));
+    result.push_str(format_unsafety(unsafety));
 
-        let shape = if context.config.version() == Version::Two {
-            Shape::indented(offset + last_line_width(&result), context.config)
-        } else {
-            generics_shape_from_config(
-                context.config,
-                Shape::indented(offset + last_line_width(&result), context.config),
-                0,
-            )?
-        };
-        let generics_str = rewrite_generics(context, "impl", generics, shape)?;
-        result.push_str(&generics_str);
-        result.push_str(format_constness_right(constness));
+    let shape = if context.config.version() == Version::Two {
+        Shape::indented(offset + last_line_width(&result), context.config)
+    } else {
+        generics_shape_from_config(
+            context.config,
+            Shape::indented(offset + last_line_width(&result), context.config),
+            0,
+        )?
+    };
+    let generics_str = rewrite_generics(context, "impl", generics, shape)?;
+    result.push_str(&generics_str);
+    result.push_str(format_constness_right(constness));
 
-        let polarity_str = match polarity {
-            ast::ImplPolarity::Negative(_) => "!",
-            ast::ImplPolarity::Positive => "",
-        };
+    let polarity_str = match polarity {
+        ast::ImplPolarity::Negative(_) => "!",
+        ast::ImplPolarity::Positive => "",
+    };
 
-        let polarity_overhead;
-        let trait_ref_overhead;
-        if let Some(ref trait_ref) = *trait_ref {
-            let result_len = last_line_width(&result);
-            result.push_str(&rewrite_trait_ref(
-                context,
-                trait_ref,
-                offset,
-                polarity_str,
-                result_len,
-            )?);
-            polarity_overhead = 0; // already written
-            trait_ref_overhead = " for".len();
-        } else {
-            polarity_overhead = polarity_str.len();
-            trait_ref_overhead = 0;
-        }
+    let polarity_overhead;
+    let trait_ref_overhead;
+    if let Some(ref trait_ref) = *trait_ref {
+        let result_len = last_line_width(&result);
+        result.push_str(&rewrite_trait_ref(
+            context,
+            trait_ref,
+            offset,
+            polarity_str,
+            result_len,
+        )?);
+        polarity_overhead = 0; // already written
+        trait_ref_overhead = " for".len();
+    } else {
+        polarity_overhead = polarity_str.len();
+        trait_ref_overhead = 0;
+    }
 
-        // Try to put the self type in a single line.
-        let curly_brace_overhead = if generics.where_clause.predicates.is_empty() {
-            // If there is no where-clause adapt budget for type formatting to take space and curly
-            // brace into account.
-            match context.config.brace_style() {
-                BraceStyle::AlwaysNextLine => 0,
-                _ => 2,
-            }
-        } else {
-            0
-        };
-        let used_space = last_line_width(&result)
-            + polarity_overhead
-            + trait_ref_overhead
-            + curly_brace_overhead;
-        // 1 = space before the type.
-        let budget = context.budget(used_space + 1);
-        if let Some(self_ty_str) = self_ty.rewrite(context, Shape::legacy(budget, offset)) {
-            if !self_ty_str.contains('\n') {
-                if trait_ref.is_some() {
-                    result.push_str(" for ");
-                } else {
-                    result.push(' ');
-                    result.push_str(polarity_str);
-                }
-                result.push_str(&self_ty_str);
-                return Some(result);
+    // Try to put the self type in a single line.
+    let curly_brace_overhead = if generics.where_clause.predicates.is_empty() {
+        // If there is no where-clause adapt budget for type formatting to take space and curly
+        // brace into account.
+        match context.config.brace_style() {
+            BraceStyle::AlwaysNextLine => 0,
+            _ => 2,
+        }
+    } else {
+        0
+    };
+    let used_space =
+        last_line_width(&result) + polarity_overhead + trait_ref_overhead + curly_brace_overhead;
+    // 1 = space before the type.
+    let budget = context.budget(used_space + 1);
+    if let Some(self_ty_str) = self_ty.rewrite(context, Shape::legacy(budget, offset)) {
+        if !self_ty_str.contains('\n') {
+            if trait_ref.is_some() {
+                result.push_str(" for ");
+            } else {
+                result.push(' ');
+                result.push_str(polarity_str);
             }
+            result.push_str(&self_ty_str);
+            return Some(result);
         }
+    }
 
-        // Couldn't fit the self type on a single line, put it on a new line.
-        result.push('\n');
-        // Add indentation of one additional tab.
-        let new_line_offset = offset.block_indent(context.config);
-        result.push_str(&new_line_offset.to_string(context.config));
-        if trait_ref.is_some() {
-            result.push_str("for ");
-        } else {
-            result.push_str(polarity_str);
-        }
-        let budget = context.budget(last_line_width(&result) + polarity_overhead);
-        let type_offset = match context.config.indent_style() {
-            IndentStyle::Visual => new_line_offset + trait_ref_overhead,
-            IndentStyle::Block => new_line_offset,
-        };
-        result.push_str(&*self_ty.rewrite(context, Shape::legacy(budget, type_offset))?);
-        Some(result)
+    // Couldn't fit the self type on a single line, put it on a new line.
+    result.push('\n');
+    // Add indentation of one additional tab.
+    let new_line_offset = offset.block_indent(context.config);
+    result.push_str(&new_line_offset.to_string(context.config));
+    if trait_ref.is_some() {
+        result.push_str("for ");
     } else {
-        unreachable!();
+        result.push_str(polarity_str);
     }
+    let budget = context.budget(last_line_width(&result) + polarity_overhead);
+    let type_offset = match context.config.indent_style() {
+        IndentStyle::Visual => new_line_offset + trait_ref_overhead,
+        IndentStyle::Block => new_line_offset,
+    };
+    result.push_str(&*self_ty.rewrite(context, Shape::legacy(budget, type_offset))?);
+    Some(result)
 }
 
 fn rewrite_trait_ref(
@@ -1068,6 +1041,7 @@ pub(crate) fn format_trait(
                 result + ":",
                 bounds,
                 shape,
+                &RhsAssignKind::Bounds,
                 RhsTactics::ForceNextLineWithoutIndent,
             )?;
         }
@@ -1248,7 +1222,14 @@ pub(crate) fn format_trait_alias(
         generic_bounds,
         generics,
     };
-    rewrite_assign_rhs(context, lhs, &trait_alias_bounds, shape.sub_width(1)?).map(|s| s + ";")
+    rewrite_assign_rhs(
+        context,
+        lhs,
+        &trait_alias_bounds,
+        &RhsAssignKind::Bounds,
+        shape.sub_width(1)?,
+    )
+    .map(|s| s + ";")
 }
 
 fn format_unit_struct(
@@ -1541,43 +1522,38 @@ pub(crate) fn rewrite_type_alias<'a, 'b>(
         ref bounds,
         ref ty,
     } = *ty_alias_kind;
-    let ty_opt = ty.as_ref().map(|t| &**t);
+    let ty_opt = ty.as_ref();
     let (ident, vis) = match visitor_kind {
         Item(i) => (i.ident, &i.vis),
         AssocTraitItem(i) | AssocImplItem(i) => (i.ident, &i.vis),
         ForeignItem(i) => (i.ident, &i.vis),
     };
     let rw_info = &TyAliasRewriteInfo(context, indent, generics, ident, span);
-
+    let op_ty = opaque_ty(ty);
     // Type Aliases are formatted slightly differently depending on the context
     // in which they appear, whether they are opaque, and whether they are associated.
     // https://rustc-dev-guide.rust-lang.org/opaque-types-type-alias-impl-trait.html
     // https://github.com/rust-dev-tools/fmt-rfcs/blob/master/guide/items.md#type-aliases
-    match (visitor_kind, ty_opt) {
-        (Item(_), None) => {
-            let op_ty = OpaqueType { bounds };
-            rewrite_ty(rw_info, Some(bounds), Some(&op_ty), vis)
+    match (visitor_kind, &op_ty) {
+        (Item(_) | AssocTraitItem(_) | ForeignItem(_), Some(ref op_bounds)) => {
+            let op = OpaqueType { bounds: op_bounds };
+            rewrite_ty(rw_info, Some(bounds), Some(&op), vis)
+        }
+        (Item(_) | AssocTraitItem(_) | ForeignItem(_), None) => {
+            rewrite_ty(rw_info, Some(bounds), ty_opt, vis)
         }
-        (Item(_), Some(ty)) => rewrite_ty(rw_info, Some(bounds), Some(&*ty), vis),
         (AssocImplItem(_), _) => {
-            let result = if let Some(ast::Ty {
-                kind: ast::TyKind::ImplTrait(_, ref bounds),
-                ..
-            }) = ty_opt
-            {
-                let op_ty = OpaqueType { bounds };
-                rewrite_ty(rw_info, None, Some(&op_ty), &DEFAULT_VISIBILITY)
+            let result = if let Some(ref op_bounds) = op_ty {
+                let op = OpaqueType { bounds: op_bounds };
+                rewrite_ty(rw_info, Some(bounds), Some(&op), &DEFAULT_VISIBILITY)
             } else {
-                rewrite_ty(rw_info, None, ty.as_ref(), vis)
+                rewrite_ty(rw_info, Some(bounds), ty_opt, vis)
             }?;
             match defaultness {
                 ast::Defaultness::Default(..) => Some(format!("default {}", result)),
                 _ => Some(result),
             }
         }
-        (AssocTraitItem(_), _) | (ForeignItem(_), _) => {
-            rewrite_ty(rw_info, Some(bounds), ty.as_ref(), vis)
-        }
     }
 }
 
@@ -1670,7 +1646,7 @@ fn rewrite_ty<R: Rewrite>(
 
         // 1 = `;`
         let shape = Shape::indented(indent, context.config).sub_width(1)?;
-        rewrite_assign_rhs(context, lhs, &*ty, shape).map(|s| s + ";")
+        rewrite_assign_rhs(context, lhs, &*ty, &RhsAssignKind::Ty, shape).map(|s| s + ";")
     } else {
         Some(format!("{};", result))
     }
@@ -1760,7 +1736,7 @@ pub(crate) fn rewrite_struct_field(
 
     let is_prefix_empty = prefix.is_empty();
     // We must use multiline. We are going to put attributes and a field on different lines.
-    let field_str = rewrite_assign_rhs(context, prefix, &*field.ty, shape)?;
+    let field_str = rewrite_assign_rhs(context, prefix, &*field.ty, &RhsAssignKind::Ty, shape)?;
     // Remove a leading white-space from `rewrite_assign_rhs()` when rewriting a tuple struct.
     let field_str = if is_prefix_empty {
         field_str.trim_start()
@@ -1890,6 +1866,7 @@ fn rewrite_static(
             &lhs,
             &**expr,
             Shape::legacy(remaining_width, offset.block_only()),
+            &RhsAssignKind::Expr(&expr.kind, expr.span),
             RhsTactics::Default,
             comments_span,
             true,
@@ -1900,6 +1877,12 @@ fn rewrite_static(
         Some(format!("{}{};", prefix, ty_str))
     }
 }
+
+// FIXME(calebcartwright) - This is a hack around a bug in the handling of TyKind::ImplTrait.
+// This should be removed once that bug is resolved, with the type alias formatting using the
+// defined Ty for the RHS directly.
+// https://github.com/rust-lang/rustfmt/issues/4373
+// https://github.com/rust-lang/rustfmt/issues/5027
 struct OpaqueType<'a> {
     bounds: &'a ast::GenericBounds,
 }
@@ -3173,7 +3156,14 @@ impl Rewrite for ast::ForeignItem {
                     rewrite_ident(context, self.ident)
                 );
                 // 1 = ;
-                rewrite_assign_rhs(context, prefix, &**ty, shape.sub_width(1)?).map(|s| s + ";")
+                rewrite_assign_rhs(
+                    context,
+                    prefix,
+                    &**ty,
+                    &RhsAssignKind::Ty,
+                    shape.sub_width(1)?,
+                )
+                .map(|s| s + ";")
             }
             ast::ForeignItemKind::TyAlias(ref ty_alias) => {
                 let (kind, span) = (&ItemVisitorKind::ForeignItem(&self), self.span);
diff --git a/src/tools/rustfmt/src/lists.rs b/src/tools/rustfmt/src/lists.rs
index d341ec8e6b0..3515dd17251 100644
--- a/src/tools/rustfmt/src/lists.rs
+++ b/src/tools/rustfmt/src/lists.rs
@@ -444,10 +444,15 @@ where
                 let offset = formatting.shape.indent + overhead;
                 let comment_shape = Shape::legacy(width, offset);
 
-                // Use block-style only for the last item or multiline comments.
-                let block_style = !formatting.ends_with_newline && last
-                    || comment.trim().contains('\n')
-                    || comment.trim().len() > width;
+                let block_style = if !formatting.ends_with_newline && last {
+                    true
+                } else if starts_with_newline(comment) {
+                    false
+                } else if comment.trim().contains('\n') || comment.trim().len() > width {
+                    true
+                } else {
+                    false
+                };
 
                 rewrite_comment(
                     comment.trim_start(),
diff --git a/src/tools/rustfmt/src/macros.rs b/src/tools/rustfmt/src/macros.rs
index ef747638e33..a52568be9ea 100644
--- a/src/tools/rustfmt/src/macros.rs
+++ b/src/tools/rustfmt/src/macros.rs
@@ -27,7 +27,7 @@ use crate::comment::{
     contains_comment, CharClasses, FindUncommented, FullCodeCharKind, LineClasses,
 };
 use crate::config::lists::*;
-use crate::expr::rewrite_array;
+use crate::expr::{rewrite_array, rewrite_assign_rhs, RhsAssignKind};
 use crate::lists::{itemize_list, write_list, ListFormatting};
 use crate::overflow;
 use crate::rewrite::{Rewrite, RewriteContext};
@@ -1468,10 +1468,11 @@ fn format_lazy_static(
             id,
             ty.rewrite(context, nested_shape)?
         ));
-        result.push_str(&crate::expr::rewrite_assign_rhs(
+        result.push_str(&rewrite_assign_rhs(
             context,
             stmt,
             &*expr,
+            &RhsAssignKind::Expr(&expr.kind, expr.span),
             nested_shape.sub_width(1)?,
         )?);
         result.push(';');
diff --git a/src/tools/rustfmt/src/syntux/session.rs b/src/tools/rustfmt/src/syntux/session.rs
index cdb4893d443..dd7c7352686 100644
--- a/src/tools/rustfmt/src/syntux/session.rs
+++ b/src/tools/rustfmt/src/syntux/session.rs
@@ -286,10 +286,11 @@ impl LineRangeUtils for ParseSess {
 mod tests {
     use super::*;
 
+    use rustfmt_config_proc_macro::nightly_only_test;
+
     mod emitter {
         use super::*;
         use crate::config::IgnoreList;
-        use crate::is_nightly_channel;
         use crate::utils::mk_sp;
         use rustc_span::{FileName as SourceMapFileName, MultiSpan, RealFileName, DUMMY_SP};
         use std::path::PathBuf;
@@ -371,11 +372,9 @@ mod tests {
             assert_eq!(can_reset_errors.load(Ordering::Acquire), false);
         }
 
+        #[nightly_only_test]
         #[test]
         fn handles_recoverable_parse_error_in_ignored_file() {
-            if !is_nightly_channel!() {
-                return;
-            }
             let num_emitted_errors = Lrc::new(AtomicU32::new(0));
             let can_reset_errors = Lrc::new(AtomicBool::new(false));
             let ignore_list = get_ignore_list(r#"ignore = ["foo.rs"]"#);
@@ -398,11 +397,9 @@ mod tests {
             assert_eq!(can_reset_errors.load(Ordering::Acquire), true);
         }
 
+        #[nightly_only_test]
         #[test]
         fn handles_recoverable_parse_error_in_non_ignored_file() {
-            if !is_nightly_channel!() {
-                return;
-            }
             let num_emitted_errors = Lrc::new(AtomicU32::new(0));
             let can_reset_errors = Lrc::new(AtomicBool::new(false));
             let source_map = Lrc::new(SourceMap::new(FilePathMapping::empty()));
@@ -424,11 +421,9 @@ mod tests {
             assert_eq!(can_reset_errors.load(Ordering::Acquire), false);
         }
 
+        #[nightly_only_test]
         #[test]
         fn handles_mix_of_recoverable_parse_error() {
-            if !is_nightly_channel!() {
-                return;
-            }
             let num_emitted_errors = Lrc::new(AtomicU32::new(0));
             let can_reset_errors = Lrc::new(AtomicBool::new(false));
             let source_map = Lrc::new(SourceMap::new(FilePathMapping::empty()));
diff --git a/src/tools/rustfmt/src/test/mod.rs b/src/tools/rustfmt/src/test/mod.rs
index e2620508c34..cceb28dfea6 100644
--- a/src/tools/rustfmt/src/test/mod.rs
+++ b/src/tools/rustfmt/src/test/mod.rs
@@ -15,6 +15,8 @@ use crate::rustfmt_diff::{make_diff, print_diff, DiffLine, Mismatch, ModifiedChu
 use crate::source_file;
 use crate::{is_nightly_channel, FormatReport, FormatReportFormatterBuilder, Input, Session};
 
+use rustfmt_config_proc_macro::nightly_only_test;
+
 mod configuration_snippet;
 mod mod_resolver;
 mod parser;
@@ -307,14 +309,11 @@ fn assert_output(source: &Path, expected_filename: &Path) {
 
 // Idempotence tests. Files in tests/target are checked to be unaltered by
 // rustfmt.
+#[nightly_only_test]
 #[test]
 fn idempotence_tests() {
     init_log();
     run_test_with(&TestSetting::default(), || {
-        // these tests require nightly
-        if !is_nightly_channel!() {
-            return;
-        }
         // Get all files in the tests/target directory.
         let files = get_test_files(Path::new("tests/target"), true);
         let (_reports, count, fails) = check_files(files, &None);
@@ -332,13 +331,11 @@ fn idempotence_tests() {
 
 // Run rustfmt on itself. This operation must be idempotent. We also check that
 // no warnings are emitted.
+// Issue-3443: these tests require nightly
+#[nightly_only_test]
 #[test]
 fn self_tests() {
     init_log();
-    // Issue-3443: these tests require nightly
-    if !is_nightly_channel!() {
-        return;
-    }
     let mut files = get_test_files(Path::new("tests"), false);
     let bin_directories = vec!["cargo-fmt", "git-rustfmt", "bin", "format-diff"];
     for dir in bin_directories {
diff --git a/src/tools/rustfmt/src/types.rs b/src/tools/rustfmt/src/types.rs
index 9ea90c5e46d..88f5dc43245 100644
--- a/src/tools/rustfmt/src/types.rs
+++ b/src/tools/rustfmt/src/types.rs
@@ -2,6 +2,7 @@ use std::iter::ExactSizeIterator;
 use std::ops::Deref;
 
 use rustc_ast::ast::{self, FnRetTy, Mutability};
+use rustc_ast::ptr;
 use rustc_span::{symbol::kw, BytePos, Pos, Span};
 
 use crate::comment::{combine_strs_with_missing_comments, contains_comment};
@@ -9,6 +10,7 @@ use crate::config::lists::*;
 use crate::config::{IndentStyle, TypeDensity, Version};
 use crate::expr::{
     format_expr, rewrite_assign_rhs, rewrite_call, rewrite_tuple, rewrite_unary_prefix, ExprType,
+    RhsAssignKind,
 };
 use crate::lists::{
     definitive_tactic, itemize_list, write_list, ListFormatting, ListItem, Separator,
@@ -429,7 +431,7 @@ impl Rewrite for ast::WherePredicate {
                     format!("{}{}", type_str, colon)
                 };
 
-                rewrite_assign_rhs(context, lhs, bounds, shape)?
+                rewrite_assign_rhs(context, lhs, bounds, &RhsAssignKind::Bounds, shape)?
             }
             ast::WherePredicate::RegionPredicate(ast::WhereRegionPredicate {
                 ref lifetime,
@@ -442,7 +444,7 @@ impl Rewrite for ast::WherePredicate {
                 ..
             }) => {
                 let lhs_ty_str = lhs_ty.rewrite(context, shape).map(|lhs| lhs + " =")?;
-                rewrite_assign_rhs(context, lhs_ty_str, &**rhs_ty, shape)?
+                rewrite_assign_rhs(context, lhs_ty_str, &**rhs_ty, &RhsAssignKind::Ty, shape)?
             }
         };
 
@@ -1031,6 +1033,13 @@ fn join_bounds_inner(
     }
 }
 
+pub(crate) fn opaque_ty(ty: &Option<ptr::P<ast::Ty>>) -> Option<&ast::GenericBounds> {
+    ty.as_ref().and_then(|t| match &t.kind {
+        ast::TyKind::ImplTrait(_, bounds) => Some(bounds),
+        _ => None,
+    })
+}
+
 pub(crate) fn can_be_overflowed_type(
     context: &RewriteContext<'_>,
     ty: &ast::Ty,
diff --git a/src/tools/rustfmt/src/visitor.rs b/src/tools/rustfmt/src/visitor.rs
index 527042d098a..e4a7be742ab 100644
--- a/src/tools/rustfmt/src/visitor.rs
+++ b/src/tools/rustfmt/src/visitor.rs
@@ -485,9 +485,9 @@ impl<'b, 'a: 'b> FmtVisitor<'a> {
         if should_visit_node_again {
             match item.kind {
                 ast::ItemKind::Use(ref tree) => self.format_import(item, tree),
-                ast::ItemKind::Impl { .. } => {
+                ast::ItemKind::Impl(ref iimpl) => {
                     let block_indent = self.block_indent;
-                    let rw = self.with_context(|ctx| format_impl(ctx, item, block_indent));
+                    let rw = self.with_context(|ctx| format_impl(ctx, item, iimpl, block_indent));
                     self.push_rewrite(item.span, rw);
                 }
                 ast::ItemKind::Trait(..) => {
diff --git a/src/tools/rustfmt/tests/source/comments-in-lists/wrap-comments-not-normalized.rs b/src/tools/rustfmt/tests/source/comments-in-lists/wrap-comments-not-normalized.rs
new file mode 100644
index 00000000000..b96c02802d6
--- /dev/null
+++ b/src/tools/rustfmt/tests/source/comments-in-lists/wrap-comments-not-normalized.rs
@@ -0,0 +1,129 @@
+// rustfmt-wrap_comments: true
+
+// https://github.com/rust-lang/rustfmt/issues/4909
+pub enum E {
+    // Expand as needed, numbers should be ascending according to the stage
+    // through the inclusion pipeline, or according to the descriptions
+    Variant1,
+    // Expand as needed, numbers should be ascending according to the stage
+    // through the inclusion pipeline, or according to the descriptions
+    Variant2,
+    // Expand as needed, numbers should be ascending according to the stage
+    // through the inclusion pipeline, or according to the descriptions
+}
+
+pub enum E2 {
+    // This can be changed once https://github.com/rust-lang/rustfmt/issues/4854 is fixed
+// Expand as needed, numbers should be ascending according to the stage
+// through the inclusion pipeline, or according to the descriptions
+}
+
+pub enum E3 {
+    // Expand as needed, numbers should be ascending according to the stage through the inclusion pipeline, or according to the descriptions
+    Variant1,
+    // Expand as needed, numbers should be ascending according to the stage through the inclusion pipeline, or according to the descriptions
+    Variant2,
+    // Expand as needed, numbers should be ascending according to the stage through the inclusion pipeline, or according to the descriptions
+
+}
+
+pub struct S {
+    // Expand as needed, numbers should be ascending according to the stage
+    // through the inclusion pipeline, or according to the descriptions
+    some_field: usize,
+    // Expand as needed, numbers should be ascending according to the stage
+    // through the inclusion pipeline, or according to the descriptions
+    last_field: usize,
+    // Expand as needed, numbers should be ascending according to the stage
+    // through the inclusion pipeline, or according to the descriptions
+}
+
+pub struct S2 {
+    // This can be changed once https://github.com/rust-lang/rustfmt/issues/4854 is fixed
+// Expand as needed, numbers should be ascending according to the stage
+// through the inclusion pipeline, or according to the descriptions
+}
+
+pub struct S3 {
+    // Expand as needed, numbers should be ascending according to the stage through the inclusion pipeline, or according to the descriptions
+    some_field: usize,
+    // Expand as needed, numbers should be ascending according to the stage through the inclusion pipeline, or according to the descriptions
+    last_field: usize,
+    // Expand as needed, numbers should be ascending according to the stage through the inclusion pipeline, or according to the descriptions
+}
+
+fn foo(
+    // Expand as needed, numbers should be ascending according to the stage
+    // through the inclusion pipeline, or according to the descriptions
+    a: usize,
+    // Expand as needed, numbers should be ascending according to the stage
+    // through the inclusion pipeline, or according to the descriptions
+    b: usize,
+    // Expand as needed, numbers should be ascending according to the stage
+    // through the inclusion pipeline, or according to the descriptions
+) -> usize {
+    5
+}
+
+fn foo2(// Expand as needed, numbers should be ascending according to the stage
+    // through the inclusion pipeline, or according to the descriptions
+) -> usize {
+    5
+}
+
+fn foo3(
+    // Expand as needed, numbers should be ascending according to the stage through the inclusion pipeline, or according to the descriptions
+    a: usize,
+    // Expand as needed, numbers should be ascending according to the stage through the inclusion pipeline, or according to the descriptions
+    b: usize,
+    // Expand as needed, numbers should be ascending according to the stage through the inclusion pipeline, or according to the descriptions
+
+) -> usize {
+    5
+}
+
+fn main() {
+    let v = vec![
+        // Expand as needed, numbers should be ascending according to the stage
+        // through the inclusion pipeline, or according to the descriptions
+        1,
+        // Expand as needed, numbers should be ascending according to the stage
+        // through the inclusion pipeline, or according to the descriptions
+        2,
+        // Expand as needed, numbers should be ascending according to the stage
+        // through the inclusion pipeline, or according to the descriptions
+    ];
+
+    let v2: Vec<i32> = vec![
+        // Expand as needed, numbers should be ascending according to the stage
+        // through the inclusion pipeline, or according to the descriptions
+    ];
+
+    let v3 = vec![
+        // Expand as needed, numbers should be ascending according to the stage through the inclusion pipeline, or according to the descriptions
+        1,
+        // Expand as needed, numbers should be ascending according to the stage through the inclusion pipeline, or according to the descriptions
+        2,
+        // Expand as needed, numbers should be ascending according to the stage through the inclusion pipeline, or according to the descriptions
+    ];
+
+    // https://github.com/rust-lang/rustfmt/issues/4430
+    match a {
+        // Expand as needed, numbers should be ascending according to the stage
+        // through the inclusion pipeline, or according to the descriptions
+        b => c,
+        // Expand as needed, numbers should be ascending according to the stage
+        // through the inclusion pipeline, or according to the descriptions
+        d => e,
+        // Expand as needed, numbers should be ascending according to the stage
+        // through the inclusion pipeline, or according to the descriptions
+    }
+
+    match a {
+        // Expand as needed, numbers should be ascending according to the stage through the inclusion pipeline, or according to the descriptions
+        b => c,
+        // Expand as needed, numbers should be ascending according to the stage through the inclusion pipeline, or according to the descriptions
+        d => e,
+        // Expand as needed, numbers should be ascending according to the stage through the inclusion pipeline, or according to the descriptions
+    }
+}
diff --git a/src/tools/rustfmt/tests/source/comments-in-lists/wrap-comments-true.rs b/src/tools/rustfmt/tests/source/comments-in-lists/wrap-comments-true.rs
new file mode 100644
index 00000000000..360b838520e
--- /dev/null
+++ b/src/tools/rustfmt/tests/source/comments-in-lists/wrap-comments-true.rs
@@ -0,0 +1,130 @@
+// rustfmt-normalize_comments: true
+// rustfmt-wrap_comments: true
+
+// https://github.com/rust-lang/rustfmt/issues/4909
+pub enum E {
+    // Expand as needed, numbers should be ascending according to the stage
+    // through the inclusion pipeline, or according to the descriptions
+    Variant1,
+    // Expand as needed, numbers should be ascending according to the stage
+    // through the inclusion pipeline, or according to the descriptions
+    Variant2,
+    // Expand as needed, numbers should be ascending according to the stage
+    // through the inclusion pipeline, or according to the descriptions
+}
+
+pub enum E2 {
+    // This can be changed once https://github.com/rust-lang/rustfmt/issues/4854 is fixed
+// Expand as needed, numbers should be ascending according to the stage
+// through the inclusion pipeline, or according to the descriptions
+}
+
+pub enum E3 {
+    // Expand as needed, numbers should be ascending according to the stage through the inclusion pipeline, or according to the descriptions
+    Variant1,
+    // Expand as needed, numbers should be ascending according to the stage through the inclusion pipeline, or according to the descriptions
+    Variant2,
+    // Expand as needed, numbers should be ascending according to the stage through the inclusion pipeline, or according to the descriptions
+
+}
+
+pub struct S {
+    // Expand as needed, numbers should be ascending according to the stage
+    // through the inclusion pipeline, or according to the descriptions
+    some_field: usize,
+    // Expand as needed, numbers should be ascending according to the stage
+    // through the inclusion pipeline, or according to the descriptions
+    last_field: usize,
+    // Expand as needed, numbers should be ascending according to the stage
+    // through the inclusion pipeline, or according to the descriptions
+}
+
+pub struct S2 {
+    // This can be changed once https://github.com/rust-lang/rustfmt/issues/4854 is fixed
+// Expand as needed, numbers should be ascending according to the stage
+// through the inclusion pipeline, or according to the descriptions
+}
+
+pub struct S3 {
+    // Expand as needed, numbers should be ascending according to the stage through the inclusion pipeline, or according to the descriptions
+    some_field: usize,
+    // Expand as needed, numbers should be ascending according to the stage through the inclusion pipeline, or according to the descriptions
+    last_field: usize,
+    // Expand as needed, numbers should be ascending according to the stage through the inclusion pipeline, or according to the descriptions
+}
+
+fn foo(
+    // Expand as needed, numbers should be ascending according to the stage
+    // through the inclusion pipeline, or according to the descriptions
+    a: usize,
+    // Expand as needed, numbers should be ascending according to the stage
+    // through the inclusion pipeline, or according to the descriptions
+    b: usize,
+    // Expand as needed, numbers should be ascending according to the stage
+    // through the inclusion pipeline, or according to the descriptions
+) -> usize {
+    5
+}
+
+fn foo2(// Expand as needed, numbers should be ascending according to the stage
+    // through the inclusion pipeline, or according to the descriptions
+) -> usize {
+    5
+}
+
+fn foo3(
+    // Expand as needed, numbers should be ascending according to the stage through the inclusion pipeline, or according to the descriptions
+    a: usize,
+    // Expand as needed, numbers should be ascending according to the stage through the inclusion pipeline, or according to the descriptions
+    b: usize,
+    // Expand as needed, numbers should be ascending according to the stage through the inclusion pipeline, or according to the descriptions
+
+) -> usize {
+    5
+}
+
+fn main() {
+    let v = vec![
+        // Expand as needed, numbers should be ascending according to the stage
+        // through the inclusion pipeline, or according to the descriptions
+        1,
+        // Expand as needed, numbers should be ascending according to the stage
+        // through the inclusion pipeline, or according to the descriptions
+        2,
+        // Expand as needed, numbers should be ascending according to the stage
+        // through the inclusion pipeline, or according to the descriptions
+    ];
+
+    let v2: Vec<i32> = vec![
+        // Expand as needed, numbers should be ascending according to the stage
+        // through the inclusion pipeline, or according to the descriptions
+    ];
+
+    let v3 = vec![
+        // Expand as needed, numbers should be ascending according to the stage through the inclusion pipeline, or according to the descriptions
+        1,
+        // Expand as needed, numbers should be ascending according to the stage through the inclusion pipeline, or according to the descriptions
+        2,
+        // Expand as needed, numbers should be ascending according to the stage through the inclusion pipeline, or according to the descriptions
+    ];
+
+    // https://github.com/rust-lang/rustfmt/issues/4430
+    match a {
+        // Expand as needed, numbers should be ascending according to the stage
+        // through the inclusion pipeline, or according to the descriptions
+        b => c,
+        // Expand as needed, numbers should be ascending according to the stage
+        // through the inclusion pipeline, or according to the descriptions
+        d => e,
+        // Expand as needed, numbers should be ascending according to the stage
+        // through the inclusion pipeline, or according to the descriptions
+    }
+
+    match a {
+        // Expand as needed, numbers should be ascending according to the stage through the inclusion pipeline, or according to the descriptions
+        b => c,
+        // Expand as needed, numbers should be ascending according to the stage through the inclusion pipeline, or according to the descriptions
+        d => e,
+        // Expand as needed, numbers should be ascending according to the stage through the inclusion pipeline, or according to the descriptions
+    }
+}
diff --git a/src/tools/rustfmt/tests/source/issue-5088/deeply_nested_long_comment_wrap_comments_true.rs b/src/tools/rustfmt/tests/source/issue-5088/deeply_nested_long_comment_wrap_comments_true.rs
new file mode 100644
index 00000000000..09f68cae424
--- /dev/null
+++ b/src/tools/rustfmt/tests/source/issue-5088/deeply_nested_long_comment_wrap_comments_true.rs
@@ -0,0 +1,33 @@
+// rustfmt-wrap_comments: true
+
+fn main() {
+    {
+        {
+            {
+                {
+                    {
+                        {
+                            {
+                                {
+                                    {
+                                        {
+                                            {
+                                                // - aaaa aaaaaaaaa aaaaaaaaa aaaaaaaaa aaaaaaaaa bbbbbbbbbb bbbbbbbbb bbbbbbbbb ccc cccccccccc ccccccc cccccccc
+
+                                                // * aaaa aaaaaaaaa aaaaaaaaa aaaaaaaaa aaaaaaaaa bbbbbbbbbb bbbbbbbbb bbbbbbbbb ccc cccccccccc ccccccc cccccccc
+
+                                                /* - aaaa aaaaaaaaa aaaaaaaaa aaaaaaaaa aaaaaaaaa bbbbbbbbbb bbbbbbbbb bbbbbbbbb ccc cccccccccc ccccccc cccccccc */
+
+                                                /* * aaaa aaaaaaaaa aaaaaaaaa aaaaaaaaa aaaaaaaaa bbbbbbbbbb bbbbbbbbb bbbbbbbbb ccc cccccccccc ccccccc cccccccc */
+                                            };
+                                        };
+                                    };
+                                };
+                            };
+                        };
+                    };
+                };
+            };
+        };
+    };
+}
diff --git a/src/tools/rustfmt/tests/source/issue-5088/start_with_empty_comment_very_long_itemized_block_wrap_comments_true.rs b/src/tools/rustfmt/tests/source/issue-5088/start_with_empty_comment_very_long_itemized_block_wrap_comments_true.rs
new file mode 100644
index 00000000000..75f748000f9
--- /dev/null
+++ b/src/tools/rustfmt/tests/source/issue-5088/start_with_empty_comment_very_long_itemized_block_wrap_comments_true.rs
@@ -0,0 +1,19 @@
+// rustfmt-wrap_comments: true
+
+//
+// - Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.
+// - Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.
+
+//
+// * Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.
+// * Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.
+
+/*
+ * - Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.*/
+/*
+ * - Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.*/
+
+/*
+ * * Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.*/
+/*
+ * * Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.*/
diff --git a/src/tools/rustfmt/tests/source/issue-5088/very_long_comment_wrap_comments_true.rs b/src/tools/rustfmt/tests/source/issue-5088/very_long_comment_wrap_comments_true.rs
new file mode 100644
index 00000000000..00437f00216
--- /dev/null
+++ b/src/tools/rustfmt/tests/source/issue-5088/very_long_comment_wrap_comments_true.rs
@@ -0,0 +1,13 @@
+// rustfmt-wrap_comments: true
+
+// - Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.
+// - Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.
+
+// * Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.
+// * Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.
+
+/* - Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.*/
+/* - Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.*/
+
+/* * Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.*/
+/* * Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.*/
diff --git a/src/tools/rustfmt/tests/source/issue_4823.rs b/src/tools/rustfmt/tests/source/issue_4823.rs
new file mode 100644
index 00000000000..a008dd3d838
--- /dev/null
+++ b/src/tools/rustfmt/tests/source/issue_4823.rs
@@ -0,0 +1,5 @@
+macro_rules! m {
+() => {
+type Type;
+};
+}
diff --git a/src/tools/rustfmt/tests/source/issue_5027.rs b/src/tools/rustfmt/tests/source/issue_5027.rs
new file mode 100644
index 00000000000..67beeb23b71
--- /dev/null
+++ b/src/tools/rustfmt/tests/source/issue_5027.rs
@@ -0,0 +1,7 @@
+// rustfmt-version: Two
+
+pub type Iter<'a, D> =                 impl       DoubleEndedIterator<Item = (SomethingSomethingSomethingLongType<D>)>+ ExactSizeIterator+ 'a;
+
+trait FOo {pub type Iter<'a, D> = impl        DoubleEndedIterator<Item = (SomethingSomethingSomethingLongType<D>)>+ ExactSizeIterator+ 'a;}
+
+impl Bar {pub type Iter<'a, D> = impl             DoubleEndedIterator<Item = (SomethingSomethingSomethingLongType<D>)>+ ExactSizeIterator+ 'a;}
\ No newline at end of file
diff --git a/src/tools/rustfmt/tests/source/issue_5086.rs b/src/tools/rustfmt/tests/source/issue_5086.rs
new file mode 100644
index 00000000000..1644c9d2ccb
--- /dev/null
+++ b/src/tools/rustfmt/tests/source/issue_5086.rs
@@ -0,0 +1,2 @@
+#[cfg(any())]
+    type   Type :   Bound ;
\ No newline at end of file
diff --git a/src/tools/rustfmt/tests/target/comments-in-lists/format-doc-comments.rs b/src/tools/rustfmt/tests/target/comments-in-lists/format-doc-comments.rs
new file mode 100644
index 00000000000..be31bf0a331
--- /dev/null
+++ b/src/tools/rustfmt/tests/target/comments-in-lists/format-doc-comments.rs
@@ -0,0 +1,96 @@
+// rustfmt-format_code_in_doc_comments: true
+
+// https://github.com/rust-lang/rustfmt/issues/4420
+enum Minimal {
+    Example,
+    //[thisisremoved thatsleft
+    // canbeanything
+}
+
+struct Minimal2 {
+    Example: usize,
+    //[thisisremoved thatsleft
+    // canbeanything
+}
+
+pub enum E {
+    // Expand as needed, numbers should be ascending according to the stage
+    // through the inclusion pipeline, or according to the descriptions
+    Variant1,
+    // Expand as needed, numbers should be ascending according to the stage
+    // through the inclusion pipeline, or according to the descriptions
+    Variant2,
+    // Expand as needed, numbers should be ascending according to the stage
+    // through the inclusion pipeline, or according to the descriptions
+}
+
+pub enum E2 {
+    // This can be changed once https://github.com/rust-lang/rustfmt/issues/4854 is fixed
+// Expand as needed, numbers should be ascending according to the stage
+// through the inclusion pipeline, or according to the descriptions
+}
+
+pub struct S {
+    // Expand as needed, numbers should be ascending according to the stage
+    // through the inclusion pipeline, or according to the descriptions
+    some_field: usize,
+    // Expand as needed, numbers should be ascending according to the stage
+    // through the inclusion pipeline, or according to the descriptions
+    last_field: usize,
+    // Expand as needed, numbers should be ascending according to the stage
+    // through the inclusion pipeline, or according to the descriptions
+}
+
+pub struct S2 {
+    // This can be changed once https://github.com/rust-lang/rustfmt/issues/4854 is fixed
+// Expand as needed, numbers should be ascending according to the stage
+// through the inclusion pipeline, or according to the descriptions
+}
+
+fn foo(
+    // Expand as needed, numbers should be ascending according to the stage
+    // through the inclusion pipeline, or according to the descriptions
+    a: usize,
+    // Expand as needed, numbers should be ascending according to the stage
+    // through the inclusion pipeline, or according to the descriptions
+    b: usize,
+    // Expand as needed, numbers should be ascending according to the stage
+    // through the inclusion pipeline, or according to the descriptions
+) -> usize {
+    5
+}
+
+fn foo2(// Expand as needed, numbers should be ascending according to the stage
+    // through the inclusion pipeline, or according to the descriptions
+) -> usize {
+    5
+}
+
+fn main() {
+    let v = vec![
+        // Expand as needed, numbers should be ascending according to the stage
+        // through the inclusion pipeline, or according to the descriptions
+        1,
+        // Expand as needed, numbers should be ascending according to the stage
+        // through the inclusion pipeline, or according to the descriptions
+        2,
+        // Expand as needed, numbers should be ascending according to the stage
+        // through the inclusion pipeline, or according to the descriptions
+    ];
+
+    let v2: Vec<i32> = vec![
+        // Expand as needed, numbers should be ascending according to the stage
+        // through the inclusion pipeline, or according to the descriptions
+    ];
+
+    match a {
+        // Expand as needed, numbers should be ascending according to the stage
+        // through the inclusion pipeline, or according to the descriptions
+        b => c,
+        // Expand as needed, numbers should be ascending according to the stage
+        // through the inclusion pipeline, or according to the descriptions
+        d => e,
+        // Expand as needed, numbers should be ascending according to the stage
+        // through the inclusion pipeline, or according to the descriptions
+    }
+}
diff --git a/src/tools/rustfmt/tests/target/comments-in-lists/wrap-comments-false.rs b/src/tools/rustfmt/tests/target/comments-in-lists/wrap-comments-false.rs
new file mode 100644
index 00000000000..80aea59d1b5
--- /dev/null
+++ b/src/tools/rustfmt/tests/target/comments-in-lists/wrap-comments-false.rs
@@ -0,0 +1,85 @@
+// rustfmt-normalize_comments: true
+
+// https://github.com/rust-lang/rustfmt/issues/4909
+pub enum E {
+    // Expand as needed, numbers should be ascending according to the stage
+    // through the inclusion pipeline, or according to the descriptions
+    Variant1,
+    // Expand as needed, numbers should be ascending according to the stage
+    // through the inclusion pipeline, or according to the descriptions
+    Variant2,
+    // Expand as needed, numbers should be ascending according to the stage
+    // through the inclusion pipeline, or according to the descriptions
+}
+
+pub enum E2 {
+    // This can be changed once https://github.com/rust-lang/rustfmt/issues/4854 is fixed
+// Expand as needed, numbers should be ascending according to the stage
+// through the inclusion pipeline, or according to the descriptions
+}
+
+pub struct S {
+    // Expand as needed, numbers should be ascending according to the stage
+    // through the inclusion pipeline, or according to the descriptions
+    some_field: usize,
+    // Expand as needed, numbers should be ascending according to the stage
+    // through the inclusion pipeline, or according to the descriptions
+    last_field: usize,
+    // Expand as needed, numbers should be ascending according to the stage
+    // through the inclusion pipeline, or according to the descriptions
+}
+
+pub struct S2 {
+    // This can be changed once https://github.com/rust-lang/rustfmt/issues/4854 is fixed
+// Expand as needed, numbers should be ascending according to the stage
+// through the inclusion pipeline, or according to the descriptions
+}
+
+fn foo(
+    // Expand as needed, numbers should be ascending according to the stage
+    // through the inclusion pipeline, or according to the descriptions
+    a: usize,
+    // Expand as needed, numbers should be ascending according to the stage
+    // through the inclusion pipeline, or according to the descriptions
+    b: usize,
+    // Expand as needed, numbers should be ascending according to the stage
+    // through the inclusion pipeline, or according to the descriptions
+) -> usize {
+    5
+}
+
+fn foo2(// Expand as needed, numbers should be ascending according to the stage
+    // through the inclusion pipeline, or according to the descriptions
+) -> usize {
+    5
+}
+
+fn main() {
+    let v = vec![
+        // Expand as needed, numbers should be ascending according to the stage
+        // through the inclusion pipeline, or according to the descriptions
+        1,
+        // Expand as needed, numbers should be ascending according to the stage
+        // through the inclusion pipeline, or according to the descriptions
+        2,
+        // Expand as needed, numbers should be ascending according to the stage
+        // through the inclusion pipeline, or according to the descriptions
+    ];
+
+    let v2: Vec<i32> = vec![
+        // Expand as needed, numbers should be ascending according to the stage
+        // through the inclusion pipeline, or according to the descriptions
+    ];
+
+    // https://github.com/rust-lang/rustfmt/issues/4430
+    match a {
+        // Expand as needed, numbers should be ascending according to the stage
+        // through the inclusion pipeline, or according to the descriptions
+        b => c,
+        // Expand as needed, numbers should be ascending according to the stage
+        // through the inclusion pipeline, or according to the descriptions
+        d => e,
+        // Expand as needed, numbers should be ascending according to the stage
+        // through the inclusion pipeline, or according to the descriptions
+    }
+}
diff --git a/src/tools/rustfmt/tests/target/comments-in-lists/wrap-comments-not-normalized.rs b/src/tools/rustfmt/tests/target/comments-in-lists/wrap-comments-not-normalized.rs
new file mode 100644
index 00000000000..52315f470e4
--- /dev/null
+++ b/src/tools/rustfmt/tests/target/comments-in-lists/wrap-comments-not-normalized.rs
@@ -0,0 +1,142 @@
+// rustfmt-wrap_comments: true
+
+// https://github.com/rust-lang/rustfmt/issues/4909
+pub enum E {
+    // Expand as needed, numbers should be ascending according to the stage
+    // through the inclusion pipeline, or according to the descriptions
+    Variant1,
+    // Expand as needed, numbers should be ascending according to the stage
+    // through the inclusion pipeline, or according to the descriptions
+    Variant2,
+    // Expand as needed, numbers should be ascending according to the stage
+    // through the inclusion pipeline, or according to the descriptions
+}
+
+pub enum E2 {
+    // This can be changed once https://github.com/rust-lang/rustfmt/issues/4854 is fixed
+// Expand as needed, numbers should be ascending according to the stage
+// through the inclusion pipeline, or according to the descriptions
+}
+
+pub enum E3 {
+    // Expand as needed, numbers should be ascending according to the stage through the inclusion
+    // pipeline, or according to the descriptions
+    Variant1,
+    // Expand as needed, numbers should be ascending according to the stage through the inclusion
+    // pipeline, or according to the descriptions
+    Variant2,
+    // Expand as needed, numbers should be ascending according to the stage through the inclusion
+    // pipeline, or according to the descriptions
+}
+
+pub struct S {
+    // Expand as needed, numbers should be ascending according to the stage
+    // through the inclusion pipeline, or according to the descriptions
+    some_field: usize,
+    // Expand as needed, numbers should be ascending according to the stage
+    // through the inclusion pipeline, or according to the descriptions
+    last_field: usize,
+    // Expand as needed, numbers should be ascending according to the stage
+    // through the inclusion pipeline, or according to the descriptions
+}
+
+pub struct S2 {
+    // This can be changed once https://github.com/rust-lang/rustfmt/issues/4854 is fixed
+// Expand as needed, numbers should be ascending according to the stage
+// through the inclusion pipeline, or according to the descriptions
+}
+
+pub struct S3 {
+    // Expand as needed, numbers should be ascending according to the stage through the inclusion
+    // pipeline, or according to the descriptions
+    some_field: usize,
+    // Expand as needed, numbers should be ascending according to the stage through the inclusion
+    // pipeline, or according to the descriptions
+    last_field: usize,
+    // Expand as needed, numbers should be ascending according to the stage through the inclusion
+    // pipeline, or according to the descriptions
+}
+
+fn foo(
+    // Expand as needed, numbers should be ascending according to the stage
+    // through the inclusion pipeline, or according to the descriptions
+    a: usize,
+    // Expand as needed, numbers should be ascending according to the stage
+    // through the inclusion pipeline, or according to the descriptions
+    b: usize,
+    // Expand as needed, numbers should be ascending according to the stage
+    // through the inclusion pipeline, or according to the descriptions
+) -> usize {
+    5
+}
+
+fn foo2(// Expand as needed, numbers should be ascending according to the stage
+    // through the inclusion pipeline, or according to the descriptions
+) -> usize {
+    5
+}
+
+fn foo3(
+    // Expand as needed, numbers should be ascending according to the stage through the inclusion
+    // pipeline, or according to the descriptions
+    a: usize,
+    // Expand as needed, numbers should be ascending according to the stage through the inclusion
+    // pipeline, or according to the descriptions
+    b: usize,
+    // Expand as needed, numbers should be ascending according to the stage through the inclusion
+    // pipeline, or according to the descriptions
+) -> usize {
+    5
+}
+
+fn main() {
+    let v = vec![
+        // Expand as needed, numbers should be ascending according to the stage
+        // through the inclusion pipeline, or according to the descriptions
+        1,
+        // Expand as needed, numbers should be ascending according to the stage
+        // through the inclusion pipeline, or according to the descriptions
+        2,
+        // Expand as needed, numbers should be ascending according to the stage
+        // through the inclusion pipeline, or according to the descriptions
+    ];
+
+    let v2: Vec<i32> = vec![
+        // Expand as needed, numbers should be ascending according to the stage
+        // through the inclusion pipeline, or according to the descriptions
+    ];
+
+    let v3 = vec![
+        // Expand as needed, numbers should be ascending according to the stage through the
+        // inclusion pipeline, or according to the descriptions
+        1,
+        // Expand as needed, numbers should be ascending according to the stage through the
+        // inclusion pipeline, or according to the descriptions
+        2,
+        // Expand as needed, numbers should be ascending according to the stage through the
+        // inclusion pipeline, or according to the descriptions
+    ];
+
+    // https://github.com/rust-lang/rustfmt/issues/4430
+    match a {
+        // Expand as needed, numbers should be ascending according to the stage
+        // through the inclusion pipeline, or according to the descriptions
+        b => c,
+        // Expand as needed, numbers should be ascending according to the stage
+        // through the inclusion pipeline, or according to the descriptions
+        d => e,
+        // Expand as needed, numbers should be ascending according to the stage
+        // through the inclusion pipeline, or according to the descriptions
+    }
+
+    match a {
+        // Expand as needed, numbers should be ascending according to the stage through the
+        // inclusion pipeline, or according to the descriptions
+        b => c,
+        // Expand as needed, numbers should be ascending according to the stage through the
+        // inclusion pipeline, or according to the descriptions
+        d => e,
+        // Expand as needed, numbers should be ascending according to the stage through the
+        // inclusion pipeline, or according to the descriptions
+    }
+}
diff --git a/src/tools/rustfmt/tests/target/comments-in-lists/wrap-comments-true.rs b/src/tools/rustfmt/tests/target/comments-in-lists/wrap-comments-true.rs
new file mode 100644
index 00000000000..e0bfcf0b500
--- /dev/null
+++ b/src/tools/rustfmt/tests/target/comments-in-lists/wrap-comments-true.rs
@@ -0,0 +1,143 @@
+// rustfmt-normalize_comments: true
+// rustfmt-wrap_comments: true
+
+// https://github.com/rust-lang/rustfmt/issues/4909
+pub enum E {
+    // Expand as needed, numbers should be ascending according to the stage
+    // through the inclusion pipeline, or according to the descriptions
+    Variant1,
+    // Expand as needed, numbers should be ascending according to the stage
+    // through the inclusion pipeline, or according to the descriptions
+    Variant2,
+    // Expand as needed, numbers should be ascending according to the stage
+    // through the inclusion pipeline, or according to the descriptions
+}
+
+pub enum E2 {
+    // This can be changed once https://github.com/rust-lang/rustfmt/issues/4854 is fixed
+// Expand as needed, numbers should be ascending according to the stage
+// through the inclusion pipeline, or according to the descriptions
+}
+
+pub enum E3 {
+    // Expand as needed, numbers should be ascending according to the stage through the inclusion
+    // pipeline, or according to the descriptions
+    Variant1,
+    // Expand as needed, numbers should be ascending according to the stage through the inclusion
+    // pipeline, or according to the descriptions
+    Variant2,
+    // Expand as needed, numbers should be ascending according to the stage through the inclusion
+    // pipeline, or according to the descriptions
+}
+
+pub struct S {
+    // Expand as needed, numbers should be ascending according to the stage
+    // through the inclusion pipeline, or according to the descriptions
+    some_field: usize,
+    // Expand as needed, numbers should be ascending according to the stage
+    // through the inclusion pipeline, or according to the descriptions
+    last_field: usize,
+    // Expand as needed, numbers should be ascending according to the stage
+    // through the inclusion pipeline, or according to the descriptions
+}
+
+pub struct S2 {
+    // This can be changed once https://github.com/rust-lang/rustfmt/issues/4854 is fixed
+// Expand as needed, numbers should be ascending according to the stage
+// through the inclusion pipeline, or according to the descriptions
+}
+
+pub struct S3 {
+    // Expand as needed, numbers should be ascending according to the stage through the inclusion
+    // pipeline, or according to the descriptions
+    some_field: usize,
+    // Expand as needed, numbers should be ascending according to the stage through the inclusion
+    // pipeline, or according to the descriptions
+    last_field: usize,
+    // Expand as needed, numbers should be ascending according to the stage through the inclusion
+    // pipeline, or according to the descriptions
+}
+
+fn foo(
+    // Expand as needed, numbers should be ascending according to the stage
+    // through the inclusion pipeline, or according to the descriptions
+    a: usize,
+    // Expand as needed, numbers should be ascending according to the stage
+    // through the inclusion pipeline, or according to the descriptions
+    b: usize,
+    // Expand as needed, numbers should be ascending according to the stage
+    // through the inclusion pipeline, or according to the descriptions
+) -> usize {
+    5
+}
+
+fn foo2(// Expand as needed, numbers should be ascending according to the stage
+    // through the inclusion pipeline, or according to the descriptions
+) -> usize {
+    5
+}
+
+fn foo3(
+    // Expand as needed, numbers should be ascending according to the stage through the inclusion
+    // pipeline, or according to the descriptions
+    a: usize,
+    // Expand as needed, numbers should be ascending according to the stage through the inclusion
+    // pipeline, or according to the descriptions
+    b: usize,
+    // Expand as needed, numbers should be ascending according to the stage through the inclusion
+    // pipeline, or according to the descriptions
+) -> usize {
+    5
+}
+
+fn main() {
+    let v = vec![
+        // Expand as needed, numbers should be ascending according to the stage
+        // through the inclusion pipeline, or according to the descriptions
+        1,
+        // Expand as needed, numbers should be ascending according to the stage
+        // through the inclusion pipeline, or according to the descriptions
+        2,
+        // Expand as needed, numbers should be ascending according to the stage
+        // through the inclusion pipeline, or according to the descriptions
+    ];
+
+    let v2: Vec<i32> = vec![
+        // Expand as needed, numbers should be ascending according to the stage
+        // through the inclusion pipeline, or according to the descriptions
+    ];
+
+    let v3 = vec![
+        // Expand as needed, numbers should be ascending according to the stage through the
+        // inclusion pipeline, or according to the descriptions
+        1,
+        // Expand as needed, numbers should be ascending according to the stage through the
+        // inclusion pipeline, or according to the descriptions
+        2,
+        // Expand as needed, numbers should be ascending according to the stage through the
+        // inclusion pipeline, or according to the descriptions
+    ];
+
+    // https://github.com/rust-lang/rustfmt/issues/4430
+    match a {
+        // Expand as needed, numbers should be ascending according to the stage
+        // through the inclusion pipeline, or according to the descriptions
+        b => c,
+        // Expand as needed, numbers should be ascending according to the stage
+        // through the inclusion pipeline, or according to the descriptions
+        d => e,
+        // Expand as needed, numbers should be ascending according to the stage
+        // through the inclusion pipeline, or according to the descriptions
+    }
+
+    match a {
+        // Expand as needed, numbers should be ascending according to the stage through the
+        // inclusion pipeline, or according to the descriptions
+        b => c,
+        // Expand as needed, numbers should be ascending according to the stage through the
+        // inclusion pipeline, or according to the descriptions
+        d => e,
+        // Expand as needed, numbers should be ascending according to the stage through the
+        // inclusion pipeline, or according to the descriptions
+    }
+}
diff --git a/src/tools/rustfmt/tests/target/issue-5088/deeply_nested_long_comment_wrap_comments_false.rs b/src/tools/rustfmt/tests/target/issue-5088/deeply_nested_long_comment_wrap_comments_false.rs
new file mode 100644
index 00000000000..f4801de0184
--- /dev/null
+++ b/src/tools/rustfmt/tests/target/issue-5088/deeply_nested_long_comment_wrap_comments_false.rs
@@ -0,0 +1,33 @@
+// rustfmt-wrap_comments: false
+
+fn main() {
+    {
+        {
+            {
+                {
+                    {
+                        {
+                            {
+                                {
+                                    {
+                                        {
+                                            {
+                                                // - aaaa aaaaaaaaa aaaaaaaaa aaaaaaaaa aaaaaaaaa bbbbbbbbbb bbbbbbbbb bbbbbbbbb ccc cccccccccc ccccccc cccccccc
+
+                                                // * aaaa aaaaaaaaa aaaaaaaaa aaaaaaaaa aaaaaaaaa bbbbbbbbbb bbbbbbbbb bbbbbbbbb ccc cccccccccc ccccccc cccccccc
+
+                                                /* - aaaa aaaaaaaaa aaaaaaaaa aaaaaaaaa aaaaaaaaa bbbbbbbbbb bbbbbbbbb bbbbbbbbb ccc cccccccccc ccccccc cccccccc */
+
+                                                /* * aaaa aaaaaaaaa aaaaaaaaa aaaaaaaaa aaaaaaaaa bbbbbbbbbb bbbbbbbbb bbbbbbbbb ccc cccccccccc ccccccc cccccccc */
+                                            };
+                                        };
+                                    };
+                                };
+                            };
+                        };
+                    };
+                };
+            };
+        };
+    };
+}
diff --git a/src/tools/rustfmt/tests/target/issue-5088/deeply_nested_long_comment_wrap_comments_true.rs b/src/tools/rustfmt/tests/target/issue-5088/deeply_nested_long_comment_wrap_comments_true.rs
new file mode 100644
index 00000000000..b289c9f859e
--- /dev/null
+++ b/src/tools/rustfmt/tests/target/issue-5088/deeply_nested_long_comment_wrap_comments_true.rs
@@ -0,0 +1,49 @@
+// rustfmt-wrap_comments: true
+
+fn main() {
+    {
+        {
+            {
+                {
+                    {
+                        {
+                            {
+                                {
+                                    {
+                                        {
+                                            {
+                                                // - aaaa aaaaaaaaa aaaaaaaaa
+                                                //   aaaaaaaaa aaaaaaaaa
+                                                //   bbbbbbbbbb bbbbbbbbb
+                                                //   bbbbbbbbb ccc cccccccccc
+                                                //   ccccccc cccccccc
+
+                                                // * aaaa aaaaaaaaa aaaaaaaaa
+                                                //   aaaaaaaaa aaaaaaaaa
+                                                //   bbbbbbbbbb bbbbbbbbb
+                                                //   bbbbbbbbb ccc cccccccccc
+                                                //   ccccccc cccccccc
+
+                                                /* - aaaa aaaaaaaaa aaaaaaaaa
+                                                 *   aaaaaaaaa aaaaaaaaa
+                                                 *   bbbbbbbbbb bbbbbbbbb
+                                                 *   bbbbbbbbb ccc cccccccccc
+                                                 *   ccccccc cccccccc */
+
+                                                /* * aaaa aaaaaaaaa aaaaaaaaa
+                                                 *   aaaaaaaaa aaaaaaaaa
+                                                 *   bbbbbbbbbb bbbbbbbbb
+                                                 *   bbbbbbbbb ccc cccccccccc
+                                                 *   ccccccc cccccccc */
+                                            };
+                                        };
+                                    };
+                                };
+                            };
+                        };
+                    };
+                };
+            };
+        };
+    };
+}
diff --git a/src/tools/rustfmt/tests/target/issue-5088/multi_line_itemized_block_wrap_comments_false.rs b/src/tools/rustfmt/tests/target/issue-5088/multi_line_itemized_block_wrap_comments_false.rs
new file mode 100644
index 00000000000..60beed1b048
--- /dev/null
+++ b/src/tools/rustfmt/tests/target/issue-5088/multi_line_itemized_block_wrap_comments_false.rs
@@ -0,0 +1,17 @@
+// rustfmt-wrap_comments: false
+
+// - some itemized block 1
+// - some itemized block 2
+
+// * some itemized block 3
+// * some itemized block 4
+
+/*
+ * - some itemized block 5
+ * - some itemized block 6
+ */
+
+/*
+ * * some itemized block 7
+ * * some itemized block 8
+ */
diff --git a/src/tools/rustfmt/tests/target/issue-5088/multi_line_itemized_block_wrap_comments_true.rs b/src/tools/rustfmt/tests/target/issue-5088/multi_line_itemized_block_wrap_comments_true.rs
new file mode 100644
index 00000000000..84fba4b7c19
--- /dev/null
+++ b/src/tools/rustfmt/tests/target/issue-5088/multi_line_itemized_block_wrap_comments_true.rs
@@ -0,0 +1,17 @@
+// rustfmt-wrap_comments: true
+
+// - some itemized block 1
+// - some itemized block 2
+
+// * some itemized block 3
+// * some itemized block 4
+
+/*
+ * - some itemized block 5
+ * - some itemized block 6
+ */
+
+/*
+ * * some itemized block 7
+ * * some itemized block 8
+ */
diff --git a/src/tools/rustfmt/tests/target/issue-5088/multi_line_text_with_itemized_block_wrap_comments_false.rs b/src/tools/rustfmt/tests/target/issue-5088/multi_line_text_with_itemized_block_wrap_comments_false.rs
new file mode 100644
index 00000000000..d1bf44f6c74
--- /dev/null
+++ b/src/tools/rustfmt/tests/target/issue-5088/multi_line_text_with_itemized_block_wrap_comments_false.rs
@@ -0,0 +1,37 @@
+// rustfmt-wrap_comments: false
+
+// Some text
+// - some itemized block 1
+// - some itemized block 2
+// Some more text
+// - some itemized block 3
+// - some itemized block 4
+// Even more text
+
+// Some text
+// * some itemized block 5
+// * some itemized block 6
+// Some more text
+// * some itemized block 7
+// * some itemized block 8
+// Even more text
+
+/*
+ * Some text
+ * - some itemized block 9
+ * - some itemized block 10
+ * Some more text
+ * - some itemized block 11
+ * - some itemized block 12
+ * Even more text
+ */
+
+/*
+ * Some text
+ * * some itemized block 13
+ * * some itemized block 14
+ * Some more text
+ * * some itemized block 15
+ * * some itemized block 16
+ * Even more text
+ */
diff --git a/src/tools/rustfmt/tests/target/issue-5088/multi_line_text_with_itemized_block_wrap_comments_true.rs b/src/tools/rustfmt/tests/target/issue-5088/multi_line_text_with_itemized_block_wrap_comments_true.rs
new file mode 100644
index 00000000000..f767491f902
--- /dev/null
+++ b/src/tools/rustfmt/tests/target/issue-5088/multi_line_text_with_itemized_block_wrap_comments_true.rs
@@ -0,0 +1,37 @@
+// rustfmt-wrap_comments: true
+
+// Some text
+// - some itemized block 1
+// - some itemized block 2
+// Some more text
+// - some itemized block 3
+// - some itemized block 4
+// Even more text
+
+// Some text
+// * some itemized block 5
+// * some itemized block 6
+// Some more text
+// * some itemized block 7
+// * some itemized block 8
+// Even more text
+
+/*
+ * Some text
+ * - some itemized block 9
+ * - some itemized block 10
+ * Some more text
+ * - some itemized block 11
+ * - some itemized block 12
+ * Even more text
+ */
+
+/*
+ * Some text
+ * * some itemized block 13
+ * * some itemized block 14
+ * Some more text
+ * * some itemized block 15
+ * * some itemized block 16
+ * Even more text
+ */
diff --git a/src/tools/rustfmt/tests/target/issue-5088/single_line_itemized_block_wrap_comments_false.rs b/src/tools/rustfmt/tests/target/issue-5088/single_line_itemized_block_wrap_comments_false.rs
new file mode 100644
index 00000000000..2cd85c787f9
--- /dev/null
+++ b/src/tools/rustfmt/tests/target/issue-5088/single_line_itemized_block_wrap_comments_false.rs
@@ -0,0 +1,9 @@
+// rustfmt-wrap_comments: false
+
+// - some itemized block 1
+
+// * some itemized block 2
+
+/* - some itemized block 3 */
+
+/* * some itemized block 4 */
diff --git a/src/tools/rustfmt/tests/target/issue-5088/single_line_itemized_block_wrap_comments_true.rs b/src/tools/rustfmt/tests/target/issue-5088/single_line_itemized_block_wrap_comments_true.rs
new file mode 100644
index 00000000000..e9f343d75d5
--- /dev/null
+++ b/src/tools/rustfmt/tests/target/issue-5088/single_line_itemized_block_wrap_comments_true.rs
@@ -0,0 +1,9 @@
+// rustfmt-wrap_comments: true
+
+// - some itemized block 1
+
+// * some itemized block 2
+
+/* - some itemized block 3 */
+
+/* * some itemized block 4 */
diff --git a/src/tools/rustfmt/tests/target/issue-5088/start_with_empty_comment_very_long_itemized_block_wrap_comments_false.rs b/src/tools/rustfmt/tests/target/issue-5088/start_with_empty_comment_very_long_itemized_block_wrap_comments_false.rs
new file mode 100644
index 00000000000..97bb7733d18
--- /dev/null
+++ b/src/tools/rustfmt/tests/target/issue-5088/start_with_empty_comment_very_long_itemized_block_wrap_comments_false.rs
@@ -0,0 +1,19 @@
+// rustfmt-wrap_comments: false
+
+//
+// - Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.
+// - Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.
+
+//
+// * Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.
+// * Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.
+
+/*
+ * - Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.*/
+/*
+ * - Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.*/
+
+/*
+ * * Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.*/
+/*
+ * * Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.*/
diff --git a/src/tools/rustfmt/tests/target/issue-5088/start_with_empty_comment_very_long_itemized_block_wrap_comments_true.rs b/src/tools/rustfmt/tests/target/issue-5088/start_with_empty_comment_very_long_itemized_block_wrap_comments_true.rs
new file mode 100644
index 00000000000..c8af8383e05
--- /dev/null
+++ b/src/tools/rustfmt/tests/target/issue-5088/start_with_empty_comment_very_long_itemized_block_wrap_comments_true.rs
@@ -0,0 +1,27 @@
+// rustfmt-wrap_comments: true
+
+//
+// - Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod
+//   tempor incididunt ut labore et dolore magna aliqua.
+// - Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod
+//   tempor incididunt ut labore et dolore magna aliqua.
+
+//
+// * Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod
+//   tempor incididunt ut labore et dolore magna aliqua.
+// * Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod
+//   tempor incididunt ut labore et dolore magna aliqua.
+
+/*
+ * - Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod
+ *   tempor incididunt ut labore et dolore magna aliqua. */
+/*
+ * - Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod
+ *   tempor incididunt ut labore et dolore magna aliqua. */
+
+/*
+ * * Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod
+ *   tempor incididunt ut labore et dolore magna aliqua. */
+/*
+ * * Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod
+ *   tempor incididunt ut labore et dolore magna aliqua. */
diff --git a/src/tools/rustfmt/tests/target/issue-5088/start_with_empty_comment_wrap_comments_false.rs b/src/tools/rustfmt/tests/target/issue-5088/start_with_empty_comment_wrap_comments_false.rs
new file mode 100644
index 00000000000..75cc42c0e66
--- /dev/null
+++ b/src/tools/rustfmt/tests/target/issue-5088/start_with_empty_comment_wrap_comments_false.rs
@@ -0,0 +1,17 @@
+// rustfmt-wrap_comments: false
+
+//
+// - some itemized block 1
+// - some itemized block 2
+
+//
+// * some itemized block 3
+// * some itemized block 4
+
+/*
+ * - some itemized block 5
+ * - some itemized block 6 */
+
+/*
+ * * some itemized block 7
+ * * some itemized block 8 */
diff --git a/src/tools/rustfmt/tests/target/issue-5088/start_with_empty_comment_wrap_comments_true.rs b/src/tools/rustfmt/tests/target/issue-5088/start_with_empty_comment_wrap_comments_true.rs
new file mode 100644
index 00000000000..ef2c8f90cd3
--- /dev/null
+++ b/src/tools/rustfmt/tests/target/issue-5088/start_with_empty_comment_wrap_comments_true.rs
@@ -0,0 +1,17 @@
+// rustfmt-wrap_comments: true
+
+//
+// - some itemized block 1
+// - some itemized block 2
+
+//
+// * some itemized block 3
+// * some itemized block 4
+
+/*
+ * - some itemized block 5
+ * - some itemized block 6 */
+
+/*
+ * * some itemized block 7
+ * * some itemized block 8 */
diff --git a/src/tools/rustfmt/tests/target/issue-5088/very_long_comment_wrap_comments_false.rs b/src/tools/rustfmt/tests/target/issue-5088/very_long_comment_wrap_comments_false.rs
new file mode 100644
index 00000000000..c826cc5d4da
--- /dev/null
+++ b/src/tools/rustfmt/tests/target/issue-5088/very_long_comment_wrap_comments_false.rs
@@ -0,0 +1,13 @@
+// rustfmt-wrap_comments: false
+
+// - Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.
+// - Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.
+
+// * Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.
+// * Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.
+
+/* - Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.*/
+/* - Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.*/
+
+/* * Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.*/
+/* * Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.*/
diff --git a/src/tools/rustfmt/tests/target/issue-5088/very_long_comment_wrap_comments_true.rs b/src/tools/rustfmt/tests/target/issue-5088/very_long_comment_wrap_comments_true.rs
new file mode 100644
index 00000000000..7f764dbd8a2
--- /dev/null
+++ b/src/tools/rustfmt/tests/target/issue-5088/very_long_comment_wrap_comments_true.rs
@@ -0,0 +1,21 @@
+// rustfmt-wrap_comments: true
+
+// - Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod
+//   tempor incididunt ut labore et dolore magna aliqua.
+// - Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod
+//   tempor incididunt ut labore et dolore magna aliqua.
+
+// * Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod
+//   tempor incididunt ut labore et dolore magna aliqua.
+// * Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod
+//   tempor incididunt ut labore et dolore magna aliqua.
+
+/* - Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod
+ *   tempor incididunt ut labore et dolore magna aliqua. */
+/* - Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod
+ *   tempor incididunt ut labore et dolore magna aliqua. */
+
+/* * Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod
+ *   tempor incididunt ut labore et dolore magna aliqua. */
+/* * Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod
+ *   tempor incididunt ut labore et dolore magna aliqua. */
diff --git a/src/tools/rustfmt/tests/target/issue-5095.rs b/src/tools/rustfmt/tests/target/issue-5095.rs
new file mode 100644
index 00000000000..6981a65808c
--- /dev/null
+++ b/src/tools/rustfmt/tests/target/issue-5095.rs
@@ -0,0 +1,27 @@
+// rustfmt-wrap_comments: true
+
+pub mod a_long_name {
+    pub mod b_long_name {
+        pub mod c_long_name {
+            pub mod d_long_name {
+                pub mod e_long_name {
+                    pub struct Bananas;
+                    impl Bananas {
+                        pub fn fantastic() {}
+                    }
+
+                    pub mod f_long_name {
+                        pub struct Apples;
+                    }
+                }
+            }
+        }
+    }
+}
+
+/// Check out [my other struct] ([`Bananas`]) and [the method it has].
+///
+/// [my other struct]: a_long_name::b_long_name::c_long_name::d_long_name::e_long_name::f_long_name::Apples
+/// [`Bananas`]: a_long_name::b_long_name::c_long_name::d_long_name::e_long_name::Bananas::fantastic()
+/// [the method it has]: a_long_name::b_long_name::c_long_name::d_long_name::e_long_name::Bananas::fantastic()
+pub struct A;
diff --git a/src/tools/rustfmt/tests/target/issue_4823.rs b/src/tools/rustfmt/tests/target/issue_4823.rs
new file mode 100644
index 00000000000..de17467c0ef
--- /dev/null
+++ b/src/tools/rustfmt/tests/target/issue_4823.rs
@@ -0,0 +1,5 @@
+macro_rules! m {
+    () => {
+        type Type;
+    };
+}
diff --git a/src/tools/rustfmt/tests/target/issue_5027.rs b/src/tools/rustfmt/tests/target/issue_5027.rs
new file mode 100644
index 00000000000..26d771720b6
--- /dev/null
+++ b/src/tools/rustfmt/tests/target/issue_5027.rs
@@ -0,0 +1,17 @@
+// rustfmt-version: Two
+
+pub type Iter<'a, D> = impl DoubleEndedIterator<Item = (SomethingSomethingSomethingLongType<D>)>
+    + ExactSizeIterator
+    + 'a;
+
+trait FOo {
+    pub type Iter<'a, D> = impl DoubleEndedIterator<Item = (SomethingSomethingSomethingLongType<D>)>
+        + ExactSizeIterator
+        + 'a;
+}
+
+impl Bar {
+    type Iter<'a, D> = impl DoubleEndedIterator<Item = (SomethingSomethingSomethingLongType<D>)>
+        + ExactSizeIterator
+        + 'a;
+}
diff --git a/src/tools/rustfmt/tests/target/issue_5086.rs b/src/tools/rustfmt/tests/target/issue_5086.rs
new file mode 100644
index 00000000000..7a0be06f791
--- /dev/null
+++ b/src/tools/rustfmt/tests/target/issue_5086.rs
@@ -0,0 +1,2 @@
+#[cfg(any())]
+type Type: Bound;