about summary refs log tree commit diff
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2024-03-21 13:28:59 +0000
committerbors <bors@rust-lang.org>2024-03-21 13:28:59 +0000
commit2627e9f3012a97d3136b3e11bf6bd0853c38a534 (patch)
treea31d7bc829f5121aa89a9442fa6084f79bf84bdb
parent03994e498df79aa1f97f7bbcfd52d57c8e865049 (diff)
parent62e414d3af8ad08aec8c4a0a29e2de1265944592 (diff)
downloadrust-2627e9f3012a97d3136b3e11bf6bd0853c38a534.tar.gz
rust-2627e9f3012a97d3136b3e11bf6bd0853c38a534.zip
Auto merge of #122822 - matthiaskrgr:rollup-rjgmnbe, r=matthiaskrgr
Rollup of 8 pull requests

Successful merges:

 - #122222 (deref patterns: bare-bones feature gate and typechecking)
 - #122358 (Don't ICE when encountering bound regions in generator interior type)
 - #122696 (Add bare metal riscv32 target.)
 - #122773 (make "expected paren or brace" error translatable)
 - #122795 (Inherit `RUSTC_BOOTSTRAP` when testing wasm)
 - #122799 (Replace closures with `_` when suggesting fully qualified path for method call)
 - #122801 (Fix misc printing issues in emit=stable_mir)
 - #122806 (Make `type_ascribe!` not a built-in)

Failed merges:

 - #122771 (add some comments to hir::ModuleItems)

r? `@ghost`
`@rustbot` modify labels: rollup
-rw-r--r--compiler/rustc_ast_passes/src/feature_gate.rs10
-rw-r--r--compiler/rustc_builtin_macros/src/lib.rs2
-rw-r--r--compiler/rustc_builtin_macros/src/type_ascribe.rs35
-rw-r--r--compiler/rustc_expand/messages.ftl3
-rw-r--r--compiler/rustc_expand/src/errors.rs8
-rw-r--r--compiler/rustc_expand/src/mbe/quoted.rs8
-rw-r--r--compiler/rustc_feature/src/unstable.rs2
-rw-r--r--compiler/rustc_hir_analysis/src/astconv/bounds.rs2
-rw-r--r--compiler/rustc_hir_analysis/src/collect.rs6
-rw-r--r--compiler/rustc_hir_analysis/src/collect/type_of.rs6
-rw-r--r--compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs2
-rw-r--r--compiler/rustc_hir_typeck/src/op.rs4
-rw-r--r--compiler/rustc_hir_typeck/src/pat.rs28
-rw-r--r--compiler/rustc_infer/src/infer/error_reporting/need_type_info.rs77
-rw-r--r--compiler/rustc_middle/src/thir.rs9
-rw-r--r--compiler/rustc_middle/src/thir/visit.rs1
-rw-r--r--compiler/rustc_middle/src/ty/diagnostics.rs28
-rw-r--r--compiler/rustc_middle/src/ty/util.rs36
-rw-r--r--compiler/rustc_mir_build/src/build/matches/mod.rs4
-rw-r--r--compiler/rustc_mir_build/src/build/matches/util.rs6
-rw-r--r--compiler/rustc_mir_build/src/check_unsafety.rs3
-rw-r--r--compiler/rustc_mir_build/src/thir/pattern/mod.rs3
-rw-r--r--compiler/rustc_mir_build/src/thir/print.rs6
-rw-r--r--compiler/rustc_parse/src/parser/expr.rs20
-rw-r--r--compiler/rustc_pattern_analysis/src/rustc.rs6
-rw-r--r--compiler/rustc_smir/src/rustc_internal/internal.rs46
-rw-r--r--compiler/rustc_smir/src/rustc_internal/pretty.rs2
-rw-r--r--compiler/rustc_smir/src/rustc_smir/context.rs15
-rw-r--r--compiler/rustc_span/src/symbol.rs1
-rw-r--r--compiler/rustc_target/src/spec/mod.rs1
-rw-r--r--compiler/rustc_target/src/spec/targets/riscv32ima_unknown_none_elf.rs29
-rw-r--r--compiler/rustc_trait_selection/src/solve/assembly/structural_traits.rs36
-rw-r--r--compiler/rustc_trait_selection/src/traits/select/confirmation.rs8
-rw-r--r--compiler/stable_mir/src/compiler_interface.rs10
-rw-r--r--compiler/stable_mir/src/lib.rs6
-rw-r--r--compiler/stable_mir/src/mir/body.rs30
-rw-r--r--compiler/stable_mir/src/mir/mono.rs6
-rw-r--r--compiler/stable_mir/src/mir/pretty.rs521
-rw-r--r--library/core/src/macros/mod.rs4
-rw-r--r--src/bootstrap/src/lib.rs7
-rw-r--r--src/ci/docker/host-x86_64/test-various/Dockerfile4
-rw-r--r--src/doc/rustc/src/platform-support.md1
-rw-r--r--src/doc/rustc/src/platform-support/riscv32-unknown-none-elf.md6
-rw-r--r--src/tools/build-manifest/src/main.rs1
-rw-r--r--src/tools/clippy/clippy_lints/src/box_default.rs4
-rw-r--r--tests/assembly/targets/targets-elf.rs3
-rw-r--r--tests/ui/async-await/send-bound-async-closure.rs3
-rw-r--r--tests/ui/cfg/cfg-false-feature.stderr24
-rw-r--r--tests/ui/feature-gates/feature-gate-deref_patterns.rs9
-rw-r--r--tests/ui/feature-gates/feature-gate-deref_patterns.stderr13
-rw-r--r--tests/ui/pattern/deref-patterns/typeck.rs31
-rw-r--r--tests/ui/raw-ref-op/raw-ref-temp.stderr8
-rw-r--r--tests/ui/reachable/expr_type.stderr1
-rw-r--r--tests/ui/stable-mir-print/basic_function.rs13
-rw-r--r--tests/ui/stable-mir-print/basic_function.stdout266
-rw-r--r--tests/ui/suggestions/types/into-inference-needs-type.rs15
-rw-r--r--tests/ui/suggestions/types/into-inference-needs-type.stderr19
-rw-r--r--tests/ui/traits/suggest-fully-qualified-closure.rs2
-rw-r--r--tests/ui/traits/suggest-fully-qualified-closure.stderr8
-rw-r--r--tests/ui/typeck/issue-91267.stderr2
60 files changed, 751 insertions, 719 deletions
diff --git a/compiler/rustc_ast_passes/src/feature_gate.rs b/compiler/rustc_ast_passes/src/feature_gate.rs
index 2c396a64789..277e82b4e53 100644
--- a/compiler/rustc_ast_passes/src/feature_gate.rs
+++ b/compiler/rustc_ast_passes/src/feature_gate.rs
@@ -413,7 +413,10 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> {
                 }
             }
             PatKind::Box(..) => {
-                gate!(&self, box_patterns, pattern.span, "box pattern syntax is experimental");
+                if !self.features.deref_patterns {
+                    // Allow box patterns under `deref_patterns`.
+                    gate!(&self, box_patterns, pattern.span, "box pattern syntax is experimental");
+                }
             }
             PatKind::Range(_, Some(_), Spanned { node: RangeEnd::Excluded, .. }) => {
                 gate!(
@@ -607,13 +610,16 @@ pub fn check_crate(krate: &ast::Crate, sess: &Session, features: &Features) {
         };
     }
 
+    if !visitor.features.deref_patterns {
+        // Allow box patterns under `deref_patterns`.
+        gate_all_legacy_dont_use!(box_patterns, "box pattern syntax is experimental");
+    }
     gate_all_legacy_dont_use!(trait_alias, "trait aliases are experimental");
     // Despite being a new feature, `where T: Trait<Assoc(): Sized>`, which is RTN syntax now,
     // used to be gated under associated_type_bounds, which are right above, so RTN needs to
     // be too.
     gate_all_legacy_dont_use!(return_type_notation, "return type notation is experimental");
     gate_all_legacy_dont_use!(decl_macro, "`macro` is experimental");
-    gate_all_legacy_dont_use!(box_patterns, "box pattern syntax is experimental");
     gate_all_legacy_dont_use!(
         exclusive_range_pattern,
         "exclusive range pattern syntax is experimental"
diff --git a/compiler/rustc_builtin_macros/src/lib.rs b/compiler/rustc_builtin_macros/src/lib.rs
index f344dbcd10c..554dac0852f 100644
--- a/compiler/rustc_builtin_macros/src/lib.rs
+++ b/compiler/rustc_builtin_macros/src/lib.rs
@@ -49,7 +49,6 @@ mod log_syntax;
 mod source_util;
 mod test;
 mod trace_macros;
-mod type_ascribe;
 mod util;
 
 pub mod asm;
@@ -99,7 +98,6 @@ pub fn register_builtin_macros(resolver: &mut dyn ResolverExpand) {
         std_panic: edition_panic::expand_panic,
         stringify: source_util::expand_stringify,
         trace_macros: trace_macros::expand_trace_macros,
-        type_ascribe: type_ascribe::expand_type_ascribe,
         unreachable: edition_panic::expand_unreachable,
         // tidy-alphabetical-end
     }
diff --git a/compiler/rustc_builtin_macros/src/type_ascribe.rs b/compiler/rustc_builtin_macros/src/type_ascribe.rs
deleted file mode 100644
index f3e66ffc759..00000000000
--- a/compiler/rustc_builtin_macros/src/type_ascribe.rs
+++ /dev/null
@@ -1,35 +0,0 @@
-use rustc_ast::ptr::P;
-use rustc_ast::tokenstream::TokenStream;
-use rustc_ast::{token, Expr, ExprKind, Ty};
-use rustc_errors::PResult;
-use rustc_expand::base::{DummyResult, ExpandResult, ExtCtxt, MacEager, MacroExpanderResult};
-use rustc_span::Span;
-
-pub fn expand_type_ascribe(
-    cx: &mut ExtCtxt<'_>,
-    span: Span,
-    tts: TokenStream,
-) -> MacroExpanderResult<'static> {
-    let (expr, ty) = match parse_ascribe(cx, tts) {
-        Ok(parsed) => parsed,
-        Err(err) => {
-            let guar = err.emit();
-            return ExpandResult::Ready(DummyResult::any(span, guar));
-        }
-    };
-
-    let asc_expr = cx.expr(span, ExprKind::Type(expr, ty));
-
-    ExpandResult::Ready(MacEager::expr(asc_expr))
-}
-
-fn parse_ascribe<'a>(cx: &mut ExtCtxt<'a>, stream: TokenStream) -> PResult<'a, (P<Expr>, P<Ty>)> {
-    let mut parser = cx.new_parser_from_tts(stream);
-
-    let expr = parser.parse_expr()?;
-    parser.expect(&token::Comma)?;
-
-    let ty = parser.parse_ty()?;
-
-    Ok((expr, ty))
-}
diff --git a/compiler/rustc_expand/messages.ftl b/compiler/rustc_expand/messages.ftl
index 1f0488130b2..fdd1a87cae8 100644
--- a/compiler/rustc_expand/messages.ftl
+++ b/compiler/rustc_expand/messages.ftl
@@ -33,6 +33,9 @@ expand_duplicate_matcher_binding = duplicate matcher binding
 expand_expected_comma_in_list =
     expected token: `,`
 
+expand_expected_paren_or_brace =
+    expected `(` or `{"{"}`, found `{$token}`
+
 expand_explain_doc_comment_inner =
     inner doc comments expand to `#![doc = "..."]`, which is what this macro attempted to match
 
diff --git a/compiler/rustc_expand/src/errors.rs b/compiler/rustc_expand/src/errors.rs
index fe901603c73..21ce5e1d81e 100644
--- a/compiler/rustc_expand/src/errors.rs
+++ b/compiler/rustc_expand/src/errors.rs
@@ -448,3 +448,11 @@ pub struct InvalidFragmentSpecifier {
     pub fragment: Ident,
     pub help: String,
 }
+
+#[derive(Diagnostic)]
+#[diag(expand_expected_paren_or_brace)]
+pub struct ExpectedParenOrBrace<'a> {
+    #[primary_span]
+    pub span: Span,
+    pub token: Cow<'a, str>,
+}
diff --git a/compiler/rustc_expand/src/mbe/quoted.rs b/compiler/rustc_expand/src/mbe/quoted.rs
index 5fd3716743b..06c1612ddba 100644
--- a/compiler/rustc_expand/src/mbe/quoted.rs
+++ b/compiler/rustc_expand/src/mbe/quoted.rs
@@ -194,9 +194,11 @@ fn parse_tree<'a>(
                             }
                             Delimiter::Parenthesis => {}
                             _ => {
-                                let tok = pprust::token_kind_to_string(&token::OpenDelim(delim));
-                                let msg = format!("expected `(` or `{{`, found `{tok}`");
-                                sess.dcx().span_err(delim_span.entire(), msg);
+                                let token = pprust::token_kind_to_string(&token::OpenDelim(delim));
+                                sess.dcx().emit_err(errors::ExpectedParenOrBrace {
+                                    span: delim_span.entire(),
+                                    token,
+                                });
                             }
                         }
                     }
diff --git a/compiler/rustc_feature/src/unstable.rs b/compiler/rustc_feature/src/unstable.rs
index a3b13c4d907..1820e172ea5 100644
--- a/compiler/rustc_feature/src/unstable.rs
+++ b/compiler/rustc_feature/src/unstable.rs
@@ -436,6 +436,8 @@ declare_features! (
     (unstable, deprecated_safe, "1.61.0", Some(94978)),
     /// Allows having using `suggestion` in the `#[deprecated]` attribute.
     (unstable, deprecated_suggestion, "1.61.0", Some(94785)),
+    /// Allows deref patterns.
+    (incomplete, deref_patterns, "CURRENT_RUSTC_VERSION", Some(87121)),
     /// Controls errors in trait implementations.
     (unstable, do_not_recommend, "1.67.0", Some(51992)),
     /// Tells rustdoc to automatically generate `#[doc(cfg(...))]`.
diff --git a/compiler/rustc_hir_analysis/src/astconv/bounds.rs b/compiler/rustc_hir_analysis/src/astconv/bounds.rs
index 3067e2d0b71..7a5cb6e9d6f 100644
--- a/compiler/rustc_hir_analysis/src/astconv/bounds.rs
+++ b/compiler/rustc_hir_analysis/src/astconv/bounds.rs
@@ -565,7 +565,7 @@ fn check_assoc_const_binding_type<'tcx>(
     let mut guar = ty.visit_with(&mut collector).break_value();
 
     let ty_note = ty
-        .make_suggestable(tcx, false)
+        .make_suggestable(tcx, false, None)
         .map(|ty| crate::errors::TyOfAssocConstBindingNote { assoc_const, ty });
 
     let enclosing_item_owner_id = tcx
diff --git a/compiler/rustc_hir_analysis/src/collect.rs b/compiler/rustc_hir_analysis/src/collect.rs
index bd56275b159..6c3f99ccc12 100644
--- a/compiler/rustc_hir_analysis/src/collect.rs
+++ b/compiler/rustc_hir_analysis/src/collect.rs
@@ -1371,7 +1371,7 @@ fn infer_return_ty_for_fn_sig<'tcx>(
             // recursive function definition to leak out into the fn sig.
             let mut should_recover = false;
 
-            if let Some(ret_ty) = ret_ty.make_suggestable(tcx, false) {
+            if let Some(ret_ty) = ret_ty.make_suggestable(tcx, false, None) {
                 diag.span_suggestion(
                     ty.span,
                     "replace with the correct return type",
@@ -1449,7 +1449,7 @@ fn suggest_impl_trait<'tcx>(
             let ty::Tuple(types) = *args_tuple.kind() else {
                 return None;
             };
-            let types = types.make_suggestable(tcx, false)?;
+            let types = types.make_suggestable(tcx, false, None)?;
             let maybe_ret =
                 if item_ty.is_unit() { String::new() } else { format!(" -> {item_ty}") };
             Some(format!(
@@ -1507,7 +1507,7 @@ fn suggest_impl_trait<'tcx>(
         // FIXME(compiler-errors): We may benefit from resolving regions here.
         if ocx.select_where_possible().is_empty()
             && let item_ty = infcx.resolve_vars_if_possible(item_ty)
-            && let Some(item_ty) = item_ty.make_suggestable(tcx, false)
+            && let Some(item_ty) = item_ty.make_suggestable(tcx, false, None)
             && let Some(sugg) = formatter(
                 tcx,
                 infcx.resolve_vars_if_possible(args),
diff --git a/compiler/rustc_hir_analysis/src/collect/type_of.rs b/compiler/rustc_hir_analysis/src/collect/type_of.rs
index fd86f2dd1b1..cec01abae4b 100644
--- a/compiler/rustc_hir_analysis/src/collect/type_of.rs
+++ b/compiler/rustc_hir_analysis/src/collect/type_of.rs
@@ -47,7 +47,7 @@ fn anon_const_type_of<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> Ty<'tcx> {
             let ty = tcx.fold_regions(ty, |r, _| {
                 if r.is_erased() { ty::Region::new_error_misc(tcx) } else { r }
             });
-            let (ty, opt_sugg) = if let Some(ty) = ty.make_suggestable(tcx, false) {
+            let (ty, opt_sugg) = if let Some(ty) = ty.make_suggestable(tcx, false, None) {
                 (ty, Some((span, Applicability::MachineApplicable)))
             } else {
                 (ty, None)
@@ -587,7 +587,7 @@ fn infer_placeholder_type<'a>(
                     suggestions.clear();
                 }
 
-                if let Some(ty) = ty.make_suggestable(tcx, false) {
+                if let Some(ty) = ty.make_suggestable(tcx, false, None) {
                     err.span_suggestion(
                         span,
                         format!("provide a type for the {kind}"),
@@ -606,7 +606,7 @@ fn infer_placeholder_type<'a>(
             let mut diag = bad_placeholder(tcx, vec![span], kind);
 
             if !ty.references_error() {
-                if let Some(ty) = ty.make_suggestable(tcx, false) {
+                if let Some(ty) = ty.make_suggestable(tcx, false, None) {
                     diag.span_suggestion(
                         span,
                         "replace with the correct type",
diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs
index 3f6f4cccba7..f4090feee17 100644
--- a/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs
+++ b/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs
@@ -809,7 +809,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                 return true;
             }
             &hir::FnRetTy::DefaultReturn(span) if expected.is_unit() => {
-                if let Some(found) = found.make_suggestable(self.tcx, false) {
+                if let Some(found) = found.make_suggestable(self.tcx, false, None) {
                     err.subdiagnostic(
                         self.dcx(),
                         errors::AddReturnTypeSuggestion::Add { span, found: found.to_string() },
diff --git a/compiler/rustc_hir_typeck/src/op.rs b/compiler/rustc_hir_typeck/src/op.rs
index 79f574aa7fd..8969030d683 100644
--- a/compiler/rustc_hir_typeck/src/op.rs
+++ b/compiler/rustc_hir_typeck/src/op.rs
@@ -601,8 +601,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                                             if let Some(output_def_id) = output_def_id
                                                 && let Some(trait_def_id) = trait_def_id
                                                 && self.tcx.parent(output_def_id) == trait_def_id
-                                                && let Some(output_ty) =
-                                                    output_ty.make_suggestable(self.tcx, false)
+                                                && let Some(output_ty) = output_ty
+                                                    .make_suggestable(self.tcx, false, None)
                                             {
                                                 Some(("Output", output_ty))
                                             } else {
diff --git a/compiler/rustc_hir_typeck/src/pat.rs b/compiler/rustc_hir_typeck/src/pat.rs
index 491da7eb2c2..633f851c7d5 100644
--- a/compiler/rustc_hir_typeck/src/pat.rs
+++ b/compiler/rustc_hir_typeck/src/pat.rs
@@ -18,8 +18,7 @@ use rustc_span::edit_distance::find_best_match_for_name;
 use rustc_span::hygiene::DesugaringKind;
 use rustc_span::source_map::Spanned;
 use rustc_span::symbol::{kw, sym, Ident};
-use rustc_span::Span;
-use rustc_span::{BytePos, DUMMY_SP};
+use rustc_span::{BytePos, Span, DUMMY_SP};
 use rustc_target::abi::FieldIdx;
 use rustc_trait_selection::traits::{ObligationCause, Pattern};
 use ty::VariantDef;
@@ -211,6 +210,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
             PatKind::Tuple(elements, ddpos) => {
                 self.check_pat_tuple(pat.span, elements, ddpos, expected, pat_info)
             }
+            PatKind::Box(inner) if self.tcx.features().deref_patterns => {
+                self.check_pat_deref(pat.span, inner, expected, pat_info)
+            }
             PatKind::Box(inner) => self.check_pat_box(pat.span, inner, expected, pat_info),
             PatKind::Ref(inner, mutbl) => self.check_pat_ref(pat, inner, mutbl, expected, pat_info),
             PatKind::Slice(before, slice, after) => {
@@ -1975,6 +1977,28 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         box_ty
     }
 
+    fn check_pat_deref(
+        &self,
+        span: Span,
+        inner: &'tcx Pat<'tcx>,
+        expected: Ty<'tcx>,
+        pat_info: PatInfo<'tcx, '_>,
+    ) -> Ty<'tcx> {
+        let tcx = self.tcx;
+        // FIXME(deref_patterns): use `DerefPure` for soundness
+        // FIXME(deref_patterns): use `DerefMut` when required
+        // <expected as Deref>::Target
+        let ty = Ty::new_projection(
+            tcx,
+            tcx.require_lang_item(hir::LangItem::DerefTarget, Some(span)),
+            [expected],
+        );
+        let ty = self.normalize(span, ty);
+        let ty = self.try_structurally_resolve_type(span, ty);
+        self.check_pat(inner, ty, pat_info);
+        expected
+    }
+
     // Precondition: Pat is Ref(inner)
     fn check_pat_ref(
         &self,
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 0686994b037..ce9001ccb1c 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
@@ -546,40 +546,55 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
                 }
             }
             InferSourceKind::FullyQualifiedMethodCall { receiver, successor, args, def_id } => {
-                let mut printer = fmt_printer(self, Namespace::ValueNS);
-                printer.print_def_path(def_id, args).unwrap();
-                let def_path = printer.into_buffer();
-
-                // We only care about whether we have to add `&` or `&mut ` for now.
-                // This is the case if the last adjustment is a borrow and the
-                // first adjustment was not a builtin deref.
-                let adjustment = match typeck_results.expr_adjustments(receiver) {
-                    [
-                        Adjustment { kind: Adjust::Deref(None), target: _ },
-                        ..,
-                        Adjustment { kind: Adjust::Borrow(AutoBorrow::Ref(..)), target: _ },
-                    ] => "",
-                    [
-                        ..,
-                        Adjustment { kind: Adjust::Borrow(AutoBorrow::Ref(_, mut_)), target: _ },
-                    ] => hir::Mutability::from(*mut_).ref_prefix_str(),
-                    _ => "",
-                };
+                let placeholder = Some(self.next_ty_var(TypeVariableOrigin {
+                    span: rustc_span::DUMMY_SP,
+                    kind: TypeVariableOriginKind::MiscVariable,
+                }));
+                if let Some(args) = args.make_suggestable(self.infcx.tcx, true, placeholder) {
+                    let mut printer = fmt_printer(self, Namespace::ValueNS);
+                    printer.print_def_path(def_id, args).unwrap();
+                    let def_path = printer.into_buffer();
+
+                    // We only care about whether we have to add `&` or `&mut ` for now.
+                    // This is the case if the last adjustment is a borrow and the
+                    // first adjustment was not a builtin deref.
+                    let adjustment = match typeck_results.expr_adjustments(receiver) {
+                        [
+                            Adjustment { kind: Adjust::Deref(None), target: _ },
+                            ..,
+                            Adjustment { kind: Adjust::Borrow(AutoBorrow::Ref(..)), target: _ },
+                        ] => "",
+                        [
+                            ..,
+                            Adjustment {
+                                kind: Adjust::Borrow(AutoBorrow::Ref(_, mut_)),
+                                target: _,
+                            },
+                        ] => hir::Mutability::from(*mut_).ref_prefix_str(),
+                        _ => "",
+                    };
 
-                multi_suggestions.push(SourceKindMultiSuggestion::new_fully_qualified(
-                    receiver.span,
-                    def_path,
-                    adjustment,
-                    successor,
-                ));
+                    multi_suggestions.push(SourceKindMultiSuggestion::new_fully_qualified(
+                        receiver.span,
+                        def_path,
+                        adjustment,
+                        successor,
+                    ));
+                }
             }
             InferSourceKind::ClosureReturn { ty, data, should_wrap_expr } => {
-                let ty_info = ty_to_string(self, ty, None);
-                multi_suggestions.push(SourceKindMultiSuggestion::new_closure_return(
-                    ty_info,
-                    data,
-                    should_wrap_expr,
-                ));
+                let placeholder = Some(self.next_ty_var(TypeVariableOrigin {
+                    span: rustc_span::DUMMY_SP,
+                    kind: TypeVariableOriginKind::MiscVariable,
+                }));
+                if let Some(ty) = ty.make_suggestable(self.infcx.tcx, true, placeholder) {
+                    let ty_info = ty_to_string(self, ty, None);
+                    multi_suggestions.push(SourceKindMultiSuggestion::new_closure_return(
+                        ty_info,
+                        data,
+                        should_wrap_expr,
+                    ));
+                }
             }
         }
         match error_code {
diff --git a/compiler/rustc_middle/src/thir.rs b/compiler/rustc_middle/src/thir.rs
index 96a61883cc1..fc9950a51fb 100644
--- a/compiler/rustc_middle/src/thir.rs
+++ b/compiler/rustc_middle/src/thir.rs
@@ -647,6 +647,7 @@ impl<'tcx> Pat<'tcx> {
             AscribeUserType { subpattern, .. }
             | Binding { subpattern: Some(subpattern), .. }
             | Deref { subpattern }
+            | DerefPattern { subpattern }
             | InlineConstant { subpattern, .. } => subpattern.walk_(it),
             Leaf { subpatterns } | Variant { subpatterns, .. } => {
                 subpatterns.iter().for_each(|field| field.pattern.walk_(it))
@@ -762,6 +763,11 @@ pub enum PatKind<'tcx> {
         subpattern: Box<Pat<'tcx>>,
     },
 
+    /// Deref pattern, written `box P` for now.
+    DerefPattern {
+        subpattern: Box<Pat<'tcx>>,
+    },
+
     /// One of the following:
     /// * `&str` (represented as a valtree), which will be handled as a string pattern and thus
     ///   exhaustiveness checking will detect if you use the same string twice in different
@@ -1172,6 +1178,9 @@ impl<'tcx> fmt::Display for Pat<'tcx> {
                 }
                 write!(f, "{subpattern}")
             }
+            PatKind::DerefPattern { ref subpattern } => {
+                write!(f, "k#deref {subpattern}")
+            }
             PatKind::Constant { value } => write!(f, "{value}"),
             PatKind::InlineConstant { def: _, ref subpattern } => {
                 write!(f, "{} (from inline const)", subpattern)
diff --git a/compiler/rustc_middle/src/thir/visit.rs b/compiler/rustc_middle/src/thir/visit.rs
index 5952c296fb6..99ab006bcc0 100644
--- a/compiler/rustc_middle/src/thir/visit.rs
+++ b/compiler/rustc_middle/src/thir/visit.rs
@@ -229,6 +229,7 @@ pub fn walk_pat<'thir, 'tcx: 'thir, V: Visitor<'thir, 'tcx>>(
     match &pat.kind {
         AscribeUserType { subpattern, ascription: _ }
         | Deref { subpattern }
+        | DerefPattern { subpattern }
         | Binding {
             subpattern: Some(subpattern),
             mutability: _,
diff --git a/compiler/rustc_middle/src/ty/diagnostics.rs b/compiler/rustc_middle/src/ty/diagnostics.rs
index 05463b8554f..ee18647cdd8 100644
--- a/compiler/rustc_middle/src/ty/diagnostics.rs
+++ b/compiler/rustc_middle/src/ty/diagnostics.rs
@@ -91,7 +91,12 @@ pub trait IsSuggestable<'tcx>: Sized {
     /// inference variables to be suggestable.
     fn is_suggestable(self, tcx: TyCtxt<'tcx>, infer_suggestable: bool) -> bool;
 
-    fn make_suggestable(self, tcx: TyCtxt<'tcx>, infer_suggestable: bool) -> Option<Self>;
+    fn make_suggestable(
+        self,
+        tcx: TyCtxt<'tcx>,
+        infer_suggestable: bool,
+        placeholder: Option<Ty<'tcx>>,
+    ) -> Option<Self>;
 }
 
 impl<'tcx, T> IsSuggestable<'tcx> for T
@@ -103,8 +108,13 @@ where
         self.visit_with(&mut IsSuggestableVisitor { tcx, infer_suggestable }).is_continue()
     }
 
-    fn make_suggestable(self, tcx: TyCtxt<'tcx>, infer_suggestable: bool) -> Option<T> {
-        self.try_fold_with(&mut MakeSuggestableFolder { tcx, infer_suggestable }).ok()
+    fn make_suggestable(
+        self,
+        tcx: TyCtxt<'tcx>,
+        infer_suggestable: bool,
+        placeholder: Option<Ty<'tcx>>,
+    ) -> Option<T> {
+        self.try_fold_with(&mut MakeSuggestableFolder { tcx, infer_suggestable, placeholder }).ok()
     }
 }
 
@@ -559,6 +569,7 @@ impl<'tcx> TypeVisitor<TyCtxt<'tcx>> for IsSuggestableVisitor<'tcx> {
 pub struct MakeSuggestableFolder<'tcx> {
     tcx: TyCtxt<'tcx>,
     infer_suggestable: bool,
+    placeholder: Option<Ty<'tcx>>,
 }
 
 impl<'tcx> FallibleTypeFolder<TyCtxt<'tcx>> for MakeSuggestableFolder<'tcx> {
@@ -572,19 +583,24 @@ impl<'tcx> FallibleTypeFolder<TyCtxt<'tcx>> for MakeSuggestableFolder<'tcx> {
         let t = match *t.kind() {
             Infer(InferTy::TyVar(_)) if self.infer_suggestable => t,
 
-            FnDef(def_id, args) => {
+            FnDef(def_id, args) if self.placeholder.is_none() => {
                 Ty::new_fn_ptr(self.tcx, self.tcx.fn_sig(def_id).instantiate(self.tcx, args))
             }
 
-            // FIXME(compiler-errors): We could replace these with infer, I guess.
             Closure(..)
+            | FnDef(..)
             | Infer(..)
             | Coroutine(..)
             | CoroutineWitness(..)
             | Bound(_, _)
             | Placeholder(_)
             | Error(_) => {
-                return Err(());
+                if let Some(placeholder) = self.placeholder {
+                    // We replace these with infer (which is passed in from an infcx).
+                    placeholder
+                } else {
+                    return Err(());
+                }
             }
 
             Alias(Opaque, AliasTy { def_id, .. }) => {
diff --git a/compiler/rustc_middle/src/ty/util.rs b/compiler/rustc_middle/src/ty/util.rs
index a6526b06851..e1081423489 100644
--- a/compiler/rustc_middle/src/ty/util.rs
+++ b/compiler/rustc_middle/src/ty/util.rs
@@ -682,6 +682,9 @@ impl<'tcx> TyCtxt<'tcx> {
 
     /// Return the set of types that should be taken into account when checking
     /// trait bounds on a coroutine's internal state.
+    // FIXME(compiler-errors): We should remove this when the old solver goes away;
+    // and all other usages of this function should go through `bound_coroutine_hidden_types`
+    // instead.
     pub fn coroutine_hidden_types(
         self,
         def_id: DefId,
@@ -694,6 +697,33 @@ impl<'tcx> TyCtxt<'tcx> {
             .map(|decl| ty::EarlyBinder::bind(decl.ty))
     }
 
+    /// Return the set of types that should be taken into account when checking
+    /// trait bounds on a coroutine's internal state. This properly replaces
+    /// `ReErased` with new existential bound lifetimes.
+    pub fn bound_coroutine_hidden_types(
+        self,
+        def_id: DefId,
+    ) -> impl Iterator<Item = ty::EarlyBinder<ty::Binder<'tcx, Ty<'tcx>>>> {
+        let coroutine_layout = self.mir_coroutine_witnesses(def_id);
+        coroutine_layout
+            .as_ref()
+            .map_or_else(|| [].iter(), |l| l.field_tys.iter())
+            .filter(|decl| !decl.ignore_for_traits)
+            .map(move |decl| {
+                let mut vars = vec![];
+                let ty = self.fold_regions(decl.ty, |re, debruijn| {
+                    assert_eq!(re, self.lifetimes.re_erased);
+                    let var = ty::BoundVar::from_usize(vars.len());
+                    vars.push(ty::BoundVariableKind::Region(ty::BrAnon));
+                    ty::Region::new_bound(self, debruijn, ty::BoundRegion { var, kind: ty::BrAnon })
+                });
+                ty::EarlyBinder::bind(ty::Binder::bind_with_vars(
+                    ty,
+                    self.mk_bound_variable_kinds(&vars),
+                ))
+            })
+    }
+
     /// Expands the given impl trait type, stopping if the type is recursive.
     #[instrument(skip(self), level = "debug", ret)]
     pub fn try_expand_impl_trait_type(
@@ -998,8 +1028,10 @@ impl<'tcx> OpaqueTypeExpander<'tcx> {
                 Some(expanded_ty) => *expanded_ty,
                 None => {
                     if matches!(self.inspect_coroutine_fields, InspectCoroutineFields::Yes) {
-                        for bty in self.tcx.coroutine_hidden_types(def_id) {
-                            let hidden_ty = bty.instantiate(self.tcx, args);
+                        for bty in self.tcx.bound_coroutine_hidden_types(def_id) {
+                            let hidden_ty = self.tcx.instantiate_bound_regions_with_erased(
+                                bty.instantiate(self.tcx, args),
+                            );
                             self.fold_ty(hidden_ty);
                         }
                     }
diff --git a/compiler/rustc_mir_build/src/build/matches/mod.rs b/compiler/rustc_mir_build/src/build/matches/mod.rs
index d2cbbf9be32..f4f452d474f 100644
--- a/compiler/rustc_mir_build/src/build/matches/mod.rs
+++ b/compiler/rustc_mir_build/src/build/matches/mod.rs
@@ -879,6 +879,10 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
                 self.visit_primary_bindings(subpattern, pattern_user_ty.deref(), f);
             }
 
+            PatKind::DerefPattern { ref subpattern } => {
+                self.visit_primary_bindings(subpattern, UserTypeProjections::none(), f);
+            }
+
             PatKind::AscribeUserType {
                 ref subpattern,
                 ascription: thir::Ascription { ref annotation, variance: _ },
diff --git a/compiler/rustc_mir_build/src/build/matches/util.rs b/compiler/rustc_mir_build/src/build/matches/util.rs
index d0d49c13f13..1148cd19a01 100644
--- a/compiler/rustc_mir_build/src/build/matches/util.rs
+++ b/compiler/rustc_mir_build/src/build/matches/util.rs
@@ -256,6 +256,12 @@ impl<'pat, 'tcx> MatchPair<'pat, 'tcx> {
                 subpairs.push(MatchPair::new(place_builder, subpattern, cx));
                 default_irrefutable()
             }
+
+            PatKind::DerefPattern { .. } => {
+                // FIXME(deref_patterns)
+                // Treat it like a wildcard for now.
+                default_irrefutable()
+            }
         };
 
         MatchPair { place, test_case, subpairs, pattern }
diff --git a/compiler/rustc_mir_build/src/check_unsafety.rs b/compiler/rustc_mir_build/src/check_unsafety.rs
index 1ce8da162bf..e04fe31a76f 100644
--- a/compiler/rustc_mir_build/src/check_unsafety.rs
+++ b/compiler/rustc_mir_build/src/check_unsafety.rs
@@ -250,6 +250,7 @@ impl<'a, 'tcx> Visitor<'a, 'tcx> for UnsafetyVisitor<'a, 'tcx> {
                 | PatKind::Variant { .. }
                 | PatKind::Leaf { .. }
                 | PatKind::Deref { .. }
+                | PatKind::DerefPattern { .. }
                 | PatKind::Range { .. }
                 | PatKind::Slice { .. }
                 | PatKind::Array { .. } => {
@@ -310,7 +311,7 @@ impl<'a, 'tcx> Visitor<'a, 'tcx> for UnsafetyVisitor<'a, 'tcx> {
                 }
                 visit::walk_pat(self, pat);
             }
-            PatKind::Deref { .. } => {
+            PatKind::Deref { .. } | PatKind::DerefPattern { .. } => {
                 let old_inside_adt = std::mem::replace(&mut self.inside_adt, false);
                 visit::walk_pat(self, pat);
                 self.inside_adt = old_inside_adt;
diff --git a/compiler/rustc_mir_build/src/thir/pattern/mod.rs b/compiler/rustc_mir_build/src/thir/pattern/mod.rs
index 03eda9a9322..f4aed91cd72 100644
--- a/compiler/rustc_mir_build/src/thir/pattern/mod.rs
+++ b/compiler/rustc_mir_build/src/thir/pattern/mod.rs
@@ -257,6 +257,9 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> {
                 return self.lower_path(qpath, pat.hir_id, pat.span);
             }
 
+            hir::PatKind::Box(subpattern) if self.tcx.features().deref_patterns => {
+                PatKind::DerefPattern { subpattern: self.lower_pattern(subpattern) }
+            }
             hir::PatKind::Ref(subpattern, _) | hir::PatKind::Box(subpattern) => {
                 PatKind::Deref { subpattern: self.lower_pattern(subpattern) }
             }
diff --git a/compiler/rustc_mir_build/src/thir/print.rs b/compiler/rustc_mir_build/src/thir/print.rs
index d53704f89e7..16c4248a159 100644
--- a/compiler/rustc_mir_build/src/thir/print.rs
+++ b/compiler/rustc_mir_build/src/thir/print.rs
@@ -688,6 +688,12 @@ impl<'a, 'tcx> ThirPrinter<'a, 'tcx> {
                 self.print_pat(subpattern, depth_lvl + 2);
                 print_indented!(self, "}", depth_lvl + 1);
             }
+            PatKind::DerefPattern { subpattern } => {
+                print_indented!(self, "DerefPattern { ", depth_lvl + 1);
+                print_indented!(self, "subpattern:", depth_lvl + 2);
+                self.print_pat(subpattern, depth_lvl + 2);
+                print_indented!(self, "}", depth_lvl + 1);
+            }
             PatKind::Constant { value } => {
                 print_indented!(self, "Constant {", depth_lvl + 1);
                 print_indented!(self, format!("value: {:?}", value), depth_lvl + 2);
diff --git a/compiler/rustc_parse/src/parser/expr.rs b/compiler/rustc_parse/src/parser/expr.rs
index 136145dd182..6256db99251 100644
--- a/compiler/rustc_parse/src/parser/expr.rs
+++ b/compiler/rustc_parse/src/parser/expr.rs
@@ -1939,11 +1939,11 @@ impl<'a> Parser<'a> {
     /// Parse `builtin # ident(args,*)`.
     fn parse_expr_builtin(&mut self) -> PResult<'a, P<Expr>> {
         self.parse_builtin(|this, lo, ident| {
-            if ident.name == sym::offset_of {
-                return Ok(Some(this.parse_expr_offset_of(lo)?));
-            }
-
-            Ok(None)
+            Ok(match ident.name {
+                sym::offset_of => Some(this.parse_expr_offset_of(lo)?),
+                sym::type_ascribe => Some(this.parse_expr_type_ascribe(lo)?),
+                _ => None,
+            })
         })
     }
 
@@ -1978,6 +1978,7 @@ impl<'a> Parser<'a> {
         ret
     }
 
+    /// Built-in macro for `offset_of!` expressions.
     pub(crate) fn parse_expr_offset_of(&mut self, lo: Span) -> PResult<'a, P<Expr>> {
         let container = self.parse_ty()?;
         self.expect(&TokenKind::Comma)?;
@@ -2007,6 +2008,15 @@ impl<'a> Parser<'a> {
         Ok(self.mk_expr(span, ExprKind::OffsetOf(container, fields)))
     }
 
+    /// Built-in macro for type ascription expressions.
+    pub(crate) fn parse_expr_type_ascribe(&mut self, lo: Span) -> PResult<'a, P<Expr>> {
+        let expr = self.parse_expr()?;
+        self.expect(&token::Comma)?;
+        let ty = self.parse_ty()?;
+        let span = lo.to(self.token.span);
+        Ok(self.mk_expr(span, ExprKind::Type(expr, ty)))
+    }
+
     /// Returns a string literal if the next token is a string literal.
     /// In case of error returns `Some(lit)` if the next token is a literal with a wrong kind,
     /// and returns `None` if the next token is not literal at all.
diff --git a/compiler/rustc_pattern_analysis/src/rustc.rs b/compiler/rustc_pattern_analysis/src/rustc.rs
index eedc00a5613..4cb306b1950 100644
--- a/compiler/rustc_pattern_analysis/src/rustc.rs
+++ b/compiler/rustc_pattern_analysis/src/rustc.rs
@@ -462,6 +462,12 @@ impl<'p, 'tcx: 'p> RustcPatCtxt<'p, 'tcx> {
                     _ => bug!("pattern has unexpected type: pat: {:?}, ty: {:?}", pat, ty),
                 };
             }
+            PatKind::DerefPattern { .. } => {
+                // FIXME(deref_patterns): At least detect that `box _` is irrefutable.
+                fields = vec![];
+                arity = 0;
+                ctor = Opaque(OpaqueId::new());
+            }
             PatKind::Leaf { subpatterns } | PatKind::Variant { subpatterns, .. } => {
                 match ty.kind() {
                     ty::Tuple(fs) => {
diff --git a/compiler/rustc_smir/src/rustc_internal/internal.rs b/compiler/rustc_smir/src/rustc_internal/internal.rs
index 2cc9bc31873..bf7346be31f 100644
--- a/compiler/rustc_smir/src/rustc_internal/internal.rs
+++ b/compiler/rustc_smir/src/rustc_internal/internal.rs
@@ -10,7 +10,7 @@ use rustc_span::Symbol;
 use stable_mir::abi::Layout;
 use stable_mir::mir::alloc::AllocId;
 use stable_mir::mir::mono::{Instance, MonoItem, StaticDef};
-use stable_mir::mir::{Mutability, Safety};
+use stable_mir::mir::{Mutability, Place, ProjectionElem, Safety};
 use stable_mir::ty::{
     Abi, AdtDef, Binder, BoundRegionKind, BoundTyKind, BoundVariableKind, ClosureKind, Const,
     DynKind, ExistentialPredicate, ExistentialProjection, ExistentialTraitRef, FloatTy, FnSig,
@@ -492,6 +492,50 @@ impl RustcInternal for Layout {
     }
 }
 
+impl RustcInternal for Place {
+    type T<'tcx> = rustc_middle::mir::Place<'tcx>;
+
+    fn internal<'tcx>(&self, tables: &mut Tables<'_>, tcx: TyCtxt<'tcx>) -> Self::T<'tcx> {
+        rustc_middle::mir::Place {
+            local: rustc_middle::mir::Local::from_usize(self.local),
+            projection: tcx.mk_place_elems(&self.projection.internal(tables, tcx)),
+        }
+    }
+}
+
+impl RustcInternal for ProjectionElem {
+    type T<'tcx> = rustc_middle::mir::PlaceElem<'tcx>;
+
+    fn internal<'tcx>(&self, tables: &mut Tables<'_>, tcx: TyCtxt<'tcx>) -> Self::T<'tcx> {
+        match self {
+            ProjectionElem::Deref => rustc_middle::mir::PlaceElem::Deref,
+            ProjectionElem::Field(idx, ty) => {
+                rustc_middle::mir::PlaceElem::Field((*idx).into(), ty.internal(tables, tcx))
+            }
+            ProjectionElem::Index(idx) => rustc_middle::mir::PlaceElem::Index((*idx).into()),
+            ProjectionElem::ConstantIndex { offset, min_length, from_end } => {
+                rustc_middle::mir::PlaceElem::ConstantIndex {
+                    offset: *offset,
+                    min_length: *min_length,
+                    from_end: *from_end,
+                }
+            }
+            ProjectionElem::Subslice { from, to, from_end } => {
+                rustc_middle::mir::PlaceElem::Subslice { from: *from, to: *to, from_end: *from_end }
+            }
+            ProjectionElem::Downcast(idx) => {
+                rustc_middle::mir::PlaceElem::Downcast(None, idx.internal(tables, tcx))
+            }
+            ProjectionElem::OpaqueCast(ty) => {
+                rustc_middle::mir::PlaceElem::OpaqueCast(ty.internal(tables, tcx))
+            }
+            ProjectionElem::Subtype(ty) => {
+                rustc_middle::mir::PlaceElem::Subtype(ty.internal(tables, tcx))
+            }
+        }
+    }
+}
+
 impl<T> RustcInternal for &T
 where
     T: RustcInternal,
diff --git a/compiler/rustc_smir/src/rustc_internal/pretty.rs b/compiler/rustc_smir/src/rustc_internal/pretty.rs
index 3ef2d28ea47..c0dce08b0d3 100644
--- a/compiler/rustc_smir/src/rustc_internal/pretty.rs
+++ b/compiler/rustc_smir/src/rustc_internal/pretty.rs
@@ -14,7 +14,7 @@ pub fn write_smir_pretty<'tcx, W: io::Write>(tcx: TyCtxt<'tcx>, w: &mut W) -> io
     )?;
     let _ = run(tcx, || {
         let items = stable_mir::all_local_items();
-        let _ = items.iter().map(|item| -> io::Result<()> { item.dump(w) }).collect::<Vec<_>>();
+        let _ = items.iter().map(|item| -> io::Result<()> { item.emit_mir(w) }).collect::<Vec<_>>();
     });
     Ok(())
 }
diff --git a/compiler/rustc_smir/src/rustc_smir/context.rs b/compiler/rustc_smir/src/rustc_smir/context.rs
index d427e5fb88d..d39a3788d4c 100644
--- a/compiler/rustc_smir/src/rustc_smir/context.rs
+++ b/compiler/rustc_smir/src/rustc_smir/context.rs
@@ -19,7 +19,7 @@ use stable_mir::abi::{FnAbi, Layout, LayoutShape};
 use stable_mir::compiler_interface::Context;
 use stable_mir::mir::alloc::GlobalAlloc;
 use stable_mir::mir::mono::{InstanceDef, StaticDef};
-use stable_mir::mir::Body;
+use stable_mir::mir::{Body, Place};
 use stable_mir::target::{MachineInfo, MachineSize};
 use stable_mir::ty::{
     AdtDef, AdtKind, Allocation, ClosureDef, ClosureKind, Const, FieldDef, FnDef, ForeignDef,
@@ -423,7 +423,7 @@ impl<'tcx> Context for TablesWrapper<'tcx> {
         def_ty.instantiate(tables.tcx, args).stable(&mut *tables)
     }
 
-    fn const_literal(&self, cnst: &stable_mir::ty::Const) -> String {
+    fn const_pretty(&self, cnst: &stable_mir::ty::Const) -> String {
         let mut tables = self.0.borrow_mut();
         let tcx = tables.tcx;
         cnst.internal(&mut *tables, tcx).to_string()
@@ -434,6 +434,11 @@ impl<'tcx> Context for TablesWrapper<'tcx> {
         tables.tcx.def_span(tables[def_id]).stable(&mut *tables)
     }
 
+    fn ty_pretty(&self, ty: stable_mir::ty::Ty) -> String {
+        let tables = self.0.borrow_mut();
+        tables.types[ty].to_string()
+    }
+
     fn ty_kind(&self, ty: stable_mir::ty::Ty) -> TyKind {
         let mut tables = self.0.borrow_mut();
         tables.types[ty].kind().stable(&mut *tables)
@@ -654,6 +659,12 @@ impl<'tcx> Context for TablesWrapper<'tcx> {
         let tcx = tables.tcx;
         id.internal(&mut *tables, tcx).0.stable(&mut *tables)
     }
+
+    fn place_pretty(&self, place: &Place) -> String {
+        let mut tables = self.0.borrow_mut();
+        let tcx = tables.tcx;
+        format!("{:?}", place.internal(&mut *tables, tcx))
+    }
 }
 
 pub struct TablesWrapper<'tcx>(pub RefCell<Tables<'tcx>>);
diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs
index 8b911a41a11..8b35087a005 100644
--- a/compiler/rustc_span/src/symbol.rs
+++ b/compiler/rustc_span/src/symbol.rs
@@ -674,6 +674,7 @@ symbols! {
         deref_method,
         deref_mut,
         deref_mut_method,
+        deref_patterns,
         deref_target,
         derive,
         derive_const,
diff --git a/compiler/rustc_target/src/spec/mod.rs b/compiler/rustc_target/src/spec/mod.rs
index 941d767b850..896f208f560 100644
--- a/compiler/rustc_target/src/spec/mod.rs
+++ b/compiler/rustc_target/src/spec/mod.rs
@@ -1621,6 +1621,7 @@ supported_targets! {
     ("riscv32i-unknown-none-elf", riscv32i_unknown_none_elf),
     ("riscv32im-risc0-zkvm-elf", riscv32im_risc0_zkvm_elf),
     ("riscv32im-unknown-none-elf", riscv32im_unknown_none_elf),
+    ("riscv32ima-unknown-none-elf", riscv32ima_unknown_none_elf),
     ("riscv32imc-unknown-none-elf", riscv32imc_unknown_none_elf),
     ("riscv32imc-esp-espidf", riscv32imc_esp_espidf),
     ("riscv32imac-esp-espidf", riscv32imac_esp_espidf),
diff --git a/compiler/rustc_target/src/spec/targets/riscv32ima_unknown_none_elf.rs b/compiler/rustc_target/src/spec/targets/riscv32ima_unknown_none_elf.rs
new file mode 100644
index 00000000000..9acf6a3b5a0
--- /dev/null
+++ b/compiler/rustc_target/src/spec/targets/riscv32ima_unknown_none_elf.rs
@@ -0,0 +1,29 @@
+use crate::spec::{Cc, LinkerFlavor, Lld, PanicStrategy, RelocModel, Target, TargetOptions};
+
+pub fn target() -> Target {
+    Target {
+        data_layout: "e-m:e-p:32:32-i64:64-n32-S128".into(),
+        llvm_target: "riscv32".into(),
+        metadata: crate::spec::TargetMetadata {
+            description: None,
+            tier: None,
+            host_tools: None,
+            std: None,
+        },
+        pointer_width: 32,
+        arch: "riscv32".into(),
+
+        options: TargetOptions {
+            linker_flavor: LinkerFlavor::Gnu(Cc::No, Lld::Yes),
+            linker: Some("rust-lld".into()),
+            cpu: "generic-rv32".into(),
+            max_atomic_width: Some(32),
+            features: "+m,+a".into(),
+            panic_strategy: PanicStrategy::Abort,
+            relocation_model: RelocModel::Static,
+            emit_debug_gdb_scripts: false,
+            eh_frame_header: false,
+            ..Default::default()
+        },
+    }
+}
diff --git a/compiler/rustc_trait_selection/src/solve/assembly/structural_traits.rs b/compiler/rustc_trait_selection/src/solve/assembly/structural_traits.rs
index faf8c55c475..80c31831462 100644
--- a/compiler/rustc_trait_selection/src/solve/assembly/structural_traits.rs
+++ b/compiler/rustc_trait_selection/src/solve/assembly/structural_traits.rs
@@ -6,7 +6,7 @@ use rustc_hir::{def_id::DefId, Movability, Mutability};
 use rustc_infer::traits::query::NoSolution;
 use rustc_middle::traits::solve::Goal;
 use rustc_middle::ty::{
-    self, ToPredicate, Ty, TyCtxt, TypeFoldable, TypeFolder, TypeSuperFoldable, TypeVisitableExt,
+    self, ToPredicate, Ty, TyCtxt, TypeFoldable, TypeFolder, TypeSuperFoldable,
 };
 use rustc_span::sym;
 
@@ -73,8 +73,8 @@ pub(in crate::solve) fn instantiate_constituent_tys_for_auto_trait<'tcx>(
 
         ty::CoroutineWitness(def_id, args) => Ok(ecx
             .tcx()
-            .coroutine_hidden_types(def_id)
-            .map(|bty| replace_erased_lifetimes_with_bound_vars(tcx, bty.instantiate(tcx, args)))
+            .bound_coroutine_hidden_types(def_id)
+            .map(|bty| bty.instantiate(tcx, args))
             .collect()),
 
         // For `PhantomData<T>`, we pass `T`.
@@ -93,27 +93,6 @@ pub(in crate::solve) fn instantiate_constituent_tys_for_auto_trait<'tcx>(
     }
 }
 
-pub(in crate::solve) fn replace_erased_lifetimes_with_bound_vars<'tcx>(
-    tcx: TyCtxt<'tcx>,
-    ty: Ty<'tcx>,
-) -> ty::Binder<'tcx, Ty<'tcx>> {
-    debug_assert!(!ty.has_bound_regions());
-    let mut counter = 0;
-    let ty = tcx.fold_regions(ty, |r, current_depth| match r.kind() {
-        ty::ReErased => {
-            let br = ty::BoundRegion { var: ty::BoundVar::from_u32(counter), kind: ty::BrAnon };
-            counter += 1;
-            ty::Region::new_bound(tcx, current_depth, br)
-        }
-        // All free regions should be erased here.
-        r => bug!("unexpected region: {r:?}"),
-    });
-    let bound_vars = tcx.mk_bound_variable_kinds_from_iter(
-        (0..counter).map(|_| ty::BoundVariableKind::Region(ty::BrAnon)),
-    );
-    ty::Binder::bind_with_vars(ty, bound_vars)
-}
-
 #[instrument(level = "debug", skip(ecx), ret)]
 pub(in crate::solve) fn instantiate_constituent_tys_for_sized_trait<'tcx>(
     ecx: &EvalCtxt<'_, 'tcx>,
@@ -241,13 +220,8 @@ pub(in crate::solve) fn instantiate_constituent_tys_for_copy_clone_trait<'tcx>(
         // impl Copy/Clone for CoroutineWitness where T: Copy/Clone forall T in coroutine_hidden_types
         ty::CoroutineWitness(def_id, args) => Ok(ecx
             .tcx()
-            .coroutine_hidden_types(def_id)
-            .map(|bty| {
-                replace_erased_lifetimes_with_bound_vars(
-                    ecx.tcx(),
-                    bty.instantiate(ecx.tcx(), args),
-                )
-            })
+            .bound_coroutine_hidden_types(def_id)
+            .map(|bty| bty.instantiate(ecx.tcx(), args))
             .collect()),
     }
 }
diff --git a/compiler/rustc_trait_selection/src/traits/select/confirmation.rs b/compiler/rustc_trait_selection/src/traits/select/confirmation.rs
index 51fc223a5d1..557fc99a536 100644
--- a/compiler/rustc_trait_selection/src/traits/select/confirmation.rs
+++ b/compiler/rustc_trait_selection/src/traits/select/confirmation.rs
@@ -14,7 +14,7 @@ use rustc_infer::infer::{DefineOpaqueTypes, InferOk};
 use rustc_middle::traits::{BuiltinImplSource, SignatureMismatchData};
 use rustc_middle::ty::{
     self, GenericArgs, GenericArgsRef, GenericParamDefKind, ToPolyTraitRef, ToPredicate,
-    TraitPredicate, Ty, TyCtxt, TypeVisitableExt,
+    TraitPredicate, Ty, TyCtxt,
 };
 use rustc_span::def_id::DefId;
 
@@ -1438,10 +1438,8 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
                 }
                 ty::CoroutineWitness(def_id, args) => {
                     let tcx = self.tcx();
-                    stack.extend(tcx.coroutine_hidden_types(def_id).map(|bty| {
-                        let ty = bty.instantiate(tcx, args);
-                        debug_assert!(!ty.has_bound_regions());
-                        ty
+                    stack.extend(tcx.bound_coroutine_hidden_types(def_id).map(|bty| {
+                        self.infcx.enter_forall_and_leak_universe(bty.instantiate(tcx, args))
                     }))
                 }
 
diff --git a/compiler/stable_mir/src/compiler_interface.rs b/compiler/stable_mir/src/compiler_interface.rs
index f53dbcfbd96..8ed34fab54d 100644
--- a/compiler/stable_mir/src/compiler_interface.rs
+++ b/compiler/stable_mir/src/compiler_interface.rs
@@ -8,7 +8,7 @@ use std::cell::Cell;
 use crate::abi::{FnAbi, Layout, LayoutShape};
 use crate::mir::alloc::{AllocId, GlobalAlloc};
 use crate::mir::mono::{Instance, InstanceDef, StaticDef};
-use crate::mir::Body;
+use crate::mir::{Body, Place};
 use crate::target::MachineInfo;
 use crate::ty::{
     AdtDef, AdtKind, Allocation, ClosureDef, ClosureKind, Const, FieldDef, FnDef, ForeignDef,
@@ -126,12 +126,15 @@ pub trait Context {
     fn def_ty_with_args(&self, item: DefId, args: &GenericArgs) -> Ty;
 
     /// Returns literal value of a const as a string.
-    fn const_literal(&self, cnst: &Const) -> String;
+    fn const_pretty(&self, cnst: &Const) -> String;
 
     /// `Span` of an item
     fn span_of_an_item(&self, def_id: DefId) -> Span;
 
     /// Obtain the representation of a type.
+    fn ty_pretty(&self, ty: Ty) -> String;
+
+    /// Obtain the representation of a type.
     fn ty_kind(&self, ty: Ty) -> TyKind;
 
     // Get the discriminant Ty for this Ty if there's one.
@@ -205,6 +208,9 @@ pub trait Context {
 
     /// Get the layout shape.
     fn layout_shape(&self, id: Layout) -> LayoutShape;
+
+    /// Get a debug string representation of a place.
+    fn place_pretty(&self, place: &Place) -> String;
 }
 
 // A thread local variable that stores a pointer to the tables mapping between TyCtxt
diff --git a/compiler/stable_mir/src/lib.rs b/compiler/stable_mir/src/lib.rs
index d849c834ae0..d1a2948ea77 100644
--- a/compiler/stable_mir/src/lib.rs
+++ b/compiler/stable_mir/src/lib.rs
@@ -27,7 +27,6 @@ use crate::compiler_interface::with;
 pub use crate::crate_def::CrateDef;
 pub use crate::crate_def::DefId;
 pub use crate::error::*;
-use crate::mir::pretty::function_name;
 use crate::mir::Body;
 use crate::mir::Mutability;
 use crate::ty::{ForeignModuleDef, ImplDef, IndexedVal, Span, TraitDef, Ty};
@@ -148,9 +147,8 @@ impl CrateItem {
         with(|cx| cx.is_foreign_item(self.0))
     }
 
-    pub fn dump<W: io::Write>(&self, w: &mut W) -> io::Result<()> {
-        writeln!(w, "{}", function_name(*self))?;
-        self.body().dump(w)
+    pub fn emit_mir<W: io::Write>(&self, w: &mut W) -> io::Result<()> {
+        self.body().dump(w, &self.name())
     }
 }
 
diff --git a/compiler/stable_mir/src/mir/body.rs b/compiler/stable_mir/src/mir/body.rs
index ae8e71bb950..e4a012d8c47 100644
--- a/compiler/stable_mir/src/mir/body.rs
+++ b/compiler/stable_mir/src/mir/body.rs
@@ -1,10 +1,11 @@
-use crate::mir::pretty::{function_body, pretty_statement, pretty_terminator};
+use crate::mir::pretty::function_body;
 use crate::ty::{
     AdtDef, ClosureDef, Const, CoroutineDef, GenericArgs, Movability, Region, RigidTy, Ty, TyKind,
     VariantIdx,
 };
 use crate::{Error, Opaque, Span, Symbol};
 use std::io;
+
 /// The SMIR representation of a single function.
 #[derive(Clone, Debug)]
 pub struct Body {
@@ -90,28 +91,9 @@ impl Body {
         self.locals.iter().enumerate()
     }
 
-    pub fn dump<W: io::Write>(&self, w: &mut W) -> io::Result<()> {
-        writeln!(w, "{}", function_body(self))?;
-        self.blocks
-            .iter()
-            .enumerate()
-            .map(|(index, block)| -> io::Result<()> {
-                writeln!(w, "    bb{}: {{", index)?;
-                let _ = block
-                    .statements
-                    .iter()
-                    .map(|statement| -> io::Result<()> {
-                        writeln!(w, "{}", pretty_statement(&statement.kind))?;
-                        Ok(())
-                    })
-                    .collect::<Vec<_>>();
-                pretty_terminator(&block.terminator.kind, w)?;
-                writeln!(w, "").unwrap();
-                writeln!(w, "    }}").unwrap();
-                Ok(())
-            })
-            .collect::<Result<Vec<_>, _>>()?;
-        Ok(())
+    /// Emit the body using the provided name for the signature.
+    pub fn dump<W: io::Write>(&self, w: &mut W, fn_name: &str) -> io::Result<()> {
+        function_body(w, self, fn_name)
     }
 
     pub fn spread_arg(&self) -> Option<Local> {
@@ -674,7 +656,7 @@ pub enum Operand {
     Constant(Constant),
 }
 
-#[derive(Clone, Debug, Eq, PartialEq)]
+#[derive(Clone, Eq, PartialEq)]
 pub struct Place {
     pub local: Local,
     /// projection out of a place (access a field, deref a pointer, etc)
diff --git a/compiler/stable_mir/src/mir/mono.rs b/compiler/stable_mir/src/mir/mono.rs
index 38e5776c48c..aafa89c03e0 100644
--- a/compiler/stable_mir/src/mir/mono.rs
+++ b/compiler/stable_mir/src/mir/mono.rs
@@ -4,6 +4,7 @@ use crate::mir::Body;
 use crate::ty::{Allocation, ClosureDef, ClosureKind, FnDef, GenericArgs, IndexedVal, Ty};
 use crate::{with, CrateItem, DefId, Error, ItemKind, Opaque, Symbol};
 use std::fmt::{Debug, Formatter};
+use std::io;
 
 #[derive(Clone, Debug, PartialEq, Eq, Hash)]
 pub enum MonoItem {
@@ -157,6 +158,11 @@ impl Instance {
     pub fn try_const_eval(&self, const_ty: Ty) -> Result<Allocation, Error> {
         with(|cx| cx.eval_instance(self.def, const_ty))
     }
+
+    /// Emit the body of this instance if it has one.
+    pub fn emit_mir<W: io::Write>(&self, w: &mut W) -> io::Result<()> {
+        if let Some(body) = self.body() { body.dump(w, &self.name()) } else { Ok(()) }
+    }
 }
 
 impl Debug for Instance {
diff --git a/compiler/stable_mir/src/mir/pretty.rs b/compiler/stable_mir/src/mir/pretty.rs
index 8b7b488d312..4ac4833add7 100644
--- a/compiler/stable_mir/src/mir/pretty.rs
+++ b/compiler/stable_mir/src/mir/pretty.rs
@@ -1,185 +1,193 @@
-use crate::crate_def::CrateDef;
-use crate::mir::{Operand, Rvalue, StatementKind, UnwindAction};
-use crate::ty::{DynKind, FloatTy, IntTy, RigidTy, TyKind, UintTy};
-use crate::{with, Body, CrateItem, Mutability};
+use crate::mir::{Operand, Place, Rvalue, StatementKind, UnwindAction, VarDebugInfoContents};
+use crate::ty::{Const, IndexedVal, Ty};
+use crate::{with, Body, Mutability};
+use fmt::{Display, Formatter};
+use std::fmt::Debug;
 use std::io::Write;
-use std::{io, iter};
+use std::{fmt, io, iter};
 
 use super::{AssertMessage, BinOp, TerminatorKind};
 
-pub fn function_name(item: CrateItem) -> String {
-    let mut pretty_name = String::new();
-    let body = item.body();
-    pretty_name.push_str("fn ");
-    pretty_name.push_str(item.name().as_str());
-    if body.arg_locals().is_empty() {
-        pretty_name.push_str("()");
-    } else {
-        pretty_name.push_str("(");
-    }
-    body.arg_locals().iter().enumerate().for_each(|(index, local)| {
-        pretty_name.push_str(format!("_{}: ", index).as_str());
-        pretty_name.push_str(&pretty_ty(local.ty.kind()));
-    });
-    if !body.arg_locals().is_empty() {
-        pretty_name.push_str(")");
+use super::BorrowKind;
+
+impl Display for Ty {
+    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
+        with(|ctx| write!(f, "{}", ctx.ty_pretty(*self)))
     }
-    let return_local = body.ret_local();
-    pretty_name.push_str(" -> ");
-    pretty_name.push_str(&pretty_ty(return_local.ty.kind()));
-    pretty_name.push_str(" {");
-    pretty_name
 }
 
-pub fn function_body(body: &Body) -> String {
-    let mut pretty_body = String::new();
-    body.inner_locals().iter().enumerate().for_each(|(index, local)| {
-        pretty_body.push_str("    ");
-        pretty_body.push_str(format!("let {}", ret_mutability(&local.mutability)).as_str());
-        pretty_body.push_str(format!("_{}: ", index).as_str());
-        pretty_body.push_str(format!("{}", pretty_ty(local.ty.kind())).as_str());
-        pretty_body.push_str(";\n");
-    });
-    pretty_body.push_str("}");
-    pretty_body
+impl Debug for Place {
+    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
+        with(|ctx| write!(f, "{}", ctx.place_pretty(self)))
+    }
 }
 
-pub fn ret_mutability(mutability: &Mutability) -> String {
-    match mutability {
-        Mutability::Not => "".to_string(),
-        Mutability::Mut => "mut ".to_string(),
-    }
+pub(crate) fn function_body<W: Write>(writer: &mut W, body: &Body, name: &str) -> io::Result<()> {
+    write!(writer, "fn {}(", name)?;
+    body.arg_locals()
+        .iter()
+        .enumerate()
+        .try_for_each(|(index, local)| write!(writer, "_{}: {}", index + 1, local.ty))?;
+    write!(writer, ")")?;
+
+    let return_local = body.ret_local();
+    writeln!(writer, " -> {} {{", return_local.ty)?;
+
+    body.locals().iter().enumerate().try_for_each(|(index, local)| -> io::Result<()> {
+        if index == 0 || index > body.arg_count {
+            writeln!(writer, "    let {}_{}: {};", pretty_mut(local.mutability), index, local.ty)
+        } else {
+            Ok(())
+        }
+    })?;
+
+    body.var_debug_info.iter().try_for_each(|info| {
+        let content = match &info.value {
+            VarDebugInfoContents::Place(place) => {
+                format!("{place:?}")
+            }
+            VarDebugInfoContents::Const(constant) => pretty_const(&constant.const_),
+        };
+        writeln!(writer, "    debug {} => {};", info.name, content)
+    })?;
+
+    body.blocks
+        .iter()
+        .enumerate()
+        .map(|(index, block)| -> io::Result<()> {
+            writeln!(writer, "    bb{}: {{", index)?;
+            let _ = block
+                .statements
+                .iter()
+                .map(|statement| -> io::Result<()> {
+                    pretty_statement(writer, &statement.kind)?;
+                    Ok(())
+                })
+                .collect::<Vec<_>>();
+            pretty_terminator(writer, &block.terminator.kind)?;
+            writeln!(writer, "    }}").unwrap();
+            Ok(())
+        })
+        .collect::<Result<Vec<_>, _>>()?;
+    writeln!(writer, "}}")?;
+    Ok(())
 }
 
-pub fn pretty_statement(statement: &StatementKind) -> String {
-    let mut pretty = String::new();
+fn pretty_statement<W: Write>(writer: &mut W, statement: &StatementKind) -> io::Result<()> {
     match statement {
         StatementKind::Assign(place, rval) => {
-            pretty.push_str(format!("        _{} = ", place.local).as_str());
-            pretty.push_str(format!("{}", &pretty_rvalue(rval)).as_str());
+            write!(writer, "        {:?} = ", place)?;
+            pretty_rvalue(writer, rval)?;
+            writeln!(writer, ";")
         }
         // FIXME: Add rest of the statements
-        StatementKind::FakeRead(_, _) => {
-            return String::from("StatementKind::FakeRead:Unimplemented");
+        StatementKind::FakeRead(cause, place) => {
+            writeln!(writer, "FakeRead({cause:?}, {place:?});")
         }
-        StatementKind::SetDiscriminant { .. } => {
-            return String::from("StatementKind::SetDiscriminant:Unimplemented");
+        StatementKind::SetDiscriminant { place, variant_index } => {
+            writeln!(writer, "discriminant({place:?} = {};", variant_index.to_index())
         }
-        StatementKind::Deinit(_) => return String::from("StatementKind::Deinit:Unimplemented"),
-        StatementKind::StorageLive(_) => {
-            return String::from("StatementKind::StorageLive:Unimplemented");
+        StatementKind::Deinit(place) => writeln!(writer, "Deinit({place:?};"),
+        StatementKind::StorageLive(local) => {
+            writeln!(writer, "StorageLive(_{local});")
         }
-        StatementKind::StorageDead(_) => {
-            return String::from("StatementKind::StorageDead:Unimplemented");
+        StatementKind::StorageDead(local) => {
+            writeln!(writer, "StorageDead(_{local});")
         }
-        StatementKind::Retag(_, _) => return String::from("StatementKind::Retag:Unimplemented"),
-        StatementKind::PlaceMention(_) => {
-            return String::from("StatementKind::PlaceMention:Unimplemented");
-        }
-        StatementKind::AscribeUserType { .. } => {
-            return String::from("StatementKind::AscribeUserType:Unimplemented");
-        }
-        StatementKind::Coverage(_) => return String::from("StatementKind::Coverage:Unimplemented"),
-        StatementKind::Intrinsic(_) => {
-            return String::from("StatementKind::Intrinsic:Unimplemented");
+        StatementKind::Retag(kind, place) => writeln!(writer, "Retag({kind:?}, {place:?});"),
+        StatementKind::PlaceMention(place) => {
+            writeln!(writer, "PlaceMention({place:?};")
         }
         StatementKind::ConstEvalCounter => {
-            return String::from("StatementKind::ConstEvalCounter:Unimplemented");
+            writeln!(writer, "ConstEvalCounter;")
+        }
+        StatementKind::Nop => writeln!(writer, "nop;"),
+        StatementKind::AscribeUserType { .. }
+        | StatementKind::Coverage(_)
+        | StatementKind::Intrinsic(_) => {
+            // FIX-ME: Make them pretty.
+            writeln!(writer, "{statement:?};")
         }
-        StatementKind::Nop => return String::from("StatementKind::Nop:Unimplemented"),
     }
-    pretty
 }
 
-pub fn pretty_terminator<W: io::Write>(terminator: &TerminatorKind, w: &mut W) -> io::Result<()> {
-    write!(w, "{}", pretty_terminator_head(terminator))?;
+fn pretty_terminator<W: Write>(writer: &mut W, terminator: &TerminatorKind) -> io::Result<()> {
+    pretty_terminator_head(writer, terminator)?;
     let successors = terminator.successors();
     let successor_count = successors.len();
     let labels = pretty_successor_labels(terminator);
 
     let show_unwind = !matches!(terminator.unwind(), None | Some(UnwindAction::Cleanup(_)));
-    let fmt_unwind = |fmt: &mut dyn Write| -> io::Result<()> {
-        write!(fmt, "unwind ")?;
+    let fmt_unwind = |w: &mut W| -> io::Result<()> {
+        write!(w, "unwind ")?;
         match terminator.unwind() {
             None | Some(UnwindAction::Cleanup(_)) => unreachable!(),
-            Some(UnwindAction::Continue) => write!(fmt, "continue"),
-            Some(UnwindAction::Unreachable) => write!(fmt, "unreachable"),
-            Some(UnwindAction::Terminate) => write!(fmt, "terminate"),
+            Some(UnwindAction::Continue) => write!(w, "continue"),
+            Some(UnwindAction::Unreachable) => write!(w, "unreachable"),
+            Some(UnwindAction::Terminate) => write!(w, "terminate"),
         }
     };
 
     match (successor_count, show_unwind) {
-        (0, false) => Ok(()),
+        (0, false) => {}
         (0, true) => {
-            write!(w, " -> ")?;
-            fmt_unwind(w)?;
-            Ok(())
-        }
-        (1, false) => {
-            write!(w, " -> {:?}", successors[0])?;
-            Ok(())
+            write!(writer, " -> ")?;
+            fmt_unwind(writer)?;
         }
+        (1, false) => write!(writer, " -> bb{:?}", successors[0])?,
         _ => {
-            write!(w, " -> [")?;
+            write!(writer, " -> [")?;
             for (i, target) in successors.iter().enumerate() {
                 if i > 0 {
-                    write!(w, ", ")?;
+                    write!(writer, ", ")?;
                 }
-                write!(w, "{}: bb{:?}", labels[i], target)?;
+                write!(writer, "{}: bb{:?}", labels[i], target)?;
             }
             if show_unwind {
-                write!(w, ", ")?;
-                fmt_unwind(w)?;
+                write!(writer, ", ")?;
+                fmt_unwind(writer)?;
             }
-            write!(w, "]")
+            write!(writer, "]")?;
         }
-    }?;
+    };
 
-    Ok(())
+    writeln!(writer, ";")
 }
 
-pub fn pretty_terminator_head(terminator: &TerminatorKind) -> String {
+fn pretty_terminator_head<W: Write>(writer: &mut W, terminator: &TerminatorKind) -> io::Result<()> {
     use self::TerminatorKind::*;
-    let mut pretty = String::new();
+    const INDENT: &'static str = "        ";
     match terminator {
-        Goto { .. } => format!("        goto"),
+        Goto { .. } => write!(writer, "{INDENT}goto"),
         SwitchInt { discr, .. } => {
-            format!("        switchInt(_{})", pretty_operand(discr))
+            write!(writer, "{INDENT}switchInt({})", pretty_operand(discr))
         }
-        Resume => format!("        resume"),
-        Abort => format!("        abort"),
-        Return => format!("        return"),
-        Unreachable => format!("        unreachable"),
-        Drop { place, .. } => format!("        drop(_{:?})", place.local),
+        Resume => write!(writer, "{INDENT}resume"),
+        Abort => write!(writer, "{INDENT}abort"),
+        Return => write!(writer, "{INDENT}return"),
+        Unreachable => write!(writer, "{INDENT}unreachable"),
+        Drop { place, .. } => write!(writer, "{INDENT}drop({:?})", place),
         Call { func, args, destination, .. } => {
-            pretty.push_str("        ");
-            pretty.push_str(format!("_{} = ", destination.local).as_str());
-            pretty.push_str(&pretty_operand(func));
-            pretty.push_str("(");
-            args.iter().enumerate().for_each(|(i, arg)| {
-                if i > 0 {
-                    pretty.push_str(", ");
-                }
-                pretty.push_str(&pretty_operand(arg));
-            });
-            pretty.push_str(")");
-            pretty
+            write!(writer, "{INDENT}{:?} = {}(", destination, pretty_operand(func))?;
+            let mut args_iter = args.iter();
+            args_iter.next().map_or(Ok(()), |arg| write!(writer, "{}", pretty_operand(arg)))?;
+            args_iter.try_for_each(|arg| write!(writer, ", {}", pretty_operand(arg)))?;
+            write!(writer, ")")
         }
         Assert { cond, expected, msg, target: _, unwind: _ } => {
-            pretty.push_str("        assert(");
+            write!(writer, "{INDENT}assert(")?;
             if !expected {
-                pretty.push_str("!");
+                write!(writer, "!")?;
             }
-            pretty.push_str(format!("{} bool),", &pretty_operand(cond)).as_str());
-            pretty.push_str(&pretty_assert_message(msg));
-            pretty.push_str(")");
-            pretty
+            write!(writer, "{}, ", &pretty_operand(cond))?;
+            pretty_assert_message(writer, msg)?;
+            write!(writer, ")")
         }
-        InlineAsm { .. } => todo!(),
+        InlineAsm { .. } => write!(writer, "{INDENT}InlineAsm"),
     }
 }
 
-pub fn pretty_successor_labels(terminator: &TerminatorKind) -> Vec<String> {
+fn pretty_successor_labels(terminator: &TerminatorKind) -> Vec<String> {
     use self::TerminatorKind::*;
     match terminator {
         Resume | Abort | Return | Unreachable => vec![],
@@ -201,283 +209,174 @@ pub fn pretty_successor_labels(terminator: &TerminatorKind) -> Vec<String> {
             vec!["success".into(), "unwind".into()]
         }
         Assert { unwind: _, .. } => vec!["success".into()],
-        InlineAsm { .. } => todo!(),
+        InlineAsm { destination: Some(_), .. } => vec!["goto".into(), "unwind".into()],
+        InlineAsm { destination: None, .. } => vec!["unwind".into()],
     }
 }
 
-pub fn pretty_assert_message(msg: &AssertMessage) -> String {
-    let mut pretty = String::new();
+fn pretty_assert_message<W: Write>(writer: &mut W, msg: &AssertMessage) -> io::Result<()> {
     match msg {
         AssertMessage::BoundsCheck { len, index } => {
             let pretty_len = pretty_operand(len);
             let pretty_index = pretty_operand(index);
-            pretty.push_str(format!("\"index out of bounds: the length is {{}} but the index is {{}}\", {pretty_len}, {pretty_index}").as_str());
-            pretty
+            write!(
+                writer,
+                "\"index out of bounds: the length is {{}} but the index is {{}}\", {pretty_len}, {pretty_index}"
+            )
         }
         AssertMessage::Overflow(BinOp::Add, l, r) => {
             let pretty_l = pretty_operand(l);
             let pretty_r = pretty_operand(r);
-            pretty.push_str(format!("\"attempt to compute `{{}} + {{}}`, which would overflow\", {pretty_l}, {pretty_r}").as_str());
-            pretty
+            write!(
+                writer,
+                "\"attempt to compute `{{}} + {{}}`, which would overflow\", {pretty_l}, {pretty_r}"
+            )
         }
         AssertMessage::Overflow(BinOp::Sub, l, r) => {
             let pretty_l = pretty_operand(l);
             let pretty_r = pretty_operand(r);
-            pretty.push_str(format!("\"attempt to compute `{{}} - {{}}`, which would overflow\", {pretty_l}, {pretty_r}").as_str());
-            pretty
+            write!(
+                writer,
+                "\"attempt to compute `{{}} - {{}}`, which would overflow\", {pretty_l}, {pretty_r}"
+            )
         }
         AssertMessage::Overflow(BinOp::Mul, l, r) => {
             let pretty_l = pretty_operand(l);
             let pretty_r = pretty_operand(r);
-            pretty.push_str(format!("\"attempt to compute `{{}} * {{}}`, which would overflow\", {pretty_l}, {pretty_r}").as_str());
-            pretty
+            write!(
+                writer,
+                "\"attempt to compute `{{}} * {{}}`, which would overflow\", {pretty_l}, {pretty_r}"
+            )
         }
         AssertMessage::Overflow(BinOp::Div, l, r) => {
             let pretty_l = pretty_operand(l);
             let pretty_r = pretty_operand(r);
-            pretty.push_str(format!("\"attempt to compute `{{}} / {{}}`, which would overflow\", {pretty_l}, {pretty_r}").as_str());
-            pretty
+            write!(
+                writer,
+                "\"attempt to compute `{{}} / {{}}`, which would overflow\", {pretty_l}, {pretty_r}"
+            )
         }
         AssertMessage::Overflow(BinOp::Rem, l, r) => {
             let pretty_l = pretty_operand(l);
             let pretty_r = pretty_operand(r);
-            pretty.push_str(format!("\"attempt to compute `{{}} % {{}}`, which would overflow\", {pretty_l}, {pretty_r}").as_str());
-            pretty
+            write!(
+                writer,
+                "\"attempt to compute `{{}} % {{}}`, which would overflow\", {pretty_l}, {pretty_r}"
+            )
         }
         AssertMessage::Overflow(BinOp::Shr, _, r) => {
             let pretty_r = pretty_operand(r);
-            pretty.push_str(
-                format!("\"attempt to shift right by `{{}}`, which would overflow\", {pretty_r}")
-                    .as_str(),
-            );
-            pretty
+            write!(writer, "\"attempt to shift right by `{{}}`, which would overflow\", {pretty_r}")
         }
         AssertMessage::Overflow(BinOp::Shl, _, r) => {
             let pretty_r = pretty_operand(r);
-            pretty.push_str(
-                format!("\"attempt to shift left by `{{}}`, which would overflow\", {pretty_r}")
-                    .as_str(),
-            );
-            pretty
+            write!(writer, "\"attempt to shift left by `{{}}`, which would overflow\", {pretty_r}")
         }
         AssertMessage::Overflow(op, _, _) => unreachable!("`{:?}` cannot overflow", op),
         AssertMessage::OverflowNeg(op) => {
             let pretty_op = pretty_operand(op);
-            pretty.push_str(
-                format!("\"attempt to negate `{{}}`, which would overflow\", {pretty_op}").as_str(),
-            );
-            pretty
+            write!(writer, "\"attempt to negate `{{}}`, which would overflow\", {pretty_op}")
         }
         AssertMessage::DivisionByZero(op) => {
             let pretty_op = pretty_operand(op);
-            pretty.push_str(format!("\"attempt to divide `{{}}` by zero\", {pretty_op}").as_str());
-            pretty
+            write!(writer, "\"attempt to divide `{{}}` by zero\", {pretty_op}")
         }
         AssertMessage::RemainderByZero(op) => {
             let pretty_op = pretty_operand(op);
-            pretty.push_str(
-                format!("\"attempt to calculate the remainder of `{{}}` with a divisor of zero\", {pretty_op}").as_str(),
-            );
-            pretty
+            write!(
+                writer,
+                "\"attempt to calculate the remainder of `{{}}` with a divisor of zero\", {pretty_op}"
+            )
         }
         AssertMessage::MisalignedPointerDereference { required, found } => {
             let pretty_required = pretty_operand(required);
             let pretty_found = pretty_operand(found);
-            pretty.push_str(format!("\"misaligned pointer dereference: address must be a multiple of {{}} but is {{}}\",{pretty_required}, {pretty_found}").as_str());
-            pretty
+            write!(
+                writer,
+                "\"misaligned pointer dereference: address must be a multiple of {{}} but is {{}}\",{pretty_required}, {pretty_found}"
+            )
         }
         AssertMessage::ResumedAfterReturn(_) | AssertMessage::ResumedAfterPanic(_) => {
-            msg.description().unwrap().to_string()
+            write!(writer, "{}", msg.description().unwrap())
         }
     }
 }
 
-pub fn pretty_operand(operand: &Operand) -> String {
-    let mut pretty = String::new();
+fn pretty_operand(operand: &Operand) -> String {
     match operand {
         Operand::Copy(copy) => {
-            pretty.push_str("");
-            pretty.push_str(format!("{}", copy.local).as_str());
+            format!("{:?}", copy)
         }
         Operand::Move(mv) => {
-            pretty.push_str("move ");
-            pretty.push_str(format!("_{}", mv.local).as_str());
-        }
-        Operand::Constant(cnst) => {
-            pretty.push_str("const ");
-            pretty.push_str(with(|cx| cx.const_literal(&cnst.literal)).as_str());
+            format!("move {:?}", mv)
         }
+        Operand::Constant(cnst) => pretty_const(&cnst.literal),
     }
-    pretty
 }
 
-pub fn pretty_rvalue(rval: &Rvalue) -> String {
-    let mut pretty = String::new();
+fn pretty_const(literal: &Const) -> String {
+    with(|cx| cx.const_pretty(&literal))
+}
+
+fn pretty_rvalue<W: Write>(writer: &mut W, rval: &Rvalue) -> io::Result<()> {
     match rval {
-        Rvalue::AddressOf(muta, addr) => {
-            pretty.push_str("&raw ");
-            pretty.push_str(&ret_mutability(muta));
-            pretty.push_str(format!("(*_{})", addr.local).as_str());
-        }
-        Rvalue::Aggregate(aggregatekind, operands) => {
-            pretty.push_str(format!("{:#?}", aggregatekind).as_str());
-            pretty.push_str("(");
-            operands.iter().enumerate().for_each(|(i, op)| {
-                pretty.push_str(&pretty_operand(op));
-                if i != operands.len() - 1 {
-                    pretty.push_str(", ");
-                }
-            });
-            pretty.push_str(")");
+        Rvalue::AddressOf(mutability, place) => {
+            write!(writer, "&raw {}(*{:?})", &pretty_mut(*mutability), place)
         }
-        Rvalue::BinaryOp(bin, op, op2) => {
-            pretty.push_str(&pretty_operand(op));
-            pretty.push_str(" ");
-            pretty.push_str(format!("{:#?}", bin).as_str());
-            pretty.push_str(" ");
-            pretty.push_str(&pretty_operand(op2));
+        Rvalue::Aggregate(aggregate_kind, operands) => {
+            // FIXME: Add pretty_aggregate function that returns a pretty string
+            write!(writer, "{aggregate_kind:?} (")?;
+            let mut op_iter = operands.iter();
+            op_iter.next().map_or(Ok(()), |op| write!(writer, "{}", pretty_operand(op)))?;
+            op_iter.try_for_each(|op| write!(writer, ", {}", pretty_operand(op)))?;
+            write!(writer, ")")
+        }
+        Rvalue::BinaryOp(bin, op1, op2) => {
+            write!(writer, "{:?}({}, {})", bin, &pretty_operand(op1), pretty_operand(op2))
         }
         Rvalue::Cast(_, op, ty) => {
-            pretty.push_str(&pretty_operand(op));
-            pretty.push_str(" as ");
-            pretty.push_str(&pretty_ty(ty.kind()));
+            write!(writer, "{} as {}", pretty_operand(op), ty)
         }
         Rvalue::CheckedBinaryOp(bin, op1, op2) => {
-            pretty.push_str(&pretty_operand(op1));
-            pretty.push_str(" ");
-            pretty.push_str(format!("{:#?}", bin).as_str());
-            pretty.push_str(" ");
-            pretty.push_str(&pretty_operand(op2));
+            write!(writer, "Checked{:?}({}, {})", bin, &pretty_operand(op1), pretty_operand(op2))
         }
         Rvalue::CopyForDeref(deref) => {
-            pretty.push_str("CopyForDeref");
-            pretty.push_str(format!("{}", deref.local).as_str());
+            write!(writer, "CopyForDeref({:?})", deref)
         }
         Rvalue::Discriminant(place) => {
-            pretty.push_str("discriminant");
-            pretty.push_str(format!("{}", place.local).as_str());
+            write!(writer, "discriminant({:?})", place)
         }
         Rvalue::Len(len) => {
-            pretty.push_str("len");
-            pretty.push_str(format!("{}", len.local).as_str());
+            write!(writer, "len({:?})", len)
         }
         Rvalue::Ref(_, borrowkind, place) => {
-            pretty.push_str("ref");
-            pretty.push_str(format!("{:#?}", borrowkind).as_str());
-            pretty.push_str(format!("{}", place.local).as_str());
+            let kind = match borrowkind {
+                BorrowKind::Shared => "&",
+                BorrowKind::Fake => "&fake ",
+                BorrowKind::Mut { .. } => "&mut ",
+            };
+            write!(writer, "{kind}{:?}", place)
         }
         Rvalue::Repeat(op, cnst) => {
-            pretty.push_str(&pretty_operand(op));
-            pretty.push_str(" ");
-            pretty.push_str(&pretty_ty(cnst.ty().kind()));
+            write!(writer, "{} \" \" {}", &pretty_operand(op), cnst.ty())
         }
-        Rvalue::ShallowInitBox(_, _) => (),
+        Rvalue::ShallowInitBox(_, _) => Ok(()),
         Rvalue::ThreadLocalRef(item) => {
-            pretty.push_str("thread_local_ref");
-            pretty.push_str(format!("{:#?}", item).as_str());
+            write!(writer, "thread_local_ref{:?}", item)
         }
         Rvalue::NullaryOp(nul, ty) => {
-            pretty.push_str(format!("{:#?}", nul).as_str());
-            pretty.push_str(&pretty_ty(ty.kind()));
-            pretty.push_str(" ");
+            write!(writer, "{:?} {} \" \"", nul, ty)
         }
         Rvalue::UnaryOp(un, op) => {
-            pretty.push_str(&pretty_operand(op));
-            pretty.push_str(" ");
-            pretty.push_str(format!("{:#?}", un).as_str());
+            write!(writer, "{} \" \" {:?}", pretty_operand(op), un)
         }
-        Rvalue::Use(op) => pretty.push_str(&pretty_operand(op)),
+        Rvalue::Use(op) => write!(writer, "{}", pretty_operand(op)),
     }
-    pretty
 }
 
-pub fn pretty_ty(ty: TyKind) -> String {
-    let mut pretty = String::new();
-    match ty {
-        TyKind::RigidTy(rigid_ty) => match rigid_ty {
-            RigidTy::Bool => "bool".to_string(),
-            RigidTy::Char => "char".to_string(),
-            RigidTy::Int(i) => match i {
-                IntTy::Isize => "isize".to_string(),
-                IntTy::I8 => "i8".to_string(),
-                IntTy::I16 => "i16".to_string(),
-                IntTy::I32 => "i32".to_string(),
-                IntTy::I64 => "i64".to_string(),
-                IntTy::I128 => "i128".to_string(),
-            },
-            RigidTy::Uint(u) => match u {
-                UintTy::Usize => "usize".to_string(),
-                UintTy::U8 => "u8".to_string(),
-                UintTy::U16 => "u16".to_string(),
-                UintTy::U32 => "u32".to_string(),
-                UintTy::U64 => "u64".to_string(),
-                UintTy::U128 => "u128".to_string(),
-            },
-            RigidTy::Float(f) => match f {
-                FloatTy::F32 => "f32".to_string(),
-                FloatTy::F64 => "f64".to_string(),
-            },
-            RigidTy::Adt(def, _) => {
-                format!("{:#?}", with(|cx| cx.def_ty(def.0)))
-            }
-            RigidTy::Str => "str".to_string(),
-            RigidTy::Array(ty, len) => {
-                format!("[{}; {}]", pretty_ty(ty.kind()), with(|cx| cx.const_literal(&len)))
-            }
-            RigidTy::Slice(ty) => {
-                format!("[{}]", pretty_ty(ty.kind()))
-            }
-            RigidTy::RawPtr(ty, mutability) => {
-                pretty.push_str("*");
-                match mutability {
-                    Mutability::Not => pretty.push_str("const "),
-                    Mutability::Mut => pretty.push_str("mut "),
-                }
-                pretty.push_str(&pretty_ty(ty.kind()));
-                pretty
-            }
-            RigidTy::Ref(_, ty, mutability) => match mutability {
-                Mutability::Not => format!("&{}", pretty_ty(ty.kind())),
-                Mutability::Mut => format!("&mut {}", pretty_ty(ty.kind())),
-            },
-            RigidTy::FnDef(_, _) => format!("{:#?}", rigid_ty),
-            RigidTy::FnPtr(_) => format!("{:#?}", rigid_ty),
-            RigidTy::Closure(_, _) => format!("{:#?}", rigid_ty),
-            RigidTy::Coroutine(_, _, _) => format!("{:#?}", rigid_ty),
-            RigidTy::Dynamic(data, region, repr) => {
-                // FIXME: Fix binder printing, it looks ugly now
-                pretty.push_str("(");
-                match repr {
-                    DynKind::Dyn => pretty.push_str("dyn "),
-                    DynKind::DynStar => pretty.push_str("dyn* "),
-                }
-                pretty.push_str(format!("{:#?}", data).as_str());
-                pretty.push_str(format!(" +  {:#?} )", region).as_str());
-                pretty
-            }
-            RigidTy::Never => "!".to_string(),
-            RigidTy::Tuple(tuple) => {
-                if tuple.is_empty() {
-                    "()".to_string()
-                } else {
-                    let mut tuple_str = String::new();
-                    tuple_str.push_str("(");
-                    tuple.iter().enumerate().for_each(|(i, ty)| {
-                        tuple_str.push_str(&pretty_ty(ty.kind()));
-                        if i != tuple.len() - 1 {
-                            tuple_str.push_str(", ");
-                        }
-                    });
-                    tuple_str.push_str(")");
-                    tuple_str
-                }
-            }
-            _ => format!("{:#?}", rigid_ty),
-        },
-        TyKind::Alias(_, _) => format!("{:#?}", ty),
-        TyKind::Param(param_ty) => {
-            format!("{:#?}", param_ty.name)
-        }
-        TyKind::Bound(_, _) => format!("{:#?}", ty),
+fn pretty_mut(mutability: Mutability) -> &'static str {
+    match mutability {
+        Mutability::Not => " ",
+        Mutability::Mut => "mut ",
     }
 }
diff --git a/library/core/src/macros/mod.rs b/library/core/src/macros/mod.rs
index 0ee7e190e3d..ebcaa626bd3 100644
--- a/library/core/src/macros/mod.rs
+++ b/library/core/src/macros/mod.rs
@@ -1704,14 +1704,14 @@ pub(crate) mod builtin {
     }
 
     /// Unstable placeholder for type ascription.
-    #[rustc_builtin_macro]
+    #[allow_internal_unstable(builtin_syntax)]
     #[unstable(
         feature = "type_ascription",
         issue = "23416",
         reason = "placeholder syntax for type ascription"
     )]
     pub macro type_ascribe($expr:expr, $ty:ty) {
-        /* compiler built-in */
+        builtin # type_ascribe($expr, $ty)
     }
 
     /// Unstable implementation detail of the `rustc` compiler, do not use.
diff --git a/src/bootstrap/src/lib.rs b/src/bootstrap/src/lib.rs
index 64bb7bf01f7..f1edbb5ad8a 100644
--- a/src/bootstrap/src/lib.rs
+++ b/src/bootstrap/src/lib.rs
@@ -1389,6 +1389,13 @@ impl Build {
         if let Some(path) = finder.maybe_have("wasmtime") {
             if let Ok(mut path) = path.into_os_string().into_string() {
                 path.push_str(" run -C cache=n --dir .");
+                // Make sure that tests have access to RUSTC_BOOTSTRAP. This (for example) is
+                // required for libtest to work on beta/stable channels.
+                //
+                // NB: with Wasmtime 20 this can change to `-S inherit-env` to
+                // inherit the entire environment rather than just this single
+                // environment variable.
+                path.push_str(" --env RUSTC_BOOTSTRAP");
                 return Some(path);
             }
         }
diff --git a/src/ci/docker/host-x86_64/test-various/Dockerfile b/src/ci/docker/host-x86_64/test-various/Dockerfile
index 944d9aed319..4de9afdb171 100644
--- a/src/ci/docker/host-x86_64/test-various/Dockerfile
+++ b/src/ci/docker/host-x86_64/test-various/Dockerfile
@@ -55,9 +55,9 @@ ENV RUST_CONFIGURE_ARGS \
 ENV NO_DEBUG_ASSERTIONS=1
 ENV NO_OVERFLOW_CHECKS=1
 
-RUN curl -L https://github.com/bytecodealliance/wasmtime/releases/download/v18.0.2/wasmtime-v18.0.2-x86_64-linux.tar.xz | \
+RUN curl -L https://github.com/bytecodealliance/wasmtime/releases/download/v19.0.0/wasmtime-v19.0.0-x86_64-linux.tar.xz | \
   tar -xJ
-ENV PATH "$PATH:/wasmtime-v18.0.2-x86_64-linux"
+ENV PATH "$PATH:/wasmtime-v19.0.0-x86_64-linux"
 
 ENV WASM_TARGETS=wasm32-wasip1
 ENV WASM_SCRIPT python3 /checkout/x.py --stage 2 test --host='' --target $WASM_TARGETS \
diff --git a/src/doc/rustc/src/platform-support.md b/src/doc/rustc/src/platform-support.md
index 274745b9082..75d38dd20bd 100644
--- a/src/doc/rustc/src/platform-support.md
+++ b/src/doc/rustc/src/platform-support.md
@@ -339,6 +339,7 @@ target | std | host | notes
 `riscv32gc-unknown-linux-gnu` |   |   | RISC-V Linux (kernel 5.4, glibc 2.33)
 `riscv32gc-unknown-linux-musl` |   |   | RISC-V Linux (kernel 5.4, musl 1.2.3 + RISCV32 support patches)
 [`riscv32im-risc0-zkvm-elf`](platform-support/riscv32im-risc0-zkvm-elf.md) | ? |  | RISC Zero's zero-knowledge Virtual Machine (RV32IM ISA)
+[`riscv32ima-unknown-none-elf`](platform-support/riscv32-unknown-none-elf.md) | * |  | Bare RISC-V (RV32IMA ISA)
 [`riscv32imac-unknown-xous-elf`](platform-support/riscv32imac-unknown-xous-elf.md) | ? |  | RISC-V Xous (RV32IMAC ISA)
 [`riscv32imc-esp-espidf`](platform-support/esp-idf.md) | ✓ |  | RISC-V ESP-IDF
 [`riscv32imac-esp-espidf`](platform-support/esp-idf.md) | ✓ |  | RISC-V ESP-IDF
diff --git a/src/doc/rustc/src/platform-support/riscv32-unknown-none-elf.md b/src/doc/rustc/src/platform-support/riscv32-unknown-none-elf.md
index 739b12bad8b..9a27a568b57 100644
--- a/src/doc/rustc/src/platform-support/riscv32-unknown-none-elf.md
+++ b/src/doc/rustc/src/platform-support/riscv32-unknown-none-elf.md
@@ -1,9 +1,13 @@
-# `riscv32{i,im,imc,imac,imafc}-unknown-none-elf`
+# `riscv32{i,im,ima,imc,imac,imafc}-unknown-none-elf`
 
 **Tier: 2**
 
 Bare-metal target for RISC-V CPUs with the RV32I, RV32IM, RV32IMC, RV32IMAFC and RV32IMAC ISAs.
 
+**Tier: 3**
+
+Bare-metal target for RISC-V CPUs with the RV32IMA ISA.
+
 ## Target maintainers
 
 * Rust Embedded Working Group, [RISC-V team](https://github.com/rust-embedded/wg#the-risc-v-team)
diff --git a/src/tools/build-manifest/src/main.rs b/src/tools/build-manifest/src/main.rs
index eab9138b8fe..392a5a11967 100644
--- a/src/tools/build-manifest/src/main.rs
+++ b/src/tools/build-manifest/src/main.rs
@@ -126,6 +126,7 @@ static TARGETS: &[&str] = &[
     "riscv32i-unknown-none-elf",
     "riscv32im-risc0-zkvm-elf",
     "riscv32im-unknown-none-elf",
+    "riscv32ima-unknown-none-elf",
     "riscv32imc-unknown-none-elf",
     "riscv32imac-unknown-none-elf",
     "riscv32imafc-unknown-none-elf",
diff --git a/src/tools/clippy/clippy_lints/src/box_default.rs b/src/tools/clippy/clippy_lints/src/box_default.rs
index 779ae03c464..66206d1a059 100644
--- a/src/tools/clippy/clippy_lints/src/box_default.rs
+++ b/src/tools/clippy/clippy_lints/src/box_default.rs
@@ -70,7 +70,9 @@ impl LateLintPass<'_> for BoxDefault {
                 "try",
                 if is_plain_default(cx, arg_path) || given_type(cx, expr) {
                     "Box::default()".into()
-                } else if let Some(arg_ty) = cx.typeck_results().expr_ty(arg).make_suggestable(cx.tcx, true) {
+                } else if let Some(arg_ty) =
+                    cx.typeck_results().expr_ty(arg).make_suggestable(cx.tcx, true, None)
+                {
                     // Check if we can copy from the source expression in the replacement.
                     // We need the call to have no argument (see `explicit_default_type`).
                     if inner_call_args.is_empty()
diff --git a/tests/assembly/targets/targets-elf.rs b/tests/assembly/targets/targets-elf.rs
index bda77b5f09b..3563aec6d80 100644
--- a/tests/assembly/targets/targets-elf.rs
+++ b/tests/assembly/targets/targets-elf.rs
@@ -369,6 +369,9 @@
 //@ revisions: riscv32im_unknown_none_elf
 //@ [riscv32im_unknown_none_elf] compile-flags: --target riscv32im-unknown-none-elf
 //@ [riscv32im_unknown_none_elf] needs-llvm-components: riscv
+//@ revisions: riscv32ima_unknown_none_elf
+//@ [riscv32ima_unknown_none_elf] compile-flags: --target riscv32ima-unknown-none-elf
+//@ [riscv32ima_unknown_none_elf] needs-llvm-components: riscv
 //@ revisions: riscv32imac_esp_espidf
 //@ [riscv32imac_esp_espidf] compile-flags: --target riscv32imac-esp-espidf
 //@ [riscv32imac_esp_espidf] needs-llvm-components: riscv
diff --git a/tests/ui/async-await/send-bound-async-closure.rs b/tests/ui/async-await/send-bound-async-closure.rs
index 2732fa5d466..e4a9ae4cc75 100644
--- a/tests/ui/async-await/send-bound-async-closure.rs
+++ b/tests/ui/async-await/send-bound-async-closure.rs
@@ -1,5 +1,8 @@
 //@ edition: 2021
 //@ check-pass
+//@ revisions: current next
+//@ ignore-compare-mode-next-solver (explicit revisions)
+//@[next] compile-flags: -Znext-solver
 
 // This test verifies that we do not create a query cycle when typechecking has several inference
 // variables that point to the same coroutine interior type.
diff --git a/tests/ui/cfg/cfg-false-feature.stderr b/tests/ui/cfg/cfg-false-feature.stderr
index 9309b59ca59..542aeaf5caf 100644
--- a/tests/ui/cfg/cfg-false-feature.stderr
+++ b/tests/ui/cfg/cfg-false-feature.stderr
@@ -1,15 +1,3 @@
-warning: trait aliases are experimental
-  --> $DIR/cfg-false-feature.rs:12:1
-   |
-LL | trait A = Clone;
-   | ^^^^^^^^^^^^^^^^
-   |
-   = note: see issue #41517 <https://github.com/rust-lang/rust/issues/41517> for more information
-   = help: add `#![feature(trait_alias)]` to the crate attributes to enable
-   = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
-   = warning: unstable syntax can change at any point in the future, causing a hard error!
-   = note: for more information, see issue #65860 <https://github.com/rust-lang/rust/issues/65860>
-
 warning: box pattern syntax is experimental
   --> $DIR/cfg-false-feature.rs:16:9
    |
@@ -22,5 +10,17 @@ LL |     let box _ = Box::new(0);
    = warning: unstable syntax can change at any point in the future, causing a hard error!
    = note: for more information, see issue #65860 <https://github.com/rust-lang/rust/issues/65860>
 
+warning: trait aliases are experimental
+  --> $DIR/cfg-false-feature.rs:12:1
+   |
+LL | trait A = Clone;
+   | ^^^^^^^^^^^^^^^^
+   |
+   = note: see issue #41517 <https://github.com/rust-lang/rust/issues/41517> for more information
+   = help: add `#![feature(trait_alias)]` to the crate attributes to enable
+   = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
+   = warning: unstable syntax can change at any point in the future, causing a hard error!
+   = note: for more information, see issue #65860 <https://github.com/rust-lang/rust/issues/65860>
+
 warning: 2 warnings emitted
 
diff --git a/tests/ui/feature-gates/feature-gate-deref_patterns.rs b/tests/ui/feature-gates/feature-gate-deref_patterns.rs
new file mode 100644
index 00000000000..b43001f2d53
--- /dev/null
+++ b/tests/ui/feature-gates/feature-gate-deref_patterns.rs
@@ -0,0 +1,9 @@
+fn main() {
+    // We reuse the `box` syntax so this doesn't actually test the feature gate but eh.
+    let box x = Box::new('c'); //~ ERROR box pattern syntax is experimental
+    println!("x: {}", x);
+
+    // `box` syntax is allowed to be cfg-ed out for historical reasons (#65742).
+    #[cfg(FALSE)]
+    let box _x = Box::new('c');
+}
diff --git a/tests/ui/feature-gates/feature-gate-deref_patterns.stderr b/tests/ui/feature-gates/feature-gate-deref_patterns.stderr
new file mode 100644
index 00000000000..48426b50d89
--- /dev/null
+++ b/tests/ui/feature-gates/feature-gate-deref_patterns.stderr
@@ -0,0 +1,13 @@
+error[E0658]: box pattern syntax is experimental
+  --> $DIR/feature-gate-deref_patterns.rs:3:9
+   |
+LL |     let box x = Box::new('c');
+   |         ^^^^^
+   |
+   = note: see issue #29641 <https://github.com/rust-lang/rust/issues/29641> for more information
+   = help: add `#![feature(box_patterns)]` to the crate attributes to enable
+   = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
+
+error: aborting due to 1 previous error
+
+For more information about this error, try `rustc --explain E0658`.
diff --git a/tests/ui/pattern/deref-patterns/typeck.rs b/tests/ui/pattern/deref-patterns/typeck.rs
new file mode 100644
index 00000000000..20577abe485
--- /dev/null
+++ b/tests/ui/pattern/deref-patterns/typeck.rs
@@ -0,0 +1,31 @@
+//@ check-pass
+#![feature(deref_patterns)]
+#![allow(incomplete_features)]
+
+use std::rc::Rc;
+
+fn main() {
+    let vec: Vec<u32> = Vec::new();
+    match vec {
+        box [..] => {}
+        _ => {}
+    }
+    match Box::new(true) {
+        box true => {}
+        _ => {}
+    }
+    match &Box::new(true) {
+        box true => {}
+        _ => {}
+    }
+    match &Rc::new(0) {
+        box (1..) => {}
+        _ => {}
+    }
+    // FIXME(deref_patterns): fails to typecheck because `"foo"` has type &str but deref creates a
+    // place of type `str`.
+    // match "foo".to_string() {
+    //     box "foo" => {}
+    //     _ => {}
+    // }
+}
diff --git a/tests/ui/raw-ref-op/raw-ref-temp.stderr b/tests/ui/raw-ref-op/raw-ref-temp.stderr
index b9666162517..1f6d85e4a7e 100644
--- a/tests/ui/raw-ref-op/raw-ref-temp.stderr
+++ b/tests/ui/raw-ref-op/raw-ref-temp.stderr
@@ -75,24 +75,32 @@ error[E0745]: cannot take address of a temporary
    |
 LL |     let ref_ascribe = &raw const type_ascribe!(2, i32);
    |                                  ^^^^^^^^^^^^^^^^^^^^^ temporary value
+   |
+   = note: this error originates in the macro `type_ascribe` (in Nightly builds, run with -Z macro-backtrace for more info)
 
 error[E0745]: cannot take address of a temporary
   --> $DIR/raw-ref-temp.rs:27:36
    |
 LL |     let mut_ref_ascribe = &raw mut type_ascribe!(3, i32);
    |                                    ^^^^^^^^^^^^^^^^^^^^^ temporary value
+   |
+   = note: this error originates in the macro `type_ascribe` (in Nightly builds, run with -Z macro-backtrace for more info)
 
 error[E0745]: cannot take address of a temporary
   --> $DIR/raw-ref-temp.rs:29:40
    |
 LL |     let ascribe_field_ref = &raw const type_ascribe!(PAIR.0, i32);
    |                                        ^^^^^^^^^^^^^^^^^^^^^^^^^^ temporary value
+   |
+   = note: this error originates in the macro `type_ascribe` (in Nightly builds, run with -Z macro-backtrace for more info)
 
 error[E0745]: cannot take address of a temporary
   --> $DIR/raw-ref-temp.rs:30:38
    |
 LL |     let ascribe_index_ref = &raw mut type_ascribe!(ARRAY[0], i32);
    |                                      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ temporary value
+   |
+   = note: this error originates in the macro `type_ascribe` (in Nightly builds, run with -Z macro-backtrace for more info)
 
 error: aborting due to 16 previous errors
 
diff --git a/tests/ui/reachable/expr_type.stderr b/tests/ui/reachable/expr_type.stderr
index 70536326fd8..008b867e230 100644
--- a/tests/ui/reachable/expr_type.stderr
+++ b/tests/ui/reachable/expr_type.stderr
@@ -12,6 +12,7 @@ note: the lint level is defined here
    |
 LL | #![deny(unreachable_code)]
    |         ^^^^^^^^^^^^^^^^
+   = note: this error originates in the macro `type_ascribe` (in Nightly builds, run with -Z macro-backtrace for more info)
 
 error: aborting due to 1 previous error
 
diff --git a/tests/ui/stable-mir-print/basic_function.rs b/tests/ui/stable-mir-print/basic_function.rs
index 9b27a56dab1..deefef63bdb 100644
--- a/tests/ui/stable-mir-print/basic_function.rs
+++ b/tests/ui/stable-mir-print/basic_function.rs
@@ -2,7 +2,7 @@
 //@ check-pass
 //@ only-x86_64
 
-fn foo(i:i32) -> i32 {
+fn foo(i: i32) -> i32 {
     i + 1
 }
 
@@ -12,4 +12,13 @@ fn bar(vec: &mut Vec<i32>) -> Vec<i32> {
     new_vec
 }
 
-fn main(){}
+pub fn demux(input: u8) -> u8 {
+    match input {
+        0 => 10,
+        1 => 6,
+        2 => 8,
+        _ => 0,
+    }
+}
+
+fn main() {}
diff --git a/tests/ui/stable-mir-print/basic_function.stdout b/tests/ui/stable-mir-print/basic_function.stdout
index d9b33a4257c..3926c1048f5 100644
--- a/tests/ui/stable-mir-print/basic_function.stdout
+++ b/tests/ui/stable-mir-print/basic_function.stdout
@@ -1,234 +1,74 @@
 // WARNING: This is highly experimental output it's intended for stable-mir developers only.
 // If you find a bug or want to improve the output open a issue at https://github.com/rust-lang/project-stable-mir.
-fn foo(_0: i32) -> i32 {
-    let mut _0: (i32, bool);
+fn foo(_1: i32) -> i32 {
+    let mut _0: i32;
+    let mut _2: (i32, bool);
+    debug i => _1;
+    bb0: {
+        _2 = CheckedAdd(_1, 1_i32);
+        assert(!move (_2.1: bool), "attempt to compute `{} + {}`, which would overflow", _1, 1_i32) -> [success: bb1, unwind continue];
+    }
+    bb1: {
+        _0 = move (_2.0: i32);
+        return;
+    }
 }
+fn bar(_1: &mut Vec<i32>) -> Vec<i32> {
+    let mut _0: Vec<i32>;
+    let mut _2: Vec<i32>;
+    let mut _3: &Vec<i32>;
+    let  _4: ();
+    let mut _5: &mut Vec<i32>;
+    debug vec => _1;
+    debug new_vec => _2;
     bb0: {
-        _2 = 1 Add const 1_i32
-        assert(!move _2 bool),"attempt to compute `{} + {}`, which would overflow", 1, const 1_i32) -> [success: bb1, unwind continue]
+        _3 = &(*_1);
+        _2 = <Vec<i32> as Clone>::clone(move _3) -> [return: bb1, unwind continue];
     }
     bb1: {
-        _0 = move _2
-        return
+        _5 = &mut _2;
+        _4 = Vec::<i32>::push(move _5, 1_i32) -> [return: bb2, unwind: bb3];
+    }
+    bb2: {
+        _0 = move _2;
+        return;
+    }
+    bb3: {
+        drop(_2) -> [return: bb4, unwind terminate];
+    }
+    bb4: {
+        resume;
     }
-fn bar(_0: &mut Ty {
-    id: 10,
-    kind: RigidTy(
-        Adt(
-            AdtDef(
-                DefId {
-                    id: 3,
-                    name: "std::vec::Vec",
-                },
-            ),
-            GenericArgs(
-                [
-                    Type(
-                        Ty {
-                            id: 11,
-                            kind: Param(
-                                ParamTy {
-                                    index: 0,
-                                    name: "T",
-                                },
-                            ),
-                        },
-                    ),
-                    Type(
-                        Ty {
-                            id: 12,
-                            kind: Param(
-                                ParamTy {
-                                    index: 1,
-                                    name: "A",
-                                },
-                            ),
-                        },
-                    ),
-                ],
-            ),
-        ),
-    ),
-}) -> Ty {
-    id: 10,
-    kind: RigidTy(
-        Adt(
-            AdtDef(
-                DefId {
-                    id: 3,
-                    name: "std::vec::Vec",
-                },
-            ),
-            GenericArgs(
-                [
-                    Type(
-                        Ty {
-                            id: 11,
-                            kind: Param(
-                                ParamTy {
-                                    index: 0,
-                                    name: "T",
-                                },
-                            ),
-                        },
-                    ),
-                    Type(
-                        Ty {
-                            id: 12,
-                            kind: Param(
-                                ParamTy {
-                                    index: 1,
-                                    name: "A",
-                                },
-                            ),
-                        },
-                    ),
-                ],
-            ),
-        ),
-    ),
-} {
-    let mut _0: Ty {
-    id: 10,
-    kind: RigidTy(
-        Adt(
-            AdtDef(
-                DefId {
-                    id: 3,
-                    name: "std::vec::Vec",
-                },
-            ),
-            GenericArgs(
-                [
-                    Type(
-                        Ty {
-                            id: 11,
-                            kind: Param(
-                                ParamTy {
-                                    index: 0,
-                                    name: "T",
-                                },
-                            ),
-                        },
-                    ),
-                    Type(
-                        Ty {
-                            id: 12,
-                            kind: Param(
-                                ParamTy {
-                                    index: 1,
-                                    name: "A",
-                                },
-                            ),
-                        },
-                    ),
-                ],
-            ),
-        ),
-    ),
-};
-    let mut _1: &Ty {
-    id: 10,
-    kind: RigidTy(
-        Adt(
-            AdtDef(
-                DefId {
-                    id: 3,
-                    name: "std::vec::Vec",
-                },
-            ),
-            GenericArgs(
-                [
-                    Type(
-                        Ty {
-                            id: 11,
-                            kind: Param(
-                                ParamTy {
-                                    index: 0,
-                                    name: "T",
-                                },
-                            ),
-                        },
-                    ),
-                    Type(
-                        Ty {
-                            id: 12,
-                            kind: Param(
-                                ParamTy {
-                                    index: 1,
-                                    name: "A",
-                                },
-                            ),
-                        },
-                    ),
-                ],
-            ),
-        ),
-    ),
-};
-    let _2: ();
-    let mut _3: &mut Ty {
-    id: 10,
-    kind: RigidTy(
-        Adt(
-            AdtDef(
-                DefId {
-                    id: 3,
-                    name: "std::vec::Vec",
-                },
-            ),
-            GenericArgs(
-                [
-                    Type(
-                        Ty {
-                            id: 11,
-                            kind: Param(
-                                ParamTy {
-                                    index: 0,
-                                    name: "T",
-                                },
-                            ),
-                        },
-                    ),
-                    Type(
-                        Ty {
-                            id: 12,
-                            kind: Param(
-                                ParamTy {
-                                    index: 1,
-                                    name: "A",
-                                },
-                            ),
-                        },
-                    ),
-                ],
-            ),
-        ),
-    ),
-};
 }
+fn demux(_1: u8) -> u8 {
+    let mut _0: u8;
+    debug input => _1;
     bb0: {
-        _3 = refShared1
-        _2 = const <Vec<i32> as Clone>::clone(move _3) -> [return: bb1, unwind continue]
+        switchInt(_1) -> [0: bb2, 1: bb3, 2: bb4, otherwise: bb1];
     }
     bb1: {
-        _5 = refMut {
-    kind: TwoPhaseBorrow,
-}2
-        _4 = const Vec::<i32>::push(move _5, const 1_i32) -> [return: bb2, unwind: bb3]
+        _0 = 0_u8;
+        goto -> bb5;
     }
     bb2: {
-        _0 = move _2
-        return
+        _0 = 10_u8;
+        goto -> bb5;
     }
     bb3: {
-        drop(_2) -> [return: bb4, unwind terminate]
+        _0 = 6_u8;
+        goto -> bb5;
     }
     bb4: {
-        resume
+        _0 = 8_u8;
+        goto -> bb5;
+    }
+    bb5: {
+        return;
     }
-fn main() -> () {
 }
+fn main() -> () {
+    let mut _0: ();
     bb0: {
-        return
+        return;
     }
+}
diff --git a/tests/ui/suggestions/types/into-inference-needs-type.rs b/tests/ui/suggestions/types/into-inference-needs-type.rs
new file mode 100644
index 00000000000..4c8b6ec2113
--- /dev/null
+++ b/tests/ui/suggestions/types/into-inference-needs-type.rs
@@ -0,0 +1,15 @@
+#[derive(Debug)]
+enum MyError {
+    MainError
+}
+
+fn main() -> Result<(), MyError> {
+    let vec = vec!["one", "two", "three"];
+    let list = vec
+        .iter()
+        .map(|s| s.strip_prefix("t"))
+        .filter_map(Option::Some)
+        .into()?; //~ ERROR type annotations needed
+
+    return Ok(());
+}
diff --git a/tests/ui/suggestions/types/into-inference-needs-type.stderr b/tests/ui/suggestions/types/into-inference-needs-type.stderr
new file mode 100644
index 00000000000..dd688f90289
--- /dev/null
+++ b/tests/ui/suggestions/types/into-inference-needs-type.stderr
@@ -0,0 +1,19 @@
+error[E0283]: type annotations needed
+  --> $DIR/into-inference-needs-type.rs:12:10
+   |
+LL |         .into()?;
+   |          ^^^^
+   |
+   = note: cannot satisfy `_: From<FilterMap<Map<std::slice::Iter<'_, &str>, {closure@$DIR/into-inference-needs-type.rs:10:14: 10:17}>, fn(Option<&str>) -> Option<Option<&str>> {Option::<Option<&str>>::Some}>>`
+   = note: required for `FilterMap<Map<std::slice::Iter<'_, &str>, {closure@$DIR/into-inference-needs-type.rs:10:14: 10:17}>, fn(Option<&str>) -> Option<Option<&str>> {Option::<Option<&str>>::Some}>` to implement `Into<_>`
+help: try using a fully qualified path to specify the expected types
+   |
+LL ~     let list = <FilterMap<Map<std::slice::Iter<'_, &str>, _>, _> as Into<T>>::into(vec
+LL |         .iter()
+LL |         .map(|s| s.strip_prefix("t"))
+LL ~         .filter_map(Option::Some))?;
+   |
+
+error: aborting due to 1 previous error
+
+For more information about this error, try `rustc --explain E0283`.
diff --git a/tests/ui/traits/suggest-fully-qualified-closure.rs b/tests/ui/traits/suggest-fully-qualified-closure.rs
index f401a3012da..3d28a4e6bf5 100644
--- a/tests/ui/traits/suggest-fully-qualified-closure.rs
+++ b/tests/ui/traits/suggest-fully-qualified-closure.rs
@@ -1,7 +1,5 @@
 //@ check-fail
 //@ known-bug: #103705
-//@ normalize-stderr-test "\{closure@.*\}" -> "{closure@}"
-//@ normalize-stderr-test "\+* ~" -> "+++ ~"
 
 // The output of this currently suggests writing a closure in the qualified path.
 
diff --git a/tests/ui/traits/suggest-fully-qualified-closure.stderr b/tests/ui/traits/suggest-fully-qualified-closure.stderr
index e077bd7ac2a..a2c1115e673 100644
--- a/tests/ui/traits/suggest-fully-qualified-closure.stderr
+++ b/tests/ui/traits/suggest-fully-qualified-closure.stderr
@@ -1,11 +1,11 @@
 error[E0283]: type annotations needed
-  --> $DIR/suggest-fully-qualified-closure.rs:23:7
+  --> $DIR/suggest-fully-qualified-closure.rs:21:7
    |
 LL |     q.lol(||());
    |       ^^^
    |
 note: multiple `impl`s satisfying `Qqq: MyTrait<_>` found
-  --> $DIR/suggest-fully-qualified-closure.rs:14:1
+  --> $DIR/suggest-fully-qualified-closure.rs:12:1
    |
 LL | impl MyTrait<u32> for Qqq{
    | ^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -14,8 +14,8 @@ LL | impl MyTrait<u64> for Qqq{
    | ^^^^^^^^^^^^^^^^^^^^^^^^^
 help: try using a fully qualified path to specify the expected types
    |
-LL |     <Qqq as MyTrait<T>>::lol::<{closure@}>(&q, ||());
-   |     +++ ~
+LL |     <Qqq as MyTrait<T>>::lol::<_>(&q, ||());
+   |     +++++++++++++++++++++++++++++++ ~
 
 error: aborting due to 1 previous error
 
diff --git a/tests/ui/typeck/issue-91267.stderr b/tests/ui/typeck/issue-91267.stderr
index 7e48b251980..399309d0ec4 100644
--- a/tests/ui/typeck/issue-91267.stderr
+++ b/tests/ui/typeck/issue-91267.stderr
@@ -17,6 +17,8 @@ LL | fn main() {
    |          - expected `()` because of default return type
 LL |     type_ascribe!(0, u8<e<5>=e>)
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `()`, found `u8`
+   |
+   = note: this error originates in the macro `type_ascribe` (in Nightly builds, run with -Z macro-backtrace for more info)
 
 error: aborting due to 3 previous errors