about summary refs log tree commit diff
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2023-12-20 09:14:25 +0000
committerbors <bors@rust-lang.org>2023-12-20 09:14:25 +0000
commit3e4a15ea067e14da83ed5dedfb64cae7a30684e9 (patch)
tree32b9feaf5f7055716432e3ad64532cf5b56922bd
parent3095d31a759e569a9da3fe908541f301a211ea66 (diff)
parentd6656af16a47d7bd8b76d3b39da265c3587d8a12 (diff)
downloadrust-3e4a15ea067e14da83ed5dedfb64cae7a30684e9.tar.gz
rust-3e4a15ea067e14da83ed5dedfb64cae7a30684e9.zip
Auto merge of #119156 - matthiaskrgr:rollup-482ow65, r=matthiaskrgr
Rollup of 7 pull requests

Successful merges:

 - #118691 (Add check for possible CStr literals in pre-2021)
 - #118973 (rustc_codegen_ssa: Don't drop `IncorrectCguReuseType` , make `rustc_expected_cgu_reuse` attr work)
 - #119071 (-Znext-solver: adapt overflow rules to avoid breakage)
 - #119089 (effects: fix a comment)
 - #119094 (Add function ABI and type layout to StableMIR)
 - #119102 (Add arm-none-eabi and armv7r-none-eabi platform-support documentation.)
 - #119107 (subtype_predicate: remove unnecessary probe)

Failed merges:

 - #119135 (Fix crash due to `CrateItem::kind()` not handling constructors)
 - #119141 (Add method to get instance instantiation arguments)

r? `@ghost`
`@rustbot` modify labels: rollup
-rw-r--r--compiler/rustc_codegen_ssa/src/assert_module_sources.rs4
-rw-r--r--compiler/rustc_hir_analysis/src/astconv/generics.rs2
-rw-r--r--compiler/rustc_infer/src/infer/mod.rs15
-rw-r--r--compiler/rustc_middle/src/traits/solve.rs21
-rw-r--r--compiler/rustc_middle/src/traits/solve/inspect.rs6
-rw-r--r--compiler/rustc_middle/src/traits/solve/inspect/format.rs8
-rw-r--r--compiler/rustc_parse/src/parser/diagnostics.rs36
-rw-r--r--compiler/rustc_smir/src/rustc_internal/internal.rs9
-rw-r--r--compiler/rustc_smir/src/rustc_internal/mod.rs6
-rw-r--r--compiler/rustc_smir/src/rustc_smir/context.rs75
-rw-r--r--compiler/rustc_smir/src/rustc_smir/convert/abi.rs242
-rw-r--r--compiler/rustc_smir/src/rustc_smir/convert/mod.rs20
-rw-r--r--compiler/rustc_smir/src/rustc_smir/mod.rs13
-rw-r--r--compiler/rustc_trait_selection/src/solve/alias_relate.rs16
-rw-r--r--compiler/rustc_trait_selection/src/solve/assembly/mod.rs23
-rw-r--r--compiler/rustc_trait_selection/src/solve/eval_ctxt/canonical.rs14
-rw-r--r--compiler/rustc_trait_selection/src/solve/eval_ctxt/mod.rs91
-rw-r--r--compiler/rustc_trait_selection/src/solve/inspect/analyse.rs2
-rw-r--r--compiler/rustc_trait_selection/src/solve/inspect/build.rs16
-rw-r--r--compiler/rustc_trait_selection/src/solve/mod.rs22
-rw-r--r--compiler/rustc_trait_selection/src/solve/normalizes_to/inherent.rs10
-rw-r--r--compiler/rustc_trait_selection/src/solve/normalizes_to/mod.rs21
-rw-r--r--compiler/rustc_trait_selection/src/solve/normalizes_to/weak_types.rs5
-rw-r--r--compiler/rustc_trait_selection/src/solve/project_goals.rs7
-rw-r--r--compiler/rustc_trait_selection/src/solve/search_graph.rs10
-rw-r--r--compiler/rustc_trait_selection/src/solve/trait_goals.rs66
-rw-r--r--compiler/stable_mir/src/abi.rs283
-rw-r--r--compiler/stable_mir/src/compiler_interface.rs10
-rw-r--r--compiler/stable_mir/src/lib.rs1
-rw-r--r--compiler/stable_mir/src/mir/mono.rs6
-rw-r--r--compiler/stable_mir/src/ty.rs6
-rw-r--r--src/doc/rustc/src/SUMMARY.md2
-rw-r--r--src/doc/rustc/src/platform-support.md42
-rw-r--r--src/doc/rustc/src/platform-support/arm-none-eabi.md96
-rw-r--r--src/doc/rustc/src/platform-support/armv4t-none-eabi.md45
-rw-r--r--src/doc/rustc/src/platform-support/armv5te-none-eabi.md50
-rw-r--r--src/doc/rustc/src/platform-support/armv7r-none-eabi.md47
-rw-r--r--tests/incremental/thinlto/cgu_invalidated_via_import.rs4
-rw-r--r--tests/incremental/thinlto/cgu_keeps_identical_fn.rs12
-rw-r--r--tests/incremental/thinlto/independent_cgus_dont_affect_each_other.rs8
-rw-r--r--tests/ui-fulldeps/stable-mir/check_abi.rs143
-rw-r--r--tests/ui-fulldeps/stable-mir/check_allocation.rs1
-rw-r--r--tests/ui-fulldeps/stable-mir/check_defs.rs6
-rw-r--r--tests/ui/editions/edition-cstr-2015-2018.rs62
-rw-r--r--tests/ui/editions/edition-cstr-2015-2018.stderr67
-rw-r--r--tests/ui/traits/issue-90662-projection-caching.rs10
-rw-r--r--tests/ui/traits/next-solver/overflow/recursion-limit-normalizes-to-constraints.rs25
47 files changed, 1419 insertions, 267 deletions
diff --git a/compiler/rustc_codegen_ssa/src/assert_module_sources.rs b/compiler/rustc_codegen_ssa/src/assert_module_sources.rs
index 01d1b1059b9..a5bd10ecb34 100644
--- a/compiler/rustc_codegen_ssa/src/assert_module_sources.rs
+++ b/compiler/rustc_codegen_ssa/src/assert_module_sources.rs
@@ -278,13 +278,13 @@ impl CguReuseTracker {
 
                     if error {
                         let at_least = if at_least { 1 } else { 0 };
-                        errors::IncorrectCguReuseType {
+                        sess.emit_err(errors::IncorrectCguReuseType {
                             span: *error_span,
                             cgu_user_name,
                             actual_reuse,
                             expected_reuse,
                             at_least,
-                        };
+                        });
                     }
                 } else {
                     sess.emit_fatal(errors::CguNotRecorded { cgu_user_name, cgu_name });
diff --git a/compiler/rustc_hir_analysis/src/astconv/generics.rs b/compiler/rustc_hir_analysis/src/astconv/generics.rs
index be73c027fdc..b495b00ec70 100644
--- a/compiler/rustc_hir_analysis/src/astconv/generics.rs
+++ b/compiler/rustc_hir_analysis/src/astconv/generics.rs
@@ -262,7 +262,7 @@ pub fn create_args_for_parent_generic_args<'tcx, 'a>(
                             // impl const PartialEq for () {}
                             // ```
                             //
-                            // Since this is a const impl, we need to insert `<false>` at the end of
+                            // Since this is a const impl, we need to insert a host arg at the end of
                             // `PartialEq`'s generics, but this errors since `Rhs` isn't specified.
                             // To work around this, we infer all arguments until we reach the host param.
                             args.push(ctx.inferred_kind(Some(&args), param, infer_args));
diff --git a/compiler/rustc_infer/src/infer/mod.rs b/compiler/rustc_infer/src/infer/mod.rs
index 3de269da22d..e092bbbfdd6 100644
--- a/compiler/rustc_infer/src/infer/mod.rs
+++ b/compiler/rustc_infer/src/infer/mod.rs
@@ -713,10 +713,6 @@ impl<'tcx> InferCtxtBuilder<'tcx> {
 }
 
 impl<'tcx, T> InferOk<'tcx, T> {
-    pub fn unit(self) -> InferOk<'tcx, ()> {
-        InferOk { value: (), obligations: self.obligations }
-    }
-
     /// Extracts `value`, registering any obligations into `fulfill_cx`.
     pub fn into_value_registering_obligations(
         self,
@@ -1025,15 +1021,10 @@ impl<'tcx> InferCtxt<'tcx> {
             _ => {}
         }
 
-        Ok(self.commit_if_ok(|_snapshot| {
-            let ty::SubtypePredicate { a_is_expected, a, b } =
-                self.instantiate_binder_with_placeholders(predicate);
-
-            let ok =
-                self.at(cause, param_env).sub_exp(DefineOpaqueTypes::No, a_is_expected, a, b)?;
+        let ty::SubtypePredicate { a_is_expected, a, b } =
+            self.instantiate_binder_with_placeholders(predicate);
 
-            Ok(ok.unit())
-        }))
+        Ok(self.at(cause, param_env).sub_exp(DefineOpaqueTypes::No, a_is_expected, a, b))
     }
 
     pub fn region_outlives_predicate(
diff --git a/compiler/rustc_middle/src/traits/solve.rs b/compiler/rustc_middle/src/traits/solve.rs
index 27a1e64a78b..048df367bd6 100644
--- a/compiler/rustc_middle/src/traits/solve.rs
+++ b/compiler/rustc_middle/src/traits/solve.rs
@@ -233,6 +233,27 @@ impl<'tcx> TypeVisitable<TyCtxt<'tcx>> for PredefinedOpaques<'tcx> {
     }
 }
 
+/// Why a specific goal has to be proven.
+///
+/// This is necessary as we treat nested goals different depending on
+/// their source.
+#[derive(Copy, Clone, Debug, PartialEq, Eq)]
+pub enum GoalSource {
+    Misc,
+    /// We're proving a where-bound of an impl.
+    ///
+    /// FIXME(-Znext-solver=coinductive): Explain how and why this
+    /// changes whether cycles are coinductive.
+    ///
+    /// This also impacts whether we erase constraints on overflow.
+    /// Erasing constraints is generally very useful for perf and also
+    /// results in better error messages by avoiding spurious errors.
+    /// We do not erase overflow constraints in `normalizes-to` goals unless
+    /// they are from an impl where-clause. This is necessary due to
+    /// backwards compatability, cc trait-system-refactor-initiatitive#70.
+    ImplWhereBound,
+}
+
 #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash, HashStable)]
 pub enum IsNormalizesToHack {
     Yes,
diff --git a/compiler/rustc_middle/src/traits/solve/inspect.rs b/compiler/rustc_middle/src/traits/solve/inspect.rs
index 7883cd338be..77d112d0afc 100644
--- a/compiler/rustc_middle/src/traits/solve/inspect.rs
+++ b/compiler/rustc_middle/src/traits/solve/inspect.rs
@@ -19,8 +19,8 @@
 //! [canonicalized]: https://rustc-dev-guide.rust-lang.org/solve/canonicalization.html
 
 use super::{
-    CandidateSource, Canonical, CanonicalInput, Certainty, Goal, IsNormalizesToHack, NoSolution,
-    QueryInput, QueryResult,
+    CandidateSource, Canonical, CanonicalInput, Certainty, Goal, GoalSource, IsNormalizesToHack,
+    NoSolution, QueryInput, QueryResult,
 };
 use crate::{infer::canonical::CanonicalVarValues, ty};
 use format::ProofTreeFormatter;
@@ -115,7 +115,7 @@ impl Debug for Probe<'_> {
 pub enum ProbeStep<'tcx> {
     /// We added a goal to the `EvalCtxt` which will get proven
     /// the next time `EvalCtxt::try_evaluate_added_goals` is called.
-    AddGoal(CanonicalState<'tcx, Goal<'tcx, ty::Predicate<'tcx>>>),
+    AddGoal(GoalSource, CanonicalState<'tcx, Goal<'tcx, ty::Predicate<'tcx>>>),
     /// The inside of a `EvalCtxt::try_evaluate_added_goals` call.
     EvaluateGoals(AddedGoalsEvaluation<'tcx>),
     /// A call to `probe` while proving the current goal. This is
diff --git a/compiler/rustc_middle/src/traits/solve/inspect/format.rs b/compiler/rustc_middle/src/traits/solve/inspect/format.rs
index ab9e0283918..4e2207ed523 100644
--- a/compiler/rustc_middle/src/traits/solve/inspect/format.rs
+++ b/compiler/rustc_middle/src/traits/solve/inspect/format.rs
@@ -123,7 +123,13 @@ impl<'a, 'b> ProofTreeFormatter<'a, 'b> {
         self.nested(|this| {
             for step in &probe.steps {
                 match step {
-                    ProbeStep::AddGoal(goal) => writeln!(this.f, "ADDED GOAL: {goal:?}")?,
+                    ProbeStep::AddGoal(source, goal) => {
+                        let source = match source {
+                            GoalSource::Misc => "misc",
+                            GoalSource::ImplWhereBound => "impl where-bound",
+                        };
+                        writeln!(this.f, "ADDED GOAL ({source}): {goal:?}")?
+                    }
                     ProbeStep::EvaluateGoals(eval) => this.format_added_goals_evaluation(eval)?,
                     ProbeStep::NestedProbe(probe) => this.format_probe(probe)?,
                     ProbeStep::CommitIfOkStart => writeln!(this.f, "COMMIT_IF_OK START")?,
diff --git a/compiler/rustc_parse/src/parser/diagnostics.rs b/compiler/rustc_parse/src/parser/diagnostics.rs
index 9e3637ea9f3..c077e0a83a1 100644
--- a/compiler/rustc_parse/src/parser/diagnostics.rs
+++ b/compiler/rustc_parse/src/parser/diagnostics.rs
@@ -10,13 +10,13 @@ use crate::errors::{
     ConstGenericWithoutBracesSugg, DocCommentDoesNotDocumentAnything, DocCommentOnParamType,
     DoubleColonInBound, ExpectedIdentifier, ExpectedSemi, ExpectedSemiSugg,
     GenericParamsWithoutAngleBrackets, GenericParamsWithoutAngleBracketsSugg,
-    HelpIdentifierStartsWithNumber, InInTypo, IncorrectAwait, IncorrectSemicolon,
-    IncorrectUseOfAwait, PatternMethodParamWithoutBody, QuestionMarkInType, QuestionMarkInTypeSugg,
-    SelfParamNotFirst, StructLiteralBodyWithoutPath, StructLiteralBodyWithoutPathSugg,
-    StructLiteralNeedingParens, StructLiteralNeedingParensSugg, SuggAddMissingLetStmt,
-    SuggEscapeIdentifier, SuggRemoveComma, TernaryOperator, UnexpectedConstInGenericParam,
-    UnexpectedConstParamDeclaration, UnexpectedConstParamDeclarationSugg, UnmatchedAngleBrackets,
-    UseEqInstead, WrapType,
+    HelpIdentifierStartsWithNumber, HelpUseLatestEdition, InInTypo, IncorrectAwait,
+    IncorrectSemicolon, IncorrectUseOfAwait, PatternMethodParamWithoutBody, QuestionMarkInType,
+    QuestionMarkInTypeSugg, SelfParamNotFirst, StructLiteralBodyWithoutPath,
+    StructLiteralBodyWithoutPathSugg, StructLiteralNeedingParens, StructLiteralNeedingParensSugg,
+    SuggAddMissingLetStmt, SuggEscapeIdentifier, SuggRemoveComma, TernaryOperator,
+    UnexpectedConstInGenericParam, UnexpectedConstParamDeclaration,
+    UnexpectedConstParamDeclarationSugg, UnmatchedAngleBrackets, UseEqInstead, WrapType,
 };
 use crate::fluent_generated as fluent;
 use crate::parser;
@@ -640,6 +640,28 @@ impl<'a> Parser<'a> {
             }
         }
 
+        // Try to detect an intended c-string literal while using a pre-2021 edition. The heuristic
+        // here is to identify a cooked, uninterpolated `c` id immediately followed by a string, or
+        // a cooked, uninterpolated `cr` id immediately followed by a string or a `#`, in an edition
+        // where c-string literals are not allowed. There is the very slight possibility of a false
+        // positive for a `cr#` that wasn't intended to start a c-string literal, but identifying
+        // that in the parser requires unbounded lookahead, so we only add a hint to the existing
+        // error rather than replacing it entirely.
+        if ((self.prev_token.kind == TokenKind::Ident(sym::c, false)
+            && matches!(&self.token.kind, TokenKind::Literal(token::Lit { kind: token::Str, .. })))
+            || (self.prev_token.kind == TokenKind::Ident(sym::cr, false)
+                && matches!(
+                    &self.token.kind,
+                    TokenKind::Literal(token::Lit { kind: token::Str, .. }) | token::Pound
+                )))
+            && self.prev_token.span.hi() == self.token.span.lo()
+            && !self.token.span.at_least_rust_2021()
+        {
+            err.note("you may be trying to write a c-string literal");
+            err.note("c-string literals require Rust 2021 or later");
+            HelpUseLatestEdition::new().add_to_diagnostic(&mut err);
+        }
+
         // `pub` may be used for an item or `pub(crate)`
         if self.prev_token.is_ident_named(sym::public)
             && (self.token.can_begin_item()
diff --git a/compiler/rustc_smir/src/rustc_internal/internal.rs b/compiler/rustc_smir/src/rustc_internal/internal.rs
index 63207200353..bbc98af45c0 100644
--- a/compiler/rustc_smir/src/rustc_internal/internal.rs
+++ b/compiler/rustc_smir/src/rustc_internal/internal.rs
@@ -7,6 +7,7 @@
 use crate::rustc_smir::Tables;
 use rustc_middle::ty::{self as rustc_ty, Ty as InternalTy};
 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};
@@ -460,6 +461,14 @@ impl<'tcx> RustcInternal<'tcx> for Span {
     }
 }
 
+impl<'tcx> RustcInternal<'tcx> for Layout {
+    type T = rustc_target::abi::Layout<'tcx>;
+
+    fn internal(&self, tables: &mut Tables<'tcx>) -> Self::T {
+        tables.layouts[*self]
+    }
+}
+
 impl<'tcx, T> RustcInternal<'tcx> for &T
 where
     T: RustcInternal<'tcx>,
diff --git a/compiler/rustc_smir/src/rustc_internal/mod.rs b/compiler/rustc_smir/src/rustc_internal/mod.rs
index c3db9b358e8..4bac98909ad 100644
--- a/compiler/rustc_smir/src/rustc_internal/mod.rs
+++ b/compiler/rustc_smir/src/rustc_internal/mod.rs
@@ -12,6 +12,7 @@ use rustc_middle::ty::TyCtxt;
 use rustc_span::def_id::{CrateNum, DefId};
 use rustc_span::Span;
 use scoped_tls::scoped_thread_local;
+use stable_mir::abi::Layout;
 use stable_mir::ty::IndexedVal;
 use stable_mir::Error;
 use std::cell::Cell;
@@ -136,6 +137,10 @@ impl<'tcx> Tables<'tcx> {
     pub(crate) fn static_def(&mut self, did: DefId) -> stable_mir::mir::mono::StaticDef {
         stable_mir::mir::mono::StaticDef(self.create_def_id(did))
     }
+
+    pub(crate) fn layout_id(&mut self, layout: rustc_target::abi::Layout<'tcx>) -> Layout {
+        self.layouts.create_or_fetch(layout)
+    }
 }
 
 pub fn crate_num(item: &stable_mir::Crate) -> CrateNum {
@@ -180,6 +185,7 @@ where
         types: IndexMap::default(),
         instances: IndexMap::default(),
         constants: IndexMap::default(),
+        layouts: IndexMap::default(),
     }));
     stable_mir::compiler_interface::run(&tables, || init(&tables, f))
 }
diff --git a/compiler/rustc_smir/src/rustc_smir/context.rs b/compiler/rustc_smir/src/rustc_smir/context.rs
index 2361a04a6d7..621766c695e 100644
--- a/compiler/rustc_smir/src/rustc_smir/context.rs
+++ b/compiler/rustc_smir/src/rustc_smir/context.rs
@@ -3,12 +3,19 @@
 //! This trait is currently the main interface between the Rust compiler,
 //! and the `stable_mir` crate.
 
+#![allow(rustc::usage_of_qualified_ty)]
+
+use rustc_abi::HasDataLayout;
 use rustc_middle::ty;
+use rustc_middle::ty::layout::{
+    FnAbiOf, FnAbiOfHelpers, HasParamEnv, HasTyCtxt, LayoutOf, LayoutOfHelpers,
+};
 use rustc_middle::ty::print::{with_forced_trimmed_paths, with_no_trimmed_paths};
 use rustc_middle::ty::{
-    GenericPredicates, Instance, ParamEnv, ScalarInt, TypeVisitableExt, ValTree,
+    GenericPredicates, Instance, List, ParamEnv, ScalarInt, TyCtxt, TypeVisitableExt, ValTree,
 };
 use rustc_span::def_id::LOCAL_CRATE;
+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};
@@ -280,7 +287,6 @@ impl<'tcx> Context for TablesWrapper<'tcx> {
         tables.tcx.mk_ty_from_kind(internal_kind).stable(&mut *tables)
     }
 
-    #[allow(rustc::usage_of_qualified_ty)]
     fn new_box_ty(&self, ty: stable_mir::ty::Ty) -> stable_mir::ty::Ty {
         let mut tables = self.0.borrow_mut();
         let inner = ty.internal(&mut *tables);
@@ -335,6 +341,12 @@ impl<'tcx> Context for TablesWrapper<'tcx> {
         instance.ty(tables.tcx, ParamEnv::reveal_all()).stable(&mut *tables)
     }
 
+    fn instance_abi(&self, def: InstanceDef) -> Result<FnAbi, Error> {
+        let mut tables = self.0.borrow_mut();
+        let instance = tables.instances[def];
+        Ok(tables.fn_abi_of_instance(instance, List::empty())?.stable(&mut *tables))
+    }
+
     fn instance_def_id(&self, def: InstanceDef) -> stable_mir::DefId {
         let mut tables = self.0.borrow_mut();
         let def_id = tables.instances[def].def_id();
@@ -473,6 +485,65 @@ impl<'tcx> Context for TablesWrapper<'tcx> {
             )
         }
     }
+
+    fn ty_layout(&self, ty: Ty) -> Result<Layout, Error> {
+        let mut tables = self.0.borrow_mut();
+        let ty = ty.internal(&mut *tables);
+        let layout = tables.layout_of(ty)?.layout;
+        Ok(layout.stable(&mut *tables))
+    }
+
+    fn layout_shape(&self, id: Layout) -> LayoutShape {
+        let mut tables = self.0.borrow_mut();
+        id.internal(&mut *tables).0.stable(&mut *tables)
+    }
 }
 
 pub struct TablesWrapper<'tcx>(pub RefCell<Tables<'tcx>>);
+
+/// Implement error handling for extracting function ABI information.
+impl<'tcx> FnAbiOfHelpers<'tcx> for Tables<'tcx> {
+    type FnAbiOfResult = Result<&'tcx rustc_target::abi::call::FnAbi<'tcx, ty::Ty<'tcx>>, Error>;
+
+    #[inline]
+    fn handle_fn_abi_err(
+        &self,
+        err: ty::layout::FnAbiError<'tcx>,
+        _span: rustc_span::Span,
+        fn_abi_request: ty::layout::FnAbiRequest<'tcx>,
+    ) -> Error {
+        Error::new(format!("Failed to get ABI for `{fn_abi_request:?}`: {err:?}"))
+    }
+}
+
+impl<'tcx> LayoutOfHelpers<'tcx> for Tables<'tcx> {
+    type LayoutOfResult = Result<ty::layout::TyAndLayout<'tcx>, Error>;
+
+    #[inline]
+    fn handle_layout_err(
+        &self,
+        err: ty::layout::LayoutError<'tcx>,
+        _span: rustc_span::Span,
+        ty: ty::Ty<'tcx>,
+    ) -> Error {
+        Error::new(format!("Failed to get layout for `{ty}`: {err}"))
+    }
+}
+
+impl<'tcx> HasParamEnv<'tcx> for Tables<'tcx> {
+    fn param_env(&self) -> ty::ParamEnv<'tcx> {
+        ty::ParamEnv::reveal_all()
+    }
+}
+
+impl<'tcx> HasTyCtxt<'tcx> for Tables<'tcx> {
+    fn tcx(&self) -> TyCtxt<'tcx> {
+        self.tcx
+    }
+}
+
+impl<'tcx> HasDataLayout for Tables<'tcx> {
+    fn data_layout(&self) -> &rustc_abi::TargetDataLayout {
+        self.tcx.data_layout()
+    }
+}
diff --git a/compiler/rustc_smir/src/rustc_smir/convert/abi.rs b/compiler/rustc_smir/src/rustc_smir/convert/abi.rs
new file mode 100644
index 00000000000..632e97b32f5
--- /dev/null
+++ b/compiler/rustc_smir/src/rustc_smir/convert/abi.rs
@@ -0,0 +1,242 @@
+//! Conversion of internal Rust compiler `rustc_target::abi` and `rustc_abi` items to stable ones.
+
+#![allow(rustc::usage_of_qualified_ty)]
+
+use crate::rustc_smir::{Stable, Tables};
+use rustc_middle::ty;
+use rustc_target::abi::call::Conv;
+use stable_mir::abi::{
+    ArgAbi, CallConvention, FieldsShape, FnAbi, Layout, LayoutShape, PassMode, TagEncoding,
+    TyAndLayout, ValueAbi, VariantsShape,
+};
+use stable_mir::ty::{Align, IndexedVal, Size, VariantIdx};
+use stable_mir::{opaque, Opaque};
+
+impl<'tcx> Stable<'tcx> for rustc_target::abi::VariantIdx {
+    type T = VariantIdx;
+    fn stable(&self, _: &mut Tables<'tcx>) -> Self::T {
+        VariantIdx::to_val(self.as_usize())
+    }
+}
+
+impl<'tcx> Stable<'tcx> for rustc_abi::Endian {
+    type T = stable_mir::target::Endian;
+
+    fn stable(&self, _tables: &mut Tables<'tcx>) -> Self::T {
+        match self {
+            rustc_abi::Endian::Little => stable_mir::target::Endian::Little,
+            rustc_abi::Endian::Big => stable_mir::target::Endian::Big,
+        }
+    }
+}
+
+impl<'tcx> Stable<'tcx> for rustc_target::abi::TyAndLayout<'tcx, ty::Ty<'tcx>> {
+    type T = TyAndLayout;
+
+    fn stable(&self, tables: &mut Tables<'tcx>) -> Self::T {
+        TyAndLayout { ty: self.ty.stable(tables), layout: self.layout.stable(tables) }
+    }
+}
+
+impl<'tcx> Stable<'tcx> for rustc_target::abi::Layout<'tcx> {
+    type T = Layout;
+
+    fn stable(&self, tables: &mut Tables<'tcx>) -> Self::T {
+        tables.layout_id(*self)
+    }
+}
+
+impl<'tcx> Stable<'tcx>
+    for rustc_abi::LayoutS<rustc_target::abi::FieldIdx, rustc_target::abi::VariantIdx>
+{
+    type T = LayoutShape;
+
+    fn stable(&self, tables: &mut Tables<'tcx>) -> Self::T {
+        LayoutShape {
+            fields: self.fields.stable(tables),
+            variants: self.variants.stable(tables),
+            abi: self.abi.stable(tables),
+            abi_align: self.align.abi.stable(tables),
+            size: self.size.stable(tables),
+        }
+    }
+}
+
+impl<'tcx> Stable<'tcx> for rustc_target::abi::call::FnAbi<'tcx, ty::Ty<'tcx>> {
+    type T = FnAbi;
+
+    fn stable(&self, tables: &mut Tables<'tcx>) -> Self::T {
+        assert!(self.args.len() >= self.fixed_count as usize);
+        assert!(!self.c_variadic || matches!(self.conv, Conv::C));
+        FnAbi {
+            args: self.args.as_ref().stable(tables),
+            ret: self.ret.stable(tables),
+            fixed_count: self.fixed_count,
+            conv: self.conv.stable(tables),
+            c_variadic: self.c_variadic,
+        }
+    }
+}
+
+impl<'tcx> Stable<'tcx> for rustc_target::abi::call::ArgAbi<'tcx, ty::Ty<'tcx>> {
+    type T = ArgAbi;
+
+    fn stable(&self, tables: &mut Tables<'tcx>) -> Self::T {
+        ArgAbi {
+            ty: self.layout.ty.stable(tables),
+            layout: self.layout.layout.stable(tables),
+            mode: self.mode.stable(tables),
+        }
+    }
+}
+
+impl<'tcx> Stable<'tcx> for rustc_target::abi::call::Conv {
+    type T = CallConvention;
+
+    fn stable(&self, _tables: &mut Tables<'tcx>) -> Self::T {
+        match self {
+            Conv::C => CallConvention::C,
+            Conv::Rust => CallConvention::Rust,
+            Conv::Cold => CallConvention::Cold,
+            Conv::PreserveMost => CallConvention::PreserveMost,
+            Conv::PreserveAll => CallConvention::PreserveAll,
+            Conv::ArmAapcs => CallConvention::ArmAapcs,
+            Conv::CCmseNonSecureCall => CallConvention::CCmseNonSecureCall,
+            Conv::Msp430Intr => CallConvention::Msp430Intr,
+            Conv::PtxKernel => CallConvention::PtxKernel,
+            Conv::X86Fastcall => CallConvention::X86Fastcall,
+            Conv::X86Intr => CallConvention::X86Intr,
+            Conv::X86Stdcall => CallConvention::X86Stdcall,
+            Conv::X86ThisCall => CallConvention::X86ThisCall,
+            Conv::X86VectorCall => CallConvention::X86VectorCall,
+            Conv::X86_64SysV => CallConvention::X86_64SysV,
+            Conv::X86_64Win64 => CallConvention::X86_64Win64,
+            Conv::AmdGpuKernel => CallConvention::AmdGpuKernel,
+            Conv::AvrInterrupt => CallConvention::AvrInterrupt,
+            Conv::AvrNonBlockingInterrupt => CallConvention::AvrNonBlockingInterrupt,
+            Conv::RiscvInterrupt { .. } => CallConvention::RiscvInterrupt,
+        }
+    }
+}
+
+impl<'tcx> Stable<'tcx> for rustc_target::abi::call::PassMode {
+    type T = PassMode;
+
+    fn stable(&self, _tables: &mut Tables<'tcx>) -> Self::T {
+        match self {
+            rustc_target::abi::call::PassMode::Ignore => PassMode::Ignore,
+            rustc_target::abi::call::PassMode::Direct(attr) => PassMode::Direct(opaque(attr)),
+            rustc_target::abi::call::PassMode::Pair(first, second) => {
+                PassMode::Pair(opaque(first), opaque(second))
+            }
+            rustc_target::abi::call::PassMode::Cast { pad_i32, cast } => {
+                PassMode::Cast { pad_i32: *pad_i32, cast: opaque(cast) }
+            }
+            rustc_target::abi::call::PassMode::Indirect { attrs, meta_attrs, on_stack } => {
+                PassMode::Indirect {
+                    attrs: opaque(attrs),
+                    meta_attrs: opaque(meta_attrs),
+                    on_stack: *on_stack,
+                }
+            }
+        }
+    }
+}
+
+impl<'tcx> Stable<'tcx> for rustc_abi::FieldsShape<rustc_target::abi::FieldIdx> {
+    type T = FieldsShape;
+
+    fn stable(&self, tables: &mut Tables<'tcx>) -> Self::T {
+        match self {
+            rustc_abi::FieldsShape::Primitive => FieldsShape::Primitive,
+            rustc_abi::FieldsShape::Union(count) => FieldsShape::Union(*count),
+            rustc_abi::FieldsShape::Array { stride, count } => {
+                FieldsShape::Array { stride: stride.stable(tables), count: *count }
+            }
+            rustc_abi::FieldsShape::Arbitrary { offsets, .. } => {
+                FieldsShape::Arbitrary { offsets: offsets.iter().as_slice().stable(tables) }
+            }
+        }
+    }
+}
+
+impl<'tcx> Stable<'tcx>
+    for rustc_abi::Variants<rustc_target::abi::FieldIdx, rustc_target::abi::VariantIdx>
+{
+    type T = VariantsShape;
+
+    fn stable(&self, tables: &mut Tables<'tcx>) -> Self::T {
+        match self {
+            rustc_abi::Variants::Single { index } => {
+                VariantsShape::Single { index: index.stable(tables) }
+            }
+            rustc_abi::Variants::Multiple { tag, tag_encoding, tag_field, variants } => {
+                VariantsShape::Multiple {
+                    tag: tag.stable(tables),
+                    tag_encoding: tag_encoding.stable(tables),
+                    tag_field: *tag_field,
+                    variants: variants.iter().as_slice().stable(tables),
+                }
+            }
+        }
+    }
+}
+
+impl<'tcx> Stable<'tcx> for rustc_abi::TagEncoding<rustc_target::abi::VariantIdx> {
+    type T = TagEncoding;
+
+    fn stable(&self, tables: &mut Tables<'tcx>) -> Self::T {
+        match self {
+            rustc_abi::TagEncoding::Direct => TagEncoding::Direct,
+            rustc_abi::TagEncoding::Niche { untagged_variant, niche_variants, niche_start } => {
+                TagEncoding::Niche {
+                    untagged_variant: untagged_variant.stable(tables),
+                    niche_variants: niche_variants.stable(tables),
+                    niche_start: *niche_start,
+                }
+            }
+        }
+    }
+}
+
+impl<'tcx> Stable<'tcx> for rustc_abi::Abi {
+    type T = ValueAbi;
+
+    fn stable(&self, tables: &mut Tables<'tcx>) -> Self::T {
+        match *self {
+            rustc_abi::Abi::Uninhabited => ValueAbi::Uninhabited,
+            rustc_abi::Abi::Scalar(scalar) => ValueAbi::Scalar(scalar.stable(tables)),
+            rustc_abi::Abi::ScalarPair(first, second) => {
+                ValueAbi::ScalarPair(first.stable(tables), second.stable(tables))
+            }
+            rustc_abi::Abi::Vector { element, count } => {
+                ValueAbi::Vector { element: element.stable(tables), count }
+            }
+            rustc_abi::Abi::Aggregate { sized } => ValueAbi::Aggregate { sized },
+        }
+    }
+}
+
+impl<'tcx> Stable<'tcx> for rustc_abi::Size {
+    type T = Size;
+
+    fn stable(&self, _tables: &mut Tables<'tcx>) -> Self::T {
+        self.bytes_usize()
+    }
+}
+
+impl<'tcx> Stable<'tcx> for rustc_abi::Align {
+    type T = Align;
+
+    fn stable(&self, _tables: &mut Tables<'tcx>) -> Self::T {
+        self.bytes()
+    }
+}
+
+impl<'tcx> Stable<'tcx> for rustc_abi::Scalar {
+    type T = Opaque;
+
+    fn stable(&self, _tables: &mut Tables<'tcx>) -> Self::T {
+        opaque(self)
+    }
+}
diff --git a/compiler/rustc_smir/src/rustc_smir/convert/mod.rs b/compiler/rustc_smir/src/rustc_smir/convert/mod.rs
index 7021bdda735..8b7b26f969c 100644
--- a/compiler/rustc_smir/src/rustc_smir/convert/mod.rs
+++ b/compiler/rustc_smir/src/rustc_smir/convert/mod.rs
@@ -1,10 +1,10 @@
 //! Conversion of internal Rust compiler items to stable ones.
 
 use rustc_target::abi::FieldIdx;
-use stable_mir::ty::{IndexedVal, VariantIdx};
 
 use crate::rustc_smir::{Stable, Tables};
 
+mod abi;
 mod error;
 mod mir;
 mod ty;
@@ -26,13 +26,6 @@ impl<'tcx> Stable<'tcx> for FieldIdx {
     }
 }
 
-impl<'tcx> Stable<'tcx> for rustc_target::abi::VariantIdx {
-    type T = VariantIdx;
-    fn stable(&self, _: &mut Tables<'tcx>) -> Self::T {
-        VariantIdx::to_val(self.as_usize())
-    }
-}
-
 impl<'tcx> Stable<'tcx> for rustc_hir::CoroutineSource {
     type T = stable_mir::mir::CoroutineSource;
     fn stable(&self, _: &mut Tables<'tcx>) -> Self::T {
@@ -79,14 +72,3 @@ impl<'tcx> Stable<'tcx> for rustc_span::Span {
         tables.create_span(*self)
     }
 }
-
-impl<'tcx> Stable<'tcx> for rustc_abi::Endian {
-    type T = stable_mir::target::Endian;
-
-    fn stable(&self, _tables: &mut Tables<'tcx>) -> Self::T {
-        match self {
-            rustc_abi::Endian::Little => stable_mir::target::Endian::Little,
-            rustc_abi::Endian::Big => stable_mir::target::Endian::Big,
-        }
-    }
-}
diff --git a/compiler/rustc_smir/src/rustc_smir/mod.rs b/compiler/rustc_smir/src/rustc_smir/mod.rs
index ae6cf3fe3e8..cf6ac5285c2 100644
--- a/compiler/rustc_smir/src/rustc_smir/mod.rs
+++ b/compiler/rustc_smir/src/rustc_smir/mod.rs
@@ -12,9 +12,11 @@ use rustc_middle::mir;
 use rustc_middle::mir::interpret::AllocId;
 use rustc_middle::ty::{self, Instance, Ty, TyCtxt};
 use rustc_span::def_id::{CrateNum, DefId, LOCAL_CRATE};
+use stable_mir::abi::Layout;
 use stable_mir::mir::mono::InstanceDef;
 use stable_mir::ty::{ConstId, Span};
 use stable_mir::ItemKind;
+use std::ops::RangeInclusive;
 use tracing::debug;
 
 use crate::rustc_internal::IndexMap;
@@ -32,6 +34,7 @@ pub struct Tables<'tcx> {
     pub(crate) types: IndexMap<Ty<'tcx>, stable_mir::ty::Ty>,
     pub(crate) instances: IndexMap<ty::Instance<'tcx>, InstanceDef>,
     pub(crate) constants: IndexMap<mir::Const<'tcx>, ConstId>,
+    pub(crate) layouts: IndexMap<rustc_target::abi::Layout<'tcx>, Layout>,
 }
 
 impl<'tcx> Tables<'tcx> {
@@ -162,3 +165,13 @@ where
         (self.0.stable(tables), self.1.stable(tables))
     }
 }
+
+impl<'tcx, T> Stable<'tcx> for RangeInclusive<T>
+where
+    T: Stable<'tcx>,
+{
+    type T = RangeInclusive<T::T>;
+    fn stable(&self, tables: &mut Tables<'tcx>) -> Self::T {
+        RangeInclusive::new(self.start().stable(tables), self.end().stable(tables))
+    }
+}
diff --git a/compiler/rustc_trait_selection/src/solve/alias_relate.rs b/compiler/rustc_trait_selection/src/solve/alias_relate.rs
index 2e99854ddc6..626569fb40f 100644
--- a/compiler/rustc_trait_selection/src/solve/alias_relate.rs
+++ b/compiler/rustc_trait_selection/src/solve/alias_relate.rs
@@ -11,7 +11,7 @@
 //! * bidirectional-normalizes-to: If `A` and `B` are both projections, and both
 //!   may apply, then we can compute the "intersection" of both normalizes-to by
 //!   performing them together. This is used specifically to resolve ambiguities.
-use super::EvalCtxt;
+use super::{EvalCtxt, GoalSource};
 use rustc_infer::infer::DefineOpaqueTypes;
 use rustc_infer::traits::query::NoSolution;
 use rustc_middle::traits::solve::{Certainty, Goal, QueryResult};
@@ -89,11 +89,10 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
             ty::TermKind::Const(_) => {
                 if let Some(alias) = term.to_alias_ty(self.tcx()) {
                     let term = self.next_term_infer_of_kind(term);
-                    self.add_goal(Goal::new(
-                        self.tcx(),
-                        param_env,
-                        ty::NormalizesTo { alias, term },
-                    ));
+                    self.add_goal(
+                        GoalSource::Misc,
+                        Goal::new(self.tcx(), param_env, ty::NormalizesTo { alias, term }),
+                    );
                     self.try_evaluate_added_goals()?;
                     Ok(Some(self.resolve_vars_if_possible(term)))
                 } else {
@@ -109,7 +108,10 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
         opaque: ty::AliasTy<'tcx>,
         term: ty::Term<'tcx>,
     ) -> QueryResult<'tcx> {
-        self.add_goal(Goal::new(self.tcx(), param_env, ty::NormalizesTo { alias: opaque, term }));
+        self.add_goal(
+            GoalSource::Misc,
+            Goal::new(self.tcx(), param_env, ty::NormalizesTo { alias: opaque, term }),
+        );
         self.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
     }
 
diff --git a/compiler/rustc_trait_selection/src/solve/assembly/mod.rs b/compiler/rustc_trait_selection/src/solve/assembly/mod.rs
index 62d62bdfd11..81a766f24b0 100644
--- a/compiler/rustc_trait_selection/src/solve/assembly/mod.rs
+++ b/compiler/rustc_trait_selection/src/solve/assembly/mod.rs
@@ -1,6 +1,7 @@
 //! Code shared by trait and projection goals for candidate assembly.
 
 use super::{EvalCtxt, SolverMode};
+use crate::solve::GoalSource;
 use crate::traits::coherence;
 use rustc_hir::def_id::DefId;
 use rustc_infer::traits::query::NoSolution;
@@ -62,7 +63,9 @@ pub(super) trait GoalKind<'tcx>:
         requirements: impl IntoIterator<Item = Goal<'tcx, ty::Predicate<'tcx>>>,
     ) -> QueryResult<'tcx> {
         Self::probe_and_match_goal_against_assumption(ecx, goal, assumption, |ecx| {
-            ecx.add_goals(requirements);
+            // FIXME(-Znext-solver=coinductive): check whether this should be
+            // `GoalSource::ImplWhereBound` for any caller.
+            ecx.add_goals(GoalSource::Misc, requirements);
             ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
         })
     }
@@ -94,12 +97,16 @@ pub(super) trait GoalKind<'tcx>:
             let ty::Dynamic(bounds, _, _) = *goal.predicate.self_ty().kind() else {
                 bug!("expected object type in `consider_object_bound_candidate`");
             };
-            ecx.add_goals(structural_traits::predicates_for_object_candidate(
-                ecx,
-                goal.param_env,
-                goal.predicate.trait_ref(tcx),
-                bounds,
-            ));
+            // FIXME(-Znext-solver=coinductive): Should this be `GoalSource::ImplWhereBound`?
+            ecx.add_goals(
+                GoalSource::Misc,
+                structural_traits::predicates_for_object_candidate(
+                    ecx,
+                    goal.param_env,
+                    goal.predicate.trait_ref(tcx),
+                    bounds,
+                ),
+            );
             ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
         })
     }
@@ -364,7 +371,7 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
                 let normalized_ty = ecx.next_ty_infer();
                 let normalizes_to_goal =
                     goal.with(tcx, ty::NormalizesTo { alias, term: normalized_ty.into() });
-                ecx.add_goal(normalizes_to_goal);
+                ecx.add_goal(GoalSource::Misc, normalizes_to_goal);
                 if let Err(NoSolution) = ecx.try_evaluate_added_goals() {
                     debug!("self type normalization failed");
                     return vec![];
diff --git a/compiler/rustc_trait_selection/src/solve/eval_ctxt/canonical.rs b/compiler/rustc_trait_selection/src/solve/eval_ctxt/canonical.rs
index 7457ba837f5..ecdae2521b9 100644
--- a/compiler/rustc_trait_selection/src/solve/eval_ctxt/canonical.rs
+++ b/compiler/rustc_trait_selection/src/solve/eval_ctxt/canonical.rs
@@ -94,20 +94,6 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
         );
 
         let certainty = certainty.unify_with(goals_certainty);
-        if let Certainty::OVERFLOW = certainty {
-            // If we have overflow, it's probable that we're substituting a type
-            // into itself infinitely and any partial substitutions in the query
-            // response are probably not useful anyways, so just return an empty
-            // query response.
-            //
-            // This may prevent us from potentially useful inference, e.g.
-            // 2 candidates, one ambiguous and one overflow, which both
-            // have the same inference constraints.
-            //
-            // Changing this to retain some constraints in the future
-            // won't be a breaking change, so this is good enough for now.
-            return Ok(self.make_ambiguous_response_no_constraints(MaybeCause::Overflow));
-        }
 
         let var_values = self.var_values;
         let external_constraints = self.compute_external_query_constraints()?;
diff --git a/compiler/rustc_trait_selection/src/solve/eval_ctxt/mod.rs b/compiler/rustc_trait_selection/src/solve/eval_ctxt/mod.rs
index cafb858794a..76c50a11102 100644
--- a/compiler/rustc_trait_selection/src/solve/eval_ctxt/mod.rs
+++ b/compiler/rustc_trait_selection/src/solve/eval_ctxt/mod.rs
@@ -23,14 +23,15 @@ use rustc_middle::ty::{
 use rustc_session::config::DumpSolverProofTree;
 use rustc_span::DUMMY_SP;
 use std::io::Write;
+use std::iter;
 use std::ops::ControlFlow;
 
 use crate::traits::vtable::{count_own_vtable_entries, prepare_vtable_segments, VtblSegment};
 
 use super::inspect::ProofTreeBuilder;
-use super::SolverMode;
 use super::{search_graph, GoalEvaluationKind};
 use super::{search_graph::SearchGraph, Goal};
+use super::{GoalSource, SolverMode};
 pub use select::InferCtxtSelectExt;
 
 mod canonical;
@@ -105,7 +106,7 @@ pub(super) struct NestedGoals<'tcx> {
     /// can be unsound with more powerful coinduction in the future.
     pub(super) normalizes_to_hack_goal: Option<Goal<'tcx, ty::NormalizesTo<'tcx>>>,
     /// The rest of the goals which have not yet processed or remain ambiguous.
-    pub(super) goals: Vec<Goal<'tcx, ty::Predicate<'tcx>>>,
+    pub(super) goals: Vec<(GoalSource, Goal<'tcx, ty::Predicate<'tcx>>)>,
 }
 
 impl<'tcx> NestedGoals<'tcx> {
@@ -156,7 +157,7 @@ impl<'tcx> InferCtxtEvalExt<'tcx> for InferCtxt<'tcx> {
         Option<inspect::GoalEvaluation<'tcx>>,
     ) {
         EvalCtxt::enter_root(self, generate_proof_tree, |ecx| {
-            ecx.evaluate_goal(GoalEvaluationKind::Root, goal)
+            ecx.evaluate_goal(GoalEvaluationKind::Root, GoalSource::Misc, goal)
         })
     }
 }
@@ -334,6 +335,7 @@ impl<'a, 'tcx> EvalCtxt<'a, 'tcx> {
     fn evaluate_goal(
         &mut self,
         goal_evaluation_kind: GoalEvaluationKind,
+        source: GoalSource,
         goal: Goal<'tcx, ty::Predicate<'tcx>>,
     ) -> Result<(bool, Certainty, Vec<Goal<'tcx, ty::Predicate<'tcx>>>), NoSolution> {
         let (orig_values, canonical_goal) = self.canonicalize_goal(goal);
@@ -353,13 +355,13 @@ impl<'a, 'tcx> EvalCtxt<'a, 'tcx> {
             Ok(response) => response,
         };
 
-        let has_changed = !canonical_response.value.var_values.is_identity_modulo_regions()
-            || !canonical_response.value.external_constraints.opaque_types.is_empty();
-        let (certainty, nested_goals) = match self.instantiate_and_apply_query_response(
-            goal.param_env,
-            orig_values,
-            canonical_response,
-        ) {
+        let (certainty, has_changed, nested_goals) = match self
+            .instantiate_response_discarding_overflow(
+                goal.param_env,
+                source,
+                orig_values,
+                canonical_response,
+            ) {
             Err(e) => {
                 self.inspect.goal_evaluation(goal_evaluation);
                 return Err(e);
@@ -386,6 +388,44 @@ impl<'a, 'tcx> EvalCtxt<'a, 'tcx> {
         Ok((has_changed, certainty, nested_goals))
     }
 
+    fn instantiate_response_discarding_overflow(
+        &mut self,
+        param_env: ty::ParamEnv<'tcx>,
+        source: GoalSource,
+        original_values: Vec<ty::GenericArg<'tcx>>,
+        response: CanonicalResponse<'tcx>,
+    ) -> Result<(Certainty, bool, Vec<Goal<'tcx, ty::Predicate<'tcx>>>), NoSolution> {
+        // The old solver did not evaluate nested goals when normalizing.
+        // It returned the selection constraints allowing a `Projection`
+        // obligation to not hold in coherence while avoiding the fatal error
+        // from overflow.
+        //
+        // We match this behavior here by considering all constraints
+        // from nested goals which are not from where-bounds. We will already
+        // need to track which nested goals are required by impl where-bounds
+        // for coinductive cycles, so we simply reuse that here.
+        //
+        // While we could consider overflow constraints in more cases, this should
+        // not be necessary for backcompat and results in better perf. It also
+        // avoids a potential inconsistency which would otherwise require some
+        // tracking for root goals as well. See #119071 for an example.
+        let keep_overflow_constraints = || {
+            self.search_graph.current_goal_is_normalizes_to()
+                && source != GoalSource::ImplWhereBound
+        };
+
+        if response.value.certainty == Certainty::OVERFLOW && !keep_overflow_constraints() {
+            Ok((Certainty::OVERFLOW, false, Vec::new()))
+        } else {
+            let has_changed = !response.value.var_values.is_identity_modulo_regions()
+                || !response.value.external_constraints.opaque_types.is_empty();
+
+            let (certainty, nested_goals) =
+                self.instantiate_and_apply_query_response(param_env, original_values, response)?;
+            Ok((certainty, has_changed, nested_goals))
+        }
+    }
+
     fn compute_goal(&mut self, goal: Goal<'tcx, ty::Predicate<'tcx>>) -> QueryResult<'tcx> {
         let Goal { param_env, predicate } = goal;
         let kind = predicate.kind();
@@ -439,7 +479,7 @@ impl<'a, 'tcx> EvalCtxt<'a, 'tcx> {
         } else {
             let kind = self.infcx.instantiate_binder_with_placeholders(kind);
             let goal = goal.with(self.tcx(), ty::Binder::dummy(kind));
-            self.add_goal(goal);
+            self.add_goal(GoalSource::Misc, goal);
             self.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
         }
     }
@@ -488,6 +528,13 @@ impl<'a, 'tcx> EvalCtxt<'a, 'tcx> {
         let mut goals = core::mem::replace(&mut self.nested_goals, NestedGoals::new());
 
         self.inspect.evaluate_added_goals_loop_start();
+
+        fn with_misc_source<'tcx>(
+            it: impl IntoIterator<Item = Goal<'tcx, ty::Predicate<'tcx>>>,
+        ) -> impl Iterator<Item = (GoalSource, Goal<'tcx, ty::Predicate<'tcx>>)> {
+            iter::zip(iter::repeat(GoalSource::Misc), it)
+        }
+
         // If this loop did not result in any progress, what's our final certainty.
         let mut unchanged_certainty = Some(Certainty::Yes);
         if let Some(goal) = goals.normalizes_to_hack_goal.take() {
@@ -501,9 +548,10 @@ impl<'a, 'tcx> EvalCtxt<'a, 'tcx> {
 
             let (_, certainty, instantiate_goals) = self.evaluate_goal(
                 GoalEvaluationKind::Nested { is_normalizes_to_hack: IsNormalizesToHack::Yes },
+                GoalSource::Misc,
                 unconstrained_goal,
             )?;
-            self.nested_goals.goals.extend(instantiate_goals);
+            self.nested_goals.goals.extend(with_misc_source(instantiate_goals));
 
             // Finally, equate the goal's RHS with the unconstrained var.
             // We put the nested goals from this into goals instead of
@@ -512,7 +560,7 @@ impl<'a, 'tcx> EvalCtxt<'a, 'tcx> {
             // matters in practice, though.
             let eq_goals =
                 self.eq_and_get_goals(goal.param_env, goal.predicate.term, unconstrained_rhs)?;
-            goals.goals.extend(eq_goals);
+            goals.goals.extend(with_misc_source(eq_goals));
 
             // We only look at the `projection_ty` part here rather than
             // looking at the "has changed" return from evaluate_goal,
@@ -533,12 +581,13 @@ impl<'a, 'tcx> EvalCtxt<'a, 'tcx> {
             }
         }
 
-        for goal in goals.goals.drain(..) {
+        for (source, goal) in goals.goals.drain(..) {
             let (has_changed, certainty, instantiate_goals) = self.evaluate_goal(
                 GoalEvaluationKind::Nested { is_normalizes_to_hack: IsNormalizesToHack::No },
+                source,
                 goal,
             )?;
-            self.nested_goals.goals.extend(instantiate_goals);
+            self.nested_goals.goals.extend(with_misc_source(instantiate_goals));
             if has_changed {
                 unchanged_certainty = None;
             }
@@ -546,7 +595,7 @@ impl<'a, 'tcx> EvalCtxt<'a, 'tcx> {
             match certainty {
                 Certainty::Yes => {}
                 Certainty::Maybe(_) => {
-                    self.nested_goals.goals.push(goal);
+                    self.nested_goals.goals.push((source, goal));
                     unchanged_certainty = unchanged_certainty.map(|c| c.unify_with(certainty));
                 }
             }
@@ -670,7 +719,7 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
             .at(&ObligationCause::dummy(), param_env)
             .eq(DefineOpaqueTypes::No, lhs, rhs)
             .map(|InferOk { value: (), obligations }| {
-                self.add_goals(obligations.into_iter().map(|o| o.into()));
+                self.add_goals(GoalSource::Misc, obligations.into_iter().map(|o| o.into()));
             })
             .map_err(|e| {
                 debug!(?e, "failed to equate");
@@ -689,7 +738,7 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
             .at(&ObligationCause::dummy(), param_env)
             .sub(DefineOpaqueTypes::No, sub, sup)
             .map(|InferOk { value: (), obligations }| {
-                self.add_goals(obligations.into_iter().map(|o| o.into()));
+                self.add_goals(GoalSource::Misc, obligations.into_iter().map(|o| o.into()));
             })
             .map_err(|e| {
                 debug!(?e, "failed to subtype");
@@ -709,7 +758,7 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
             .at(&ObligationCause::dummy(), param_env)
             .relate(DefineOpaqueTypes::No, lhs, variance, rhs)
             .map(|InferOk { value: (), obligations }| {
-                self.add_goals(obligations.into_iter().map(|o| o.into()));
+                self.add_goals(GoalSource::Misc, obligations.into_iter().map(|o| o.into()));
             })
             .map_err(|e| {
                 debug!(?e, "failed to relate");
@@ -842,7 +891,7 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
             true,
             &mut obligations,
         )?;
-        self.add_goals(obligations.into_iter().map(|o| o.into()));
+        self.add_goals(GoalSource::Misc, obligations.into_iter().map(|o| o.into()));
         Ok(())
     }
 
@@ -862,7 +911,7 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
             hidden_ty,
             &mut obligations,
         );
-        self.add_goals(obligations.into_iter().map(|o| o.into()));
+        self.add_goals(GoalSource::Misc, obligations.into_iter().map(|o| o.into()));
     }
 
     // Do something for each opaque/hidden pair defined with `def_id` in the
diff --git a/compiler/rustc_trait_selection/src/solve/inspect/analyse.rs b/compiler/rustc_trait_selection/src/solve/inspect/analyse.rs
index a287582dca7..6db53d6ddc4 100644
--- a/compiler/rustc_trait_selection/src/solve/inspect/analyse.rs
+++ b/compiler/rustc_trait_selection/src/solve/inspect/analyse.rs
@@ -119,7 +119,7 @@ impl<'a, 'tcx> InspectGoal<'a, 'tcx> {
     ) {
         for step in &probe.steps {
             match step {
-                &inspect::ProbeStep::AddGoal(goal) => nested_goals.push(goal),
+                &inspect::ProbeStep::AddGoal(_source, goal) => nested_goals.push(goal),
                 inspect::ProbeStep::NestedProbe(ref probe) => {
                     // Nested probes have to prove goals added in their parent
                     // but do not leak them, so we truncate the added goals
diff --git a/compiler/rustc_trait_selection/src/solve/inspect/build.rs b/compiler/rustc_trait_selection/src/solve/inspect/build.rs
index c857aae572d..d8caef5b03f 100644
--- a/compiler/rustc_trait_selection/src/solve/inspect/build.rs
+++ b/compiler/rustc_trait_selection/src/solve/inspect/build.rs
@@ -7,7 +7,7 @@ use std::mem;
 
 use rustc_middle::traits::query::NoSolution;
 use rustc_middle::traits::solve::{
-    CanonicalInput, Certainty, Goal, IsNormalizesToHack, QueryInput, QueryResult,
+    CanonicalInput, Certainty, Goal, GoalSource, IsNormalizesToHack, QueryInput, QueryResult,
 };
 use rustc_middle::ty::{self, TyCtxt};
 use rustc_session::config::DumpSolverProofTree;
@@ -216,7 +216,7 @@ impl<'tcx> WipProbe<'tcx> {
 
 #[derive(Eq, PartialEq, Debug)]
 enum WipProbeStep<'tcx> {
-    AddGoal(inspect::CanonicalState<'tcx, Goal<'tcx, ty::Predicate<'tcx>>>),
+    AddGoal(GoalSource, inspect::CanonicalState<'tcx, Goal<'tcx, ty::Predicate<'tcx>>>),
     EvaluateGoals(WipAddedGoalsEvaluation<'tcx>),
     NestedProbe(WipProbe<'tcx>),
     CommitIfOkStart,
@@ -226,7 +226,7 @@ enum WipProbeStep<'tcx> {
 impl<'tcx> WipProbeStep<'tcx> {
     fn finalize(self) -> inspect::ProbeStep<'tcx> {
         match self {
-            WipProbeStep::AddGoal(goal) => inspect::ProbeStep::AddGoal(goal),
+            WipProbeStep::AddGoal(source, goal) => inspect::ProbeStep::AddGoal(source, goal),
             WipProbeStep::EvaluateGoals(eval) => inspect::ProbeStep::EvaluateGoals(eval.finalize()),
             WipProbeStep::NestedProbe(probe) => inspect::ProbeStep::NestedProbe(probe.finalize()),
             WipProbeStep::CommitIfOkStart => inspect::ProbeStep::CommitIfOkStart,
@@ -428,7 +428,11 @@ impl<'tcx> ProofTreeBuilder<'tcx> {
         }
     }
 
-    pub fn add_goal(ecx: &mut EvalCtxt<'_, 'tcx>, goal: Goal<'tcx, ty::Predicate<'tcx>>) {
+    pub fn add_goal(
+        ecx: &mut EvalCtxt<'_, 'tcx>,
+        source: GoalSource,
+        goal: Goal<'tcx, ty::Predicate<'tcx>>,
+    ) {
         // Can't use `if let Some(this) = ecx.inspect.as_mut()` here because
         // we have to immutably use the `EvalCtxt` for `make_canonical_state`.
         if ecx.inspect.is_noop() {
@@ -442,7 +446,9 @@ impl<'tcx> ProofTreeBuilder<'tcx> {
                 evaluation: WipProbe { steps, .. },
                 ..
             })
-            | DebugSolver::Probe(WipProbe { steps, .. }) => steps.push(WipProbeStep::AddGoal(goal)),
+            | DebugSolver::Probe(WipProbe { steps, .. }) => {
+                steps.push(WipProbeStep::AddGoal(source, goal))
+            }
             s => unreachable!("tried to add {goal:?} to {s:?}"),
         }
     }
diff --git a/compiler/rustc_trait_selection/src/solve/mod.rs b/compiler/rustc_trait_selection/src/solve/mod.rs
index 1e58106e353..2f3111a2414 100644
--- a/compiler/rustc_trait_selection/src/solve/mod.rs
+++ b/compiler/rustc_trait_selection/src/solve/mod.rs
@@ -19,8 +19,8 @@ use rustc_infer::infer::DefineOpaqueTypes;
 use rustc_infer::traits::query::NoSolution;
 use rustc_middle::infer::canonical::CanonicalVarInfos;
 use rustc_middle::traits::solve::{
-    CanonicalResponse, Certainty, ExternalConstraintsData, Goal, IsNormalizesToHack, QueryResult,
-    Response,
+    CanonicalResponse, Certainty, ExternalConstraintsData, Goal, GoalSource, IsNormalizesToHack,
+    QueryResult, Response,
 };
 use rustc_middle::ty::{self, OpaqueTypeKey, Ty, TyCtxt, UniverseIndex};
 use rustc_middle::ty::{
@@ -157,7 +157,7 @@ impl<'a, 'tcx> EvalCtxt<'a, 'tcx> {
     ) -> QueryResult<'tcx> {
         match self.well_formed_goals(goal.param_env, goal.predicate) {
             Some(goals) => {
-                self.add_goals(goals);
+                self.add_goals(GoalSource::Misc, goals);
                 self.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
             }
             None => self.evaluate_added_goals_and_make_canonical_response(Certainty::AMBIGUOUS),
@@ -223,15 +223,19 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
     }
 
     #[instrument(level = "debug", skip(self))]
-    fn add_goal(&mut self, goal: Goal<'tcx, ty::Predicate<'tcx>>) {
-        inspect::ProofTreeBuilder::add_goal(self, goal);
-        self.nested_goals.goals.push(goal);
+    fn add_goal(&mut self, source: GoalSource, goal: Goal<'tcx, ty::Predicate<'tcx>>) {
+        inspect::ProofTreeBuilder::add_goal(self, source, goal);
+        self.nested_goals.goals.push((source, goal));
     }
 
     #[instrument(level = "debug", skip(self, goals))]
-    fn add_goals(&mut self, goals: impl IntoIterator<Item = Goal<'tcx, ty::Predicate<'tcx>>>) {
+    fn add_goals(
+        &mut self,
+        source: GoalSource,
+        goals: impl IntoIterator<Item = Goal<'tcx, ty::Predicate<'tcx>>>,
+    ) {
         for goal in goals {
-            self.add_goal(goal);
+            self.add_goal(source, goal);
         }
     }
 
@@ -335,7 +339,7 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
                 param_env,
                 ty::NormalizesTo { alias, term: normalized_ty.into() },
             );
-            this.add_goal(normalizes_to_goal);
+            this.add_goal(GoalSource::Misc, normalizes_to_goal);
             this.try_evaluate_added_goals()?;
             let ty = this.resolve_vars_if_possible(normalized_ty);
             Ok(this.try_normalize_ty_recur(param_env, define_opaque_types, depth + 1, ty))
diff --git a/compiler/rustc_trait_selection/src/solve/normalizes_to/inherent.rs b/compiler/rustc_trait_selection/src/solve/normalizes_to/inherent.rs
index c3b8ae9a943..b2dff9b48ff 100644
--- a/compiler/rustc_trait_selection/src/solve/normalizes_to/inherent.rs
+++ b/compiler/rustc_trait_selection/src/solve/normalizes_to/inherent.rs
@@ -4,10 +4,10 @@
 //! 1. instantiate substs,
 //! 2. equate the self type, and
 //! 3. instantiate and register where clauses.
-use rustc_middle::traits::solve::{Certainty, Goal, QueryResult};
+use rustc_middle::traits::solve::{Certainty, Goal, GoalSource, QueryResult};
 use rustc_middle::ty;
 
-use super::EvalCtxt;
+use crate::solve::EvalCtxt;
 
 impl<'tcx> EvalCtxt<'_, 'tcx> {
     pub(super) fn normalize_inherent_associated_type(
@@ -38,7 +38,13 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
         .expect("expected goal term to be fully unconstrained");
 
         // Check both where clauses on the impl and IAT
+        //
+        // FIXME(-Znext-solver=coinductive): I think this should be split
+        // and we tag the impl bounds with `GoalSource::ImplWhereBound`?
+        // Right not this includes both the impl and the assoc item where bounds,
+        // and I don't think the assoc item where-bounds are allowed to be coinductive.
         self.add_goals(
+            GoalSource::Misc,
             tcx.predicates_of(inherent.def_id)
                 .instantiate(tcx, inherent_substs)
                 .into_iter()
diff --git a/compiler/rustc_trait_selection/src/solve/normalizes_to/mod.rs b/compiler/rustc_trait_selection/src/solve/normalizes_to/mod.rs
index 980ef862366..0e9656a1e18 100644
--- a/compiler/rustc_trait_selection/src/solve/normalizes_to/mod.rs
+++ b/compiler/rustc_trait_selection/src/solve/normalizes_to/mod.rs
@@ -1,7 +1,7 @@
 use crate::traits::{check_args_compatible, specialization_graph};
 
 use super::assembly::{self, structural_traits, Candidate};
-use super::EvalCtxt;
+use super::{EvalCtxt, GoalSource};
 use rustc_hir::def::DefKind;
 use rustc_hir::def_id::DefId;
 use rustc_hir::LangItem;
@@ -128,6 +128,7 @@ impl<'tcx> assembly::GoalKind<'tcx> for NormalizesTo<'tcx> {
 
                     // Add GAT where clauses from the trait's definition
                     ecx.add_goals(
+                        GoalSource::Misc,
                         tcx.predicates_of(goal.predicate.def_id())
                             .instantiate_own(tcx, goal.predicate.alias.args)
                             .map(|(pred, _)| goal.with(tcx, pred)),
@@ -169,10 +170,11 @@ impl<'tcx> assembly::GoalKind<'tcx> for NormalizesTo<'tcx> {
                 .predicates
                 .into_iter()
                 .map(|pred| goal.with(tcx, pred));
-            ecx.add_goals(where_clause_bounds);
+            ecx.add_goals(GoalSource::ImplWhereBound, where_clause_bounds);
 
             // Add GAT where clauses from the trait's definition
             ecx.add_goals(
+                GoalSource::Misc,
                 tcx.predicates_of(goal.predicate.def_id())
                     .instantiate_own(tcx, goal.predicate.alias.args)
                     .map(|(pred, _)| goal.with(tcx, pred)),
@@ -413,7 +415,8 @@ impl<'tcx> assembly::GoalKind<'tcx> for NormalizesTo<'tcx> {
                         DUMMY_SP,
                         [ty::GenericArg::from(goal.predicate.self_ty())],
                     );
-                    ecx.add_goal(goal.with(tcx, sized_predicate));
+                    // FIXME(-Znext-solver=coinductive): Should this be `GoalSource::ImplWhereBound`?
+                    ecx.add_goal(GoalSource::Misc, goal.with(tcx, sized_predicate));
                     tcx.types.unit
                 }
 
@@ -421,7 +424,11 @@ impl<'tcx> assembly::GoalKind<'tcx> for NormalizesTo<'tcx> {
                     None => tcx.types.unit,
                     Some(field_def) => {
                         let self_ty = field_def.ty(tcx, args);
-                        ecx.add_goal(goal.with(tcx, goal.predicate.with_self_ty(tcx, self_ty)));
+                        // FIXME(-Znext-solver=coinductive): Should this be `GoalSource::ImplWhereBound`?
+                        ecx.add_goal(
+                            GoalSource::Misc,
+                            goal.with(tcx, goal.predicate.with_self_ty(tcx, self_ty)),
+                        );
                         return ecx
                             .evaluate_added_goals_and_make_canonical_response(Certainty::Yes);
                     }
@@ -431,7 +438,11 @@ impl<'tcx> assembly::GoalKind<'tcx> for NormalizesTo<'tcx> {
                 ty::Tuple(elements) => match elements.last() {
                     None => tcx.types.unit,
                     Some(&self_ty) => {
-                        ecx.add_goal(goal.with(tcx, goal.predicate.with_self_ty(tcx, self_ty)));
+                        // FIXME(-Znext-solver=coinductive): Should this be `GoalSource::ImplWhereBound`?
+                        ecx.add_goal(
+                            GoalSource::Misc,
+                            goal.with(tcx, goal.predicate.with_self_ty(tcx, self_ty)),
+                        );
                         return ecx
                             .evaluate_added_goals_and_make_canonical_response(Certainty::Yes);
                     }
diff --git a/compiler/rustc_trait_selection/src/solve/normalizes_to/weak_types.rs b/compiler/rustc_trait_selection/src/solve/normalizes_to/weak_types.rs
index 8d2bbec6d8b..6d5728797d1 100644
--- a/compiler/rustc_trait_selection/src/solve/normalizes_to/weak_types.rs
+++ b/compiler/rustc_trait_selection/src/solve/normalizes_to/weak_types.rs
@@ -3,10 +3,10 @@
 //!
 //! Since a weak alias is not ambiguous, this just computes the `type_of` of
 //! the alias and registers the where-clauses of the type alias.
-use rustc_middle::traits::solve::{Certainty, Goal, QueryResult};
+use rustc_middle::traits::solve::{Certainty, Goal, GoalSource, QueryResult};
 use rustc_middle::ty;
 
-use super::EvalCtxt;
+use crate::solve::EvalCtxt;
 
 impl<'tcx> EvalCtxt<'_, 'tcx> {
     pub(super) fn normalize_weak_type(
@@ -22,6 +22,7 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
 
         // Check where clauses
         self.add_goals(
+            GoalSource::Misc,
             tcx.predicates_of(weak_ty.def_id)
                 .instantiate(tcx, weak_ty.args)
                 .predicates
diff --git a/compiler/rustc_trait_selection/src/solve/project_goals.rs b/compiler/rustc_trait_selection/src/solve/project_goals.rs
index d0e92a54ceb..30ae385a8a0 100644
--- a/compiler/rustc_trait_selection/src/solve/project_goals.rs
+++ b/compiler/rustc_trait_selection/src/solve/project_goals.rs
@@ -1,3 +1,5 @@
+use crate::solve::GoalSource;
+
 use super::EvalCtxt;
 use rustc_middle::traits::solve::{Certainty, Goal, QueryResult};
 use rustc_middle::ty::{self, ProjectionPredicate};
@@ -22,14 +24,15 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
             )
             .into(),
         };
-        self.add_goal(goal.with(
+        let goal = goal.with(
             tcx,
             ty::PredicateKind::AliasRelate(
                 projection_term,
                 goal.predicate.term,
                 ty::AliasRelationDirection::Equate,
             ),
-        ));
+        );
+        self.add_goal(GoalSource::Misc, goal);
         self.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
     }
 }
diff --git a/compiler/rustc_trait_selection/src/solve/search_graph.rs b/compiler/rustc_trait_selection/src/solve/search_graph.rs
index 2a08b80e02a..2a161c2d956 100644
--- a/compiler/rustc_trait_selection/src/solve/search_graph.rs
+++ b/compiler/rustc_trait_selection/src/solve/search_graph.rs
@@ -8,6 +8,7 @@ use rustc_index::IndexVec;
 use rustc_middle::dep_graph::dep_kinds;
 use rustc_middle::traits::solve::CacheData;
 use rustc_middle::traits::solve::{CanonicalInput, Certainty, EvaluationCache, QueryResult};
+use rustc_middle::ty;
 use rustc_middle::ty::TyCtxt;
 use rustc_session::Limit;
 use std::collections::hash_map::Entry;
@@ -111,6 +112,15 @@ impl<'tcx> SearchGraph<'tcx> {
         self.stack.is_empty()
     }
 
+    pub(super) fn current_goal_is_normalizes_to(&self) -> bool {
+        self.stack.raw.last().map_or(false, |e| {
+            matches!(
+                e.input.value.goal.predicate.kind().skip_binder(),
+                ty::PredicateKind::NormalizesTo(..)
+            )
+        })
+    }
+
     /// Returns the remaining depth allowed for nested goals.
     ///
     /// This is generally simply one less than the current depth.
diff --git a/compiler/rustc_trait_selection/src/solve/trait_goals.rs b/compiler/rustc_trait_selection/src/solve/trait_goals.rs
index deb50e6aefd..ac3ffd2d6c2 100644
--- a/compiler/rustc_trait_selection/src/solve/trait_goals.rs
+++ b/compiler/rustc_trait_selection/src/solve/trait_goals.rs
@@ -1,7 +1,7 @@
 //! Dealing with trait goals, i.e. `T: Trait<'a, U>`.
 
 use super::assembly::{self, structural_traits, Candidate};
-use super::{EvalCtxt, SolverMode};
+use super::{EvalCtxt, GoalSource, SolverMode};
 use rustc_hir::def_id::DefId;
 use rustc_hir::{LangItem, Movability};
 use rustc_infer::traits::query::NoSolution;
@@ -72,7 +72,7 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> {
                 .predicates
                 .into_iter()
                 .map(|pred| goal.with(tcx, pred));
-            ecx.add_goals(where_clause_bounds);
+            ecx.add_goals(GoalSource::ImplWhereBound, where_clause_bounds);
 
             ecx.evaluate_added_goals_and_make_canonical_response(maximal_certainty)
         })
@@ -172,7 +172,11 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> {
             let nested_obligations = tcx
                 .predicates_of(goal.predicate.def_id())
                 .instantiate(tcx, goal.predicate.trait_ref.args);
-            ecx.add_goals(nested_obligations.predicates.into_iter().map(|p| goal.with(tcx, p)));
+            // FIXME(-Znext-solver=coinductive): Should this be `GoalSource::ImplWhereBound`?
+            ecx.add_goals(
+                GoalSource::Misc,
+                nested_obligations.predicates.into_iter().map(|p| goal.with(tcx, p)),
+            );
             ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
         })
     }
@@ -512,17 +516,23 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> {
 
             // Check that the type implements all of the predicates of the trait object.
             // (i.e. the principal, all of the associated types match, and any auto traits)
-            ecx.add_goals(b_data.iter().map(|pred| goal.with(tcx, pred.with_self_ty(tcx, a_ty))));
+            ecx.add_goals(
+                GoalSource::ImplWhereBound,
+                b_data.iter().map(|pred| goal.with(tcx, pred.with_self_ty(tcx, a_ty))),
+            );
 
             // The type must be `Sized` to be unsized.
             if let Some(sized_def_id) = tcx.lang_items().sized_trait() {
-                ecx.add_goal(goal.with(tcx, ty::TraitRef::new(tcx, sized_def_id, [a_ty])));
+                ecx.add_goal(
+                    GoalSource::ImplWhereBound,
+                    goal.with(tcx, ty::TraitRef::new(tcx, sized_def_id, [a_ty])),
+                );
             } else {
                 return Err(NoSolution);
             }
 
             // The type must outlive the lifetime of the `dyn` we're unsizing into.
-            ecx.add_goal(goal.with(tcx, ty::OutlivesPredicate(a_ty, b_region)));
+            ecx.add_goal(GoalSource::Misc, goal.with(tcx, ty::OutlivesPredicate(a_ty, b_region)));
             ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
         })
     }
@@ -749,11 +759,14 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
         }
 
         // Also require that a_ty's lifetime outlives b_ty's lifetime.
-        self.add_goal(Goal::new(
-            self.tcx(),
-            param_env,
-            ty::Binder::dummy(ty::OutlivesPredicate(a_region, b_region)),
-        ));
+        self.add_goal(
+            GoalSource::ImplWhereBound,
+            Goal::new(
+                self.tcx(),
+                param_env,
+                ty::Binder::dummy(ty::OutlivesPredicate(a_region, b_region)),
+            ),
+        );
 
         self.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
     }
@@ -826,14 +839,17 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
         // Finally, we require that `TailA: Unsize<TailB>` for the tail field
         // types.
         self.eq(goal.param_env, unsized_a_ty, b_ty)?;
-        self.add_goal(goal.with(
-            tcx,
-            ty::TraitRef::new(
+        self.add_goal(
+            GoalSource::ImplWhereBound,
+            goal.with(
                 tcx,
-                tcx.lang_items().unsize_trait().unwrap(),
-                [a_tail_ty, b_tail_ty],
+                ty::TraitRef::new(
+                    tcx,
+                    tcx.lang_items().unsize_trait().unwrap(),
+                    [a_tail_ty, b_tail_ty],
+                ),
             ),
-        ));
+        );
         self.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
     }
 
@@ -865,14 +881,17 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
         self.eq(goal.param_env, unsized_a_ty, b_ty)?;
 
         // Similar to ADTs, require that we can unsize the tail.
-        self.add_goal(goal.with(
-            tcx,
-            ty::TraitRef::new(
+        self.add_goal(
+            GoalSource::ImplWhereBound,
+            goal.with(
                 tcx,
-                tcx.lang_items().unsize_trait().unwrap(),
-                [a_last_ty, b_last_ty],
+                ty::TraitRef::new(
+                    tcx,
+                    tcx.lang_items().unsize_trait().unwrap(),
+                    [a_last_ty, b_last_ty],
+                ),
             ),
-        ));
+        );
         self.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
     }
 
@@ -981,6 +1000,7 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
     ) -> QueryResult<'tcx> {
         self.probe_misc_candidate("constituent tys").enter(|ecx| {
             ecx.add_goals(
+                GoalSource::ImplWhereBound,
                 constituent_tys(ecx, goal.predicate.self_ty())?
                     .into_iter()
                     .map(|ty| goal.with(ecx.tcx(), goal.predicate.with_self_ty(ecx.tcx(), ty)))
diff --git a/compiler/stable_mir/src/abi.rs b/compiler/stable_mir/src/abi.rs
new file mode 100644
index 00000000000..53dac6abefb
--- /dev/null
+++ b/compiler/stable_mir/src/abi.rs
@@ -0,0 +1,283 @@
+use crate::compiler_interface::with;
+use crate::mir::FieldIdx;
+use crate::ty::{Align, IndexedVal, Size, Ty, VariantIdx};
+use crate::Opaque;
+use std::num::NonZeroUsize;
+use std::ops::RangeInclusive;
+
+/// A function ABI definition.
+#[derive(Clone, Debug, PartialEq, Eq, Hash)]
+pub struct FnAbi {
+    /// The types of each argument.
+    pub args: Vec<ArgAbi>,
+
+    /// The expected return type.
+    pub ret: ArgAbi,
+
+    /// The count of non-variadic arguments.
+    ///
+    /// Should only be different from `args.len()` when a function is a C variadic function.
+    pub fixed_count: u32,
+
+    /// The ABI convention.
+    pub conv: CallConvention,
+
+    /// Whether this is a variadic C function,
+    pub c_variadic: bool,
+}
+
+/// Information about the ABI of a function's argument, or return value.
+#[derive(Clone, Debug, PartialEq, Eq, Hash)]
+pub struct ArgAbi {
+    pub ty: Ty,
+    pub layout: Layout,
+    pub mode: PassMode,
+}
+
+/// How a function argument should be passed in to the target function.
+#[derive(Clone, Debug, PartialEq, Eq, Hash)]
+pub enum PassMode {
+    /// Ignore the argument.
+    ///
+    /// The argument is either uninhabited or a ZST.
+    Ignore,
+    /// Pass the argument directly.
+    ///
+    /// The argument has a layout abi of `Scalar` or `Vector`.
+    Direct(Opaque),
+    /// Pass a pair's elements directly in two arguments.
+    ///
+    /// The argument has a layout abi of `ScalarPair`.
+    Pair(Opaque, Opaque),
+    /// Pass the argument after casting it.
+    Cast { pad_i32: bool, cast: Opaque },
+    /// Pass the argument indirectly via a hidden pointer.
+    Indirect { attrs: Opaque, meta_attrs: Opaque, on_stack: bool },
+}
+
+/// The layout of a type, alongside the type itself.
+#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
+pub struct TyAndLayout {
+    pub ty: Ty,
+    pub layout: Layout,
+}
+
+/// The layout of a type in memory.
+#[derive(Clone, Debug, PartialEq, Eq, Hash)]
+pub struct LayoutShape {
+    /// The fields location withing the layout
+    pub fields: FieldsShape,
+
+    /// Encodes information about multi-variant layouts.
+    /// Even with `Multiple` variants, a layout still has its own fields! Those are then
+    /// shared between all variants.
+    ///
+    /// To access all fields of this layout, both `fields` and the fields of the active variant
+    /// must be taken into account.
+    pub variants: VariantsShape,
+
+    /// The `abi` defines how this data is passed between functions.
+    pub abi: ValueAbi,
+
+    /// The ABI mandated alignment in bytes.
+    pub abi_align: Align,
+
+    /// The size of this layout in bytes.
+    pub size: Size,
+}
+
+impl LayoutShape {
+    /// Returns `true` if the layout corresponds to an unsized type.
+    #[inline]
+    pub fn is_unsized(&self) -> bool {
+        self.abi.is_unsized()
+    }
+
+    #[inline]
+    pub fn is_sized(&self) -> bool {
+        !self.abi.is_unsized()
+    }
+
+    /// Returns `true` if the type is sized and a 1-ZST (meaning it has size 0 and alignment 1).
+    pub fn is_1zst(&self) -> bool {
+        self.is_sized() && self.size == 0 && self.abi_align == 1
+    }
+}
+
+#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
+pub struct Layout(usize);
+
+impl Layout {
+    pub fn shape(self) -> LayoutShape {
+        with(|cx| cx.layout_shape(self))
+    }
+}
+
+impl IndexedVal for Layout {
+    fn to_val(index: usize) -> Self {
+        Layout(index)
+    }
+    fn to_index(&self) -> usize {
+        self.0
+    }
+}
+
+/// Describes how the fields of a type are shaped in memory.
+#[derive(Clone, Debug, PartialEq, Eq, Hash)]
+pub enum FieldsShape {
+    /// Scalar primitives and `!`, which never have fields.
+    Primitive,
+
+    /// All fields start at no offset. The `usize` is the field count.
+    Union(NonZeroUsize),
+
+    /// Array/vector-like placement, with all fields of identical types.
+    Array { stride: Size, count: u64 },
+
+    /// Struct-like placement, with precomputed offsets.
+    ///
+    /// Fields are guaranteed to not overlap, but note that gaps
+    /// before, between and after all the fields are NOT always
+    /// padding, and as such their contents may not be discarded.
+    /// For example, enum variants leave a gap at the start,
+    /// where the discriminant field in the enum layout goes.
+    Arbitrary {
+        /// Offsets for the first byte of each field,
+        /// ordered to match the source definition order.
+        /// I.e.: It follows the same order as [crate::ty::VariantDef::fields()].
+        /// This vector does not go in increasing order.
+        offsets: Vec<Size>,
+    },
+}
+
+impl FieldsShape {
+    pub fn fields_by_offset_order(&self) -> Vec<FieldIdx> {
+        match self {
+            FieldsShape::Primitive => vec![],
+            FieldsShape::Union(_) | FieldsShape::Array { .. } => (0..self.count()).collect(),
+            FieldsShape::Arbitrary { offsets, .. } => {
+                let mut indices = (0..offsets.len()).collect::<Vec<_>>();
+                indices.sort_by_key(|idx| offsets[*idx]);
+                indices
+            }
+        }
+    }
+
+    pub fn count(&self) -> usize {
+        match self {
+            FieldsShape::Primitive => 0,
+            FieldsShape::Union(count) => count.get(),
+            FieldsShape::Array { count, .. } => *count as usize,
+            FieldsShape::Arbitrary { offsets, .. } => offsets.len(),
+        }
+    }
+}
+
+#[derive(Clone, Debug, PartialEq, Eq, Hash)]
+pub enum VariantsShape {
+    /// Single enum variants, structs/tuples, unions, and all non-ADTs.
+    Single { index: VariantIdx },
+
+    /// Enum-likes with more than one inhabited variant: each variant comes with
+    /// a *discriminant* (usually the same as the variant index but the user can
+    /// assign explicit discriminant values). That discriminant is encoded
+    /// as a *tag* on the machine. The layout of each variant is
+    /// a struct, and they all have space reserved for the tag.
+    /// For enums, the tag is the sole field of the layout.
+    Multiple {
+        tag: Scalar,
+        tag_encoding: TagEncoding,
+        tag_field: usize,
+        variants: Vec<LayoutShape>,
+    },
+}
+
+#[derive(Clone, Debug, PartialEq, Eq, Hash)]
+pub enum TagEncoding {
+    /// The tag directly stores the discriminant, but possibly with a smaller layout
+    /// (so converting the tag to the discriminant can require sign extension).
+    Direct,
+
+    /// Niche (values invalid for a type) encoding the discriminant:
+    /// Discriminant and variant index coincide.
+    /// The variant `untagged_variant` contains a niche at an arbitrary
+    /// offset (field `tag_field` of the enum), which for a variant with
+    /// discriminant `d` is set to
+    /// `(d - niche_variants.start).wrapping_add(niche_start)`.
+    ///
+    /// For example, `Option<(usize, &T)>`  is represented such that
+    /// `None` has a null pointer for the second tuple field, and
+    /// `Some` is the identity function (with a non-null reference).
+    Niche {
+        untagged_variant: VariantIdx,
+        niche_variants: RangeInclusive<VariantIdx>,
+        niche_start: u128,
+    },
+}
+
+/// Describes how values of the type are passed by target ABIs,
+/// in terms of categories of C types there are ABI rules for.
+#[derive(Clone, Debug, PartialEq, Eq, Hash)]
+pub enum ValueAbi {
+    Uninhabited,
+    Scalar(Scalar),
+    ScalarPair(Scalar, Scalar),
+    Vector {
+        element: Scalar,
+        count: u64,
+    },
+    Aggregate {
+        /// If true, the size is exact, otherwise it's only a lower bound.
+        sized: bool,
+    },
+}
+
+impl ValueAbi {
+    /// Returns `true` if the layout corresponds to an unsized type.
+    pub fn is_unsized(&self) -> bool {
+        match *self {
+            ValueAbi::Uninhabited
+            | ValueAbi::Scalar(_)
+            | ValueAbi::ScalarPair(..)
+            | ValueAbi::Vector { .. } => false,
+            ValueAbi::Aggregate { sized } => !sized,
+        }
+    }
+}
+
+/// We currently do not support `Scalar`, and use opaque instead.
+type Scalar = Opaque;
+
+/// General language calling conventions.
+#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
+pub enum CallConvention {
+    C,
+    Rust,
+
+    Cold,
+    PreserveMost,
+    PreserveAll,
+
+    // Target-specific calling conventions.
+    ArmAapcs,
+    CCmseNonSecureCall,
+
+    Msp430Intr,
+
+    PtxKernel,
+
+    X86Fastcall,
+    X86Intr,
+    X86Stdcall,
+    X86ThisCall,
+    X86VectorCall,
+
+    X86_64SysV,
+    X86_64Win64,
+
+    AmdGpuKernel,
+    AvrInterrupt,
+    AvrNonBlockingInterrupt,
+
+    RiscvInterrupt,
+}
diff --git a/compiler/stable_mir/src/compiler_interface.rs b/compiler/stable_mir/src/compiler_interface.rs
index 57c60b70d8a..98b1d484c03 100644
--- a/compiler/stable_mir/src/compiler_interface.rs
+++ b/compiler/stable_mir/src/compiler_interface.rs
@@ -5,6 +5,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;
@@ -173,6 +174,15 @@ pub trait Context {
 
     /// Return information about the target machine.
     fn target_info(&self) -> MachineInfo;
+
+    /// Get an instance ABI.
+    fn instance_abi(&self, def: InstanceDef) -> Result<FnAbi, Error>;
+
+    /// Get the layout of a type.
+    fn ty_layout(&self, ty: Ty) -> Result<Layout, Error>;
+
+    /// Get the layout shape.
+    fn layout_shape(&self, id: Layout) -> LayoutShape;
 }
 
 // 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 8c66bfb2e98..4941e54fe4b 100644
--- a/compiler/stable_mir/src/lib.rs
+++ b/compiler/stable_mir/src/lib.rs
@@ -33,6 +33,7 @@ use crate::mir::Body;
 use crate::mir::Mutability;
 use crate::ty::{ImplDef, ImplTrait, IndexedVal, Span, TraitDecl, TraitDef, Ty};
 
+pub mod abi;
 #[macro_use]
 pub mod crate_def;
 pub mod compiler_interface;
diff --git a/compiler/stable_mir/src/mir/mono.rs b/compiler/stable_mir/src/mir/mono.rs
index c126de23c4b..70d44ef8c22 100644
--- a/compiler/stable_mir/src/mir/mono.rs
+++ b/compiler/stable_mir/src/mir/mono.rs
@@ -1,3 +1,4 @@
+use crate::abi::FnAbi;
 use crate::crate_def::CrateDef;
 use crate::mir::Body;
 use crate::ty::{Allocation, ClosureDef, ClosureKind, FnDef, GenericArgs, IndexedVal, Ty};
@@ -56,6 +57,11 @@ impl Instance {
         with(|context| context.instance_ty(self.def))
     }
 
+    /// Retrieve information about this instance binary interface.
+    pub fn fn_abi(&self) -> Result<FnAbi, Error> {
+        with(|cx| cx.instance_abi(self.def))
+    }
+
     /// Retrieve the instance's mangled name used for calling the given instance.
     ///
     /// This will also look up the correct name of instances from upstream crates.
diff --git a/compiler/stable_mir/src/ty.rs b/compiler/stable_mir/src/ty.rs
index 4807a9028eb..1d4d7b6d352 100644
--- a/compiler/stable_mir/src/ty.rs
+++ b/compiler/stable_mir/src/ty.rs
@@ -3,6 +3,7 @@ use super::{
     mir::{Body, Mutability},
     with, DefId, Error, Symbol,
 };
+use crate::abi::Layout;
 use crate::crate_def::CrateDef;
 use crate::mir::alloc::{read_target_int, read_target_uint, AllocId};
 use crate::target::MachineInfo;
@@ -85,6 +86,11 @@ impl Ty {
     pub fn unsigned_ty(inner: UintTy) -> Ty {
         Ty::from_rigid_kind(RigidTy::Uint(inner))
     }
+
+    /// Get a type layout.
+    pub fn layout(self) -> Result<Layout, Error> {
+        with(|cx| cx.ty_layout(self))
+    }
 }
 
 impl Ty {
diff --git a/src/doc/rustc/src/SUMMARY.md b/src/doc/rustc/src/SUMMARY.md
index f46daca1f30..fadd64a0353 100644
--- a/src/doc/rustc/src/SUMMARY.md
+++ b/src/doc/rustc/src/SUMMARY.md
@@ -22,8 +22,10 @@
     - [\*-apple-watchos\*](platform-support/apple-watchos.md)
     - [aarch64-nintendo-switch-freestanding](platform-support/aarch64-nintendo-switch-freestanding.md)
     - [armeb-unknown-linux-gnueabi](platform-support/armeb-unknown-linux-gnueabi.md)
+    - [arm-none-eabi](platform-support/arm-none-eabi.md)
     - [armv4t-none-eabi](platform-support/armv4t-none-eabi.md)
     - [armv5te-none-eabi](platform-support/armv5te-none-eabi.md)
+    - [armv7r-none-eabi](platform-support/armv7r-none-eabi.md)
     - [armv6k-nintendo-3ds](platform-support/armv6k-nintendo-3ds.md)
     - [armv7-sony-vita-newlibeabihf](platform-support/armv7-sony-vita-newlibeabihf.md)
     - [armv7-unknown-linux-uclibceabi](platform-support/armv7-unknown-linux-uclibceabi.md)
diff --git a/src/doc/rustc/src/platform-support.md b/src/doc/rustc/src/platform-support.md
index 1893a322708..59ef7441024 100644
--- a/src/doc/rustc/src/platform-support.md
+++ b/src/doc/rustc/src/platform-support.md
@@ -137,17 +137,17 @@ target | std | notes
 [`arm-linux-androideabi`](platform-support/android.md) | ✓ | ARMv6 Android
 `arm-unknown-linux-musleabi` | ✓ | ARMv6 Linux with MUSL
 `arm-unknown-linux-musleabihf` | ✓ | ARMv6 Linux with MUSL, hardfloat
-`armebv7r-none-eabi` | * | Bare ARMv7-R, Big Endian
-`armebv7r-none-eabihf` | * | Bare ARMv7-R, Big Endian, hardfloat
+[`armebv7r-none-eabi`](platform-support/armv7r-none-eabi.md) | * | Bare ARMv7-R, Big Endian
+[`armebv7r-none-eabihf`](platform-support/armv7r-none-eabi.md) | * | Bare ARMv7-R, Big Endian, hardfloat
 `armv5te-unknown-linux-gnueabi` | ✓ | ARMv5TE Linux (kernel 4.4, glibc 2.23)
 `armv5te-unknown-linux-musleabi` | ✓ | ARMv5TE Linux with MUSL
 [`armv7-linux-androideabi`](platform-support/android.md) | ✓ | ARMv7-A Android
 `armv7-unknown-linux-gnueabi` | ✓ | ARMv7-A Linux (kernel 4.15, glibc 2.27)
 `armv7-unknown-linux-musleabi` | ✓ | ARMv7-A Linux with MUSL
 `armv7-unknown-linux-musleabihf` | ✓ | ARMv7-A Linux with MUSL, hardfloat
-`armv7a-none-eabi` | * | Bare ARMv7-A
-`armv7r-none-eabi` | * | Bare ARMv7-R
-`armv7r-none-eabihf` | * | Bare ARMv7-R, hardfloat
+[`armv7a-none-eabi`](platform-support/arm-none-eabi.md) | * | Bare ARMv7-A
+[`armv7r-none-eabi`](platform-support/armv7r-none-eabi.md) | * | Bare ARMv7-R
+[`armv7r-none-eabihf`](platform-support/armv7r-none-eabi.md) | * | Bare ARMv7-R, hardfloat
 `i586-pc-windows-msvc` | * | 32-bit Windows w/o SSE [^x86_32-floats-x87]
 `i586-unknown-linux-gnu` | ✓ | 32-bit Linux w/o SSE (kernel 3.2, glibc 2.17) [^x86_32-floats-x87]
 `i586-unknown-linux-musl` | ✓ | 32-bit Linux w/o SSE, MUSL [^x86_32-floats-x87]
@@ -166,15 +166,15 @@ target | std | notes
 `riscv64imac-unknown-none-elf` | * | Bare RISC-V (RV64IMAC ISA)
 `sparc64-unknown-linux-gnu` | ✓ | SPARC Linux (kernel 4.4, glibc 2.23)
 `sparcv9-sun-solaris` | ✓ | SPARC Solaris 11, illumos
-`thumbv6m-none-eabi` | * | Bare ARMv6-M
-`thumbv7em-none-eabi` | * | Bare ARMv7E-M
-`thumbv7em-none-eabihf` | * | Bare ARMV7E-M, hardfloat
-`thumbv7m-none-eabi` | * | Bare ARMv7-M
+[`thumbv6m-none-eabi`](platform-support/arm-none-eabi.md) | * | Bare ARMv6-M
+[`thumbv7em-none-eabi`](platform-support/arm-none-eabi.md) | * | Bare ARMv7E-M
+[`thumbv7em-none-eabihf`](platform-support/arm-none-eabi.md) | * | Bare ARMV7E-M, hardfloat
+[`thumbv7m-none-eabi`](platform-support/arm-none-eabi.md) | * | Bare ARMv7-M
 [`thumbv7neon-linux-androideabi`](platform-support/android.md) | ✓ | Thumb2-mode ARMv7-A Android with NEON
 `thumbv7neon-unknown-linux-gnueabihf` | ✓ | Thumb2-mode ARMv7-A Linux with NEON (kernel 4.4, glibc 2.23)
-`thumbv8m.base-none-eabi` | * | Bare ARMv8-M Baseline
-`thumbv8m.main-none-eabi` | * | Bare ARMv8-M Mainline
-`thumbv8m.main-none-eabihf` | * | Bare ARMv8-M Mainline, hardfloat
+[`thumbv8m.base-none-eabi`](platform-support/arm-none-eabi.md) | * | Bare ARMv8-M Baseline
+[`thumbv8m.main-none-eabi`](platform-support/arm-none-eabi.md) | * | Bare ARMv8-M Mainline
+[`thumbv8m.main-none-eabihf`](platform-support/arm-none-eabi.md) | * | Bare ARMv8-M Mainline, hardfloat
 `wasm32-unknown-emscripten` | ✓ | WebAssembly via Emscripten
 `wasm32-unknown-unknown` | ✓ | WebAssembly
 `wasm32-wasi` | ✓ | WebAssembly with WASI
@@ -239,11 +239,11 @@ target | std | host | notes
 `aarch64_be-unknown-linux-gnu_ilp32` | ✓ | ✓ | ARM64 Linux (big-endian, ILP32 ABI)
 `aarch64_be-unknown-linux-gnu` | ✓ | ✓ | ARM64 Linux (big-endian)
 [`aarch64_be-unknown-netbsd`](platform-support/netbsd.md) | ✓ | ✓ | ARM64 NetBSD (big-endian)
-[`arm64_32-apple-watchos`](platform-support/apple-watchos.md) | ✓ | | ARM Apple WatchOS 64-bit with 32-bit pointers
+[`arm64_32-apple-watchos`](platform-support/apple-watchos.md) | ✓ |  | ARM Apple WatchOS 64-bit with 32-bit pointers
 [`armeb-unknown-linux-gnueabi`](platform-support/armeb-unknown-linux-gnueabi.md) | ✓ | ? | ARM BE8 the default ARM big-endian architecture since [ARMv6](https://developer.arm.com/documentation/101754/0616/armlink-Reference/armlink-Command-line-Options/--be8?lang=en).
-`armv4t-none-eabi` | * |  | Bare ARMv4T
+[`armv4t-none-eabi`](platform-support/armv4t-none-eabi.md) | * |  | Bare ARMv4T
 `armv4t-unknown-linux-gnueabi` | ? |  | ARMv4T Linux
-[`armv5te-none-eabi`](platform-support/armv5te-none-eabi.md) | * | | Bare ARMv5TE
+[`armv5te-none-eabi`](platform-support/armv5te-none-eabi.md) | * |  | Bare ARMv5TE
 `armv5te-unknown-linux-uclibceabi` | ? |  | ARMv5TE Linux with uClibc
 `armv6-unknown-freebsd` | ✓ | ✓ | ARMv6 FreeBSD
 [`armv6-unknown-netbsd-eabihf`](platform-support/netbsd.md) | ✓ | ✓ | ARMv6 NetBSD w/hard-float
@@ -257,8 +257,8 @@ target | std | host | notes
 `armv7-wrs-vxworks-eabihf` | ? |  | ARMv7-A for VxWorks
 [`armv7a-kmc-solid_asp3-eabi`](platform-support/kmc-solid.md) | ✓ |  | ARM SOLID with TOPPERS/ASP3
 [`armv7a-kmc-solid_asp3-eabihf`](platform-support/kmc-solid.md) | ✓ |  | ARM SOLID with TOPPERS/ASP3, hardfloat
-`armv7a-none-eabihf` | * | | Bare ARMv7-A, hardfloat
-[`armv7k-apple-watchos`](platform-support/apple-watchos.md) | ✓ | | ARMv7-A Apple WatchOS
+[`armv7a-none-eabihf`](platform-support/arm-none-eabi.md) | * |  | Bare ARMv7-A, hardfloat
+[`armv7k-apple-watchos`](platform-support/apple-watchos.md) | ✓ |  | ARMv7-A Apple WatchOS
 `armv7s-apple-ios` | ✓ |  | ARMv7-A Apple-A6 Apple iOS
 `avr-unknown-gnu-atmega328` | * |  | AVR. Requires `-Z build-std=core`
 `bpfeb-unknown-none` | * |  | BPF (big endian)
@@ -333,15 +333,15 @@ target | std | host | notes
 [`sparc-unknown-none-elf`](./platform-support/sparc-unknown-none-elf.md) | * |  | Bare 32-bit SPARC V7+
 [`sparc64-unknown-netbsd`](platform-support/netbsd.md) | ✓ | ✓ | NetBSD/sparc64
 [`sparc64-unknown-openbsd`](platform-support/openbsd.md) | ✓ | ✓ | OpenBSD/sparc64
-`thumbv4t-none-eabi` | * |  | Thumb-mode Bare ARMv4T
-[`thumbv5te-none-eabi`](platform-support/armv5te-none-eabi.md) | * | | Thumb-mode Bare ARMv5TE
+[`thumbv4t-none-eabi`](platform-support/armv4t-none-eabi.md) | * |  | Thumb-mode Bare ARMv4T
+[`thumbv5te-none-eabi`](platform-support/armv5te-none-eabi.md) | * |  | Thumb-mode Bare ARMv5TE
 `thumbv7a-pc-windows-msvc` | ? |  |
 `thumbv7a-uwp-windows-msvc` | ✓ |  |
 `thumbv7neon-unknown-linux-musleabihf` | ? |  | Thumb2-mode ARMv7-A Linux with NEON, MUSL
 [`wasm64-unknown-unknown`](platform-support/wasm64-unknown-unknown.md) | ? |  | WebAssembly
 `x86_64-apple-ios-macabi` | ✓ |  | Apple Catalyst on x86_64
-[`x86_64-apple-tvos`](platform-support/apple-tvos.md) | ? | | x86 64-bit tvOS
-[`x86_64-apple-watchos-sim`](platform-support/apple-watchos.md) | ✓ | | x86 64-bit Apple WatchOS simulator
+[`x86_64-apple-tvos`](platform-support/apple-tvos.md) | ? |  | x86 64-bit tvOS
+[`x86_64-apple-watchos-sim`](platform-support/apple-watchos.md) | ✓ |  | x86 64-bit Apple WatchOS simulator
 [`x86_64-pc-nto-qnx710`](platform-support/nto-qnx.md) | ✓ |  | x86 64-bit QNX Neutrino 7.1 RTOS |
 [`x86_64-pc-windows-gnullvm`](platform-support/pc-windows-gnullvm.md) | ✓ | ✓ |
 `x86_64-pc-windows-msvc` | * |  | 64-bit Windows XP support
diff --git a/src/doc/rustc/src/platform-support/arm-none-eabi.md b/src/doc/rustc/src/platform-support/arm-none-eabi.md
new file mode 100644
index 00000000000..4f76d0d7bbc
--- /dev/null
+++ b/src/doc/rustc/src/platform-support/arm-none-eabi.md
@@ -0,0 +1,96 @@
+# `{arm,thumb}*-none-eabi(hf)?`
+
+**Tier: 2**
+- [arm(eb)?v7r-none-eabi(hf)?](armv7r-none-eabi.md)
+- armv7a-none-eabi
+- thumbv6m-none-eabi
+- thumbv7m-none-eabi
+- thumbv7em-none-eabi(hf)?
+- thumbv8m.base-none-eabi
+- thumbv8m.main-none-eabi(hf)?
+
+**Tier: 3**
+- [{arm,thumb}v4t-none-eabi](armv4t-none-eabi.md)
+- [{arm,thumb}v5te-none-eabi](armv5te-none-eabi.md)
+- armv7a-none-eabihf
+
+Bare-metal target for 32-bit ARM CPUs.
+
+If a target has a `*hf` variant, that variant uses the hardware floating-point
+ABI and enables some minimum set of floating-point features based on the FPU(s)
+available in that processor family.
+
+## Requirements
+
+These targets are cross-compiled and use static linking.
+
+By default, the `lld` linker included with Rust will be used; however, you may
+want to use the GNU linker instead. This can be obtained for Windows/Mac/Linux
+from the [Arm Developer Website][arm-gnu-toolchain], or possibly from your OS's
+package manager. To use it, add the following to your `.cargo/config.toml`:
+
+```toml
+[target.<your-target>]
+linker = "arm-none-eabi-ld"
+```
+
+The GNU linker can also be used by specifying `arm-none-eabi-gcc` as the
+linker. This is needed when using GCC's link time optimization.
+
+[arm-gnu-toolchain]: https://developer.arm.com/Tools%20and%20Software/GNU%20Toolchain
+
+These targets don't provide a linker script, so you'll need to bring your own
+according to the specific device you are using. Pass
+`-Clink-arg=-Tyour_script.ld` as a rustc argument to make the linker use
+`your_script.ld` during linking.
+
+Targets named `thumb*` instead of `arm*`
+generate Thumb-mode code by default. M-profile processors (`thumbv*m*-*`
+targets) only support Thumb-mode code.
+For the `arm*` targets, Thumb-mode code generation can be enabled by using
+`-C target-feature=+thumb-mode`. Using the unstable
+`#![feature(arm_target_feature)]`, the attribute
+`#[target_feature(enable = "thumb-mode")]` can be applied to individual
+`unsafe` functions to cause those functions to be compiled to Thumb-mode code.
+
+## Building Rust Programs
+
+For the Tier 3 targets in this family, rust does not ship pre-compiled
+artifacts.
+
+Just use the `build-std` nightly cargo feature to build the `core` library. You
+can pass this as a command line argument to cargo, or your `.cargo/config.toml`
+file might include the following lines:
+
+```toml
+[unstable]
+build-std = ["core"]
+```
+
+Most of `core` should work as expected, with the following notes:
+* If the target is not `*hf`, then floating-point operations are emulated in
+  software.
+* Integer division is also emulated in software on some targets, depending on
+  the CPU.
+* Architectures prior to ARMv7 don't have atomic instructions.
+
+`alloc` is also supported, as long as you provide your own global allocator.
+
+Rust programs are output as ELF files.
+
+## Testing
+
+This is a cross-compiled target that you will need to emulate during testing.
+
+The exact emulator that you'll need depends on the specific device you want to
+run your code on.
+
+## Cross-compilation toolchains and C code
+
+The target supports C code compiled with the `arm-none-eabi` target triple and
+a suitable `-march` or `-mcpu` flag.
+
+`gcc` or `clang` can be used, but note that `gcc` uses `-fshort-enums` by
+default for `arm-none*` targets, while `clang` does not. `rustc` matches the
+`gcc` behavior, i.e., the size of a `#[repr(C)] enum` in Rust can be as little
+as 1 byte, rather than 4, as they are on `arm-linux` targets.
diff --git a/src/doc/rustc/src/platform-support/armv4t-none-eabi.md b/src/doc/rustc/src/platform-support/armv4t-none-eabi.md
index a230eba6bf9..29c47db8351 100644
--- a/src/doc/rustc/src/platform-support/armv4t-none-eabi.md
+++ b/src/doc/rustc/src/platform-support/armv4t-none-eabi.md
@@ -6,51 +6,16 @@ Bare-metal target for any cpu in the ARMv4T architecture family, supporting
 ARM/Thumb code interworking (aka `a32`/`t32`), with ARM code as the default code
 generation.
 
-In particular this supports the Gameboy Advance (GBA), but there's nothing GBA
-specific with this target, so any ARMv4T device should work fine.
+In particular this supports the Game Boy Advance (GBA), but there's nothing
+GBA-specific with this target, so any ARMv4T device should work fine.
+
+See [`arm-none-eabi`](arm-none-eabi.md) for information applicable to all
+`arm-none-eabi` targets.
 
 ## Target Maintainers
 
 * [@Lokathor](https://github.com/lokathor)
 
-## Requirements
-
-The target is cross-compiled, and uses static linking.
-
-This target doesn't provide a linker script, you'll need to bring your own
-according to the specific device you want to target. Pass
-`-Clink-arg=-Tyour_script.ld` as a rustc argument to make the linker use
-`your_script.ld` during linking.
-
-## Building Rust Programs
-
-Because it is Tier 3, rust does not yet ship pre-compiled artifacts for this target.
-
-Just use the `build-std` nightly cargo feature to build the `core` library. You
-can pass this as a command line argument to cargo, or your `.cargo/config.toml`
-file might include the following lines:
-
-```toml
-[unstable]
-build-std = ["core"]
-```
-
-Most of `core` should work as expected, with the following notes:
-* the target is "soft float", so `f32` and `f64` operations are emulated in
-  software.
-* integer division is also emulated in software.
-* the target is old enough that it doesn't have atomic instructions.
-
-Rust programs are output as ELF files.
-
-For running on hardware, you'll generally need to extract the "raw" program code
-out of the ELF and into a file of its own. The `objcopy` program provided as
-part of the GNU Binutils can do this:
-
-```shell
-arm-none-eabi-objcopy --output-target binary [in_file] [out_file]
-```
-
 ## Testing
 
 This is a cross-compiled target that you will need to emulate during testing.
diff --git a/src/doc/rustc/src/platform-support/armv5te-none-eabi.md b/src/doc/rustc/src/platform-support/armv5te-none-eabi.md
index f469dab1c42..37284ba7209 100644
--- a/src/doc/rustc/src/platform-support/armv5te-none-eabi.md
+++ b/src/doc/rustc/src/platform-support/armv5te-none-eabi.md
@@ -8,54 +8,13 @@ generation.
 
 The `thumbv5te-none-eabi` target is the same as this one, but the instruction set defaults to `t32`.
 
+See [`arm-none-eabi`](arm-none-eabi.md) for information applicable to all
+`arm-none-eabi` targets.
+
 ## Target Maintainers
 
 * [@QuinnPainter](https://github.com/QuinnPainter)
 
-## Requirements
-
-The target is cross-compiled, and uses static linking.
-
-By default, the `lld` linker included with Rust will be used.
-
-However, you may want to use the `arm-none-eabi-ld` linker instead. This can be obtained for Windows/Mac/Linux from the [ARM
-Developer Website][arm-dev], or possibly from your OS's package manager. To use it, add the following to your `.cargo/config.toml`:
-
-```toml
-[target.armv5te-none-eabi]
-linker = "arm-none-eabi-ld"
-```
-
-[arm-dev]: https://developer.arm.com/Tools%20and%20Software/GNU%20Toolchain
-
-This target doesn't provide a linker script, you'll need to bring your own
-according to the specific device you want to target. Pass
-`-Clink-arg=-Tyour_script.ld` as a rustc argument to make the linker use
-`your_script.ld` during linking.
-
-## Building Rust Programs
-
-Because it is Tier 3, rust does not yet ship pre-compiled artifacts for this target.
-
-Just use the `build-std` nightly cargo feature to build the `core` library. You
-can pass this as a command line argument to cargo, or your `.cargo/config.toml`
-file might include the following lines:
-
-```toml
-[unstable]
-build-std = ["core"]
-```
-
-Most of `core` should work as expected, with the following notes:
-* the target is "soft float", so `f32` and `f64` operations are emulated in
-  software.
-* integer division is also emulated in software.
-* the target is old enough that it doesn't have atomic instructions.
-
-`alloc` is also supported, as long as you provide your own global allocator.
-
-Rust programs are output as ELF files.
-
 ## Testing
 
 This is a cross-compiled target that you will need to emulate during testing.
@@ -63,4 +22,5 @@ This is a cross-compiled target that you will need to emulate during testing.
 Because this is a device-agnostic target, and the exact emulator that you'll
 need depends on the specific device you want to run your code on.
 
-For example, when programming for the DS, you can use one of the several available DS emulators, such as [melonDS](https://melonds.kuribo64.net/).
+For example, when programming for the DS, you can use one of the several
+available DS emulators, such as [melonDS](https://melonds.kuribo64.net/).
diff --git a/src/doc/rustc/src/platform-support/armv7r-none-eabi.md b/src/doc/rustc/src/platform-support/armv7r-none-eabi.md
new file mode 100644
index 00000000000..670cead9e00
--- /dev/null
+++ b/src/doc/rustc/src/platform-support/armv7r-none-eabi.md
@@ -0,0 +1,47 @@
+# `arm(eb)?v7r-none-eabi(hf)?`
+
+**Tier: 2**
+
+Bare-metal target for CPUs in the ARMv7-R architecture family, supporting
+dual ARM/Thumb mode, with ARM mode as the default.
+
+Processors in this family include the [Arm Cortex-R4, 5, 7, and 8][cortex-r].
+
+The `eb` versions of this target generate code for big-endian processors.
+
+See [`arm-none-eabi`](arm-none-eabi.md) for information applicable to all
+`arm-none-eabi` targets.
+
+[cortex-r]: https://en.wikipedia.org/wiki/ARM_Cortex-R
+
+## Target maintainers
+
+- [Chris Copeland](https://github.com/chrisnc), `chris@chrisnc.net`
+
+## Requirements
+
+When using the big-endian version of this target, note that some variants of
+the Cortex-R have both big-endian instructions and data. This configuration is
+known as BE-32, while data-only big-endianness is known as BE-8. To build
+programs for BE-32 processors, the GNU linker must be used with the `-mbe32`
+option. See [ARM Cortex-R Series Programmer's Guide: Endianness][endianness]
+for more details about different endian modes.
+
+When using the hardfloat targets, the minimum floating-point features assumed
+are those of the `vfpv3-d16`, which includes single- and double-precision, with
+16 double-precision registers. This floating-point unit appears in Cortex-R4F
+and Cortex-R5F processors. See [VFP in the Cortex-R processors][vfp]
+for more details on the possible FPU variants.
+
+If your processor supports a different set of floating-point features than the
+default expectations of `vfpv3-d16`, then these should also be enabled or
+disabled as needed with `-C target-feature=(+/-)`.
+
+[endianness]: https://developer.arm.com/documentation/den0042/a/Coding-for-Cortex-R-Processors/Endianness
+
+[vfp]: https://developer.arm.com/documentation/den0042/a/Floating-Point/Floating-point-basics-and-the-IEEE-754-standard/VFP-in-the-Cortex-R-processors
+
+## Cross-compilation toolchains and C code
+
+This target supports C code compiled with the `arm-none-eabi` target triple and
+`-march=armv7-r` or a suitable `-mcpu` flag.
diff --git a/tests/incremental/thinlto/cgu_invalidated_via_import.rs b/tests/incremental/thinlto/cgu_invalidated_via_import.rs
index e0cd385eff3..a81b4f7e9d0 100644
--- a/tests/incremental/thinlto/cgu_invalidated_via_import.rs
+++ b/tests/incremental/thinlto/cgu_invalidated_via_import.rs
@@ -14,14 +14,14 @@
                             kind="no")]
 #![rustc_expected_cgu_reuse(module="cgu_invalidated_via_import-foo",
                             cfg="cfail3",
-                            kind="post-lto")]
+                            kind="pre-lto")] // Should be "post-lto", see issue #119076
 
 #![rustc_expected_cgu_reuse(module="cgu_invalidated_via_import-bar",
                             cfg="cfail2",
                             kind="pre-lto")]
 #![rustc_expected_cgu_reuse(module="cgu_invalidated_via_import-bar",
                             cfg="cfail3",
-                            kind="post-lto")]
+                            kind="pre-lto")] // Should be "post-lto", see issue #119076
 
 mod foo {
 
diff --git a/tests/incremental/thinlto/cgu_keeps_identical_fn.rs b/tests/incremental/thinlto/cgu_keeps_identical_fn.rs
index 781aae578d4..9e840f67ab2 100644
--- a/tests/incremental/thinlto/cgu_keeps_identical_fn.rs
+++ b/tests/incremental/thinlto/cgu_keeps_identical_fn.rs
@@ -9,21 +9,25 @@
 
 #![feature(rustc_attrs)]
 #![crate_type = "rlib"]
-#![rustc_expected_cgu_reuse(module = "cgu_keeps_identical_fn-foo", cfg = "cfail2", kind = "no")]
+#![rustc_expected_cgu_reuse(
+    module = "cgu_keeps_identical_fn-foo",
+    cfg = "cfail2",
+    kind = "pre-lto"
+)]
 #![rustc_expected_cgu_reuse(
     module = "cgu_keeps_identical_fn-foo",
     cfg = "cfail3",
-    kind = "post-lto"
+    kind = "pre-lto" // Should be "post-lto", see issue #119076
 )]
 #![rustc_expected_cgu_reuse(
     module = "cgu_keeps_identical_fn-bar",
     cfg = "cfail2",
-    kind = "post-lto"
+    kind = "pre-lto" // Should be "post-lto", see issue #119076
 )]
 #![rustc_expected_cgu_reuse(
     module = "cgu_keeps_identical_fn-bar",
     cfg = "cfail3",
-    kind = "post-lto"
+    kind = "pre-lto" // Should be "post-lto", see issue #119076
 )]
 
 mod foo {
diff --git a/tests/incremental/thinlto/independent_cgus_dont_affect_each_other.rs b/tests/incremental/thinlto/independent_cgus_dont_affect_each_other.rs
index 8aa036ec978..45eb1382874 100644
--- a/tests/incremental/thinlto/independent_cgus_dont_affect_each_other.rs
+++ b/tests/incremental/thinlto/independent_cgus_dont_affect_each_other.rs
@@ -13,21 +13,21 @@
                             kind="no")]
 #![rustc_expected_cgu_reuse(module="independent_cgus_dont_affect_each_other-foo",
                             cfg="cfail3",
-                            kind="post-lto")]
+                            kind="pre-lto")] // Should be "post-lto", see issue #119076
 
 #![rustc_expected_cgu_reuse(module="independent_cgus_dont_affect_each_other-bar",
                             cfg="cfail2",
                             kind="pre-lto")]
 #![rustc_expected_cgu_reuse(module="independent_cgus_dont_affect_each_other-bar",
                             cfg="cfail3",
-                            kind="post-lto")]
+                            kind="pre-lto")] // Should be "post-lto", see issue #119076
 
 #![rustc_expected_cgu_reuse(module="independent_cgus_dont_affect_each_other-baz",
                             cfg="cfail2",
-                            kind="post-lto")]
+                            kind="pre-lto")] // Should be "post-lto", see issue #119076
 #![rustc_expected_cgu_reuse(module="independent_cgus_dont_affect_each_other-baz",
                             cfg="cfail3",
-                            kind="post-lto")]
+                            kind="pre-lto")] // Should be "post-lto", see issue #119076
 mod foo {
 
     #[cfg(cfail1)]
diff --git a/tests/ui-fulldeps/stable-mir/check_abi.rs b/tests/ui-fulldeps/stable-mir/check_abi.rs
new file mode 100644
index 00000000000..30b42bc3bfa
--- /dev/null
+++ b/tests/ui-fulldeps/stable-mir/check_abi.rs
@@ -0,0 +1,143 @@
+// run-pass
+//! Test information regarding type layout.
+
+// ignore-stage1
+// ignore-cross-compile
+// ignore-remote
+// ignore-windows-gnu mingw has troubles with linking https://github.com/rust-lang/rust/pull/116837
+
+#![feature(rustc_private)]
+#![feature(assert_matches)]
+#![feature(control_flow_enum)]
+#![feature(ascii_char, ascii_char_variants)]
+
+extern crate rustc_hir;
+extern crate rustc_middle;
+#[macro_use]
+extern crate rustc_smir;
+extern crate rustc_driver;
+extern crate rustc_interface;
+extern crate stable_mir;
+
+use rustc_middle::ty::TyCtxt;
+use rustc_smir::rustc_internal;
+use stable_mir::abi::{ArgAbi, CallConvention, FieldsShape, PassMode, VariantsShape};
+use stable_mir::mir::mono::Instance;
+use stable_mir::{CrateDef, CrateItem, CrateItems, ItemKind};
+use std::assert_matches::assert_matches;
+use std::convert::TryFrom;
+use std::io::Write;
+use std::ops::ControlFlow;
+
+const CRATE_NAME: &str = "input";
+
+/// This function uses the Stable MIR APIs to get information about the test crate.
+fn test_stable_mir(_tcx: TyCtxt<'_>) -> ControlFlow<()> {
+    // Find items in the local crate.
+    let items = stable_mir::all_local_items();
+
+    // Test fn_abi
+    let target_fn = *get_item(&items, (ItemKind::Fn, "fn_abi")).unwrap();
+    let instance = Instance::try_from(target_fn).unwrap();
+    let fn_abi = instance.fn_abi().unwrap();
+    assert_eq!(fn_abi.conv, CallConvention::Rust);
+    assert_eq!(fn_abi.args.len(), 2);
+
+    check_ignore(&fn_abi.args[0]);
+    check_primitive(&fn_abi.args[1]);
+    check_result(fn_abi.ret);
+
+    // Test variadic function.
+    let variadic_fn = *get_item(&items, (ItemKind::Fn, "variadic_fn")).unwrap();
+    check_variadic(variadic_fn);
+
+    ControlFlow::Continue(())
+}
+
+/// Check the variadic function ABI:
+/// ```no_run
+/// pub unsafe extern "C" fn variadic_fn(n: usize, mut args: ...) -> usize {
+///     0
+/// }
+/// ```
+fn check_variadic(variadic_fn: CrateItem) {
+    let instance = Instance::try_from(variadic_fn).unwrap();
+    let abi = instance.fn_abi().unwrap();
+    assert!(abi.c_variadic);
+    assert_eq!(abi.args.len(), 1);
+}
+
+/// Check the argument to be ignored: `ignore: [u8; 0]`.
+fn check_ignore(abi: &ArgAbi) {
+    assert!(abi.ty.kind().is_array());
+    assert_eq!(abi.mode, PassMode::Ignore);
+    let layout = abi.layout.shape();
+    assert!(layout.is_sized());
+    assert!(layout.is_1zst());
+}
+
+/// Check the primitive argument: `primitive: char`.
+fn check_primitive(abi: &ArgAbi) {
+    assert!(abi.ty.kind().is_char());
+    assert_matches!(abi.mode, PassMode::Direct(_));
+    let layout = abi.layout.shape();
+    assert!(layout.is_sized());
+    assert!(!layout.is_1zst());
+    assert_matches!(layout.fields, FieldsShape::Primitive);
+}
+
+/// Check the return value: `Result<usize, &str>`.
+fn check_result(abi: ArgAbi) {
+    assert!(abi.ty.kind().is_enum());
+    assert_matches!(abi.mode, PassMode::Indirect { .. });
+    let layout = abi.layout.shape();
+    assert!(layout.is_sized());
+    assert_matches!(layout.fields, FieldsShape::Arbitrary { .. });
+    assert_matches!(layout.variants, VariantsShape::Multiple { .. })
+}
+
+fn get_item<'a>(
+    items: &'a CrateItems,
+    item: (ItemKind, &str),
+) -> Option<&'a stable_mir::CrateItem> {
+    items.iter().find(|crate_item| (item.0 == crate_item.kind()) && crate_item.name() == item.1)
+}
+
+/// This test will generate and analyze a dummy crate using the stable mir.
+/// For that, it will first write the dummy crate into a file.
+/// Then it will create a `StableMir` using custom arguments and then
+/// it will run the compiler.
+fn main() {
+    let path = "alloc_input.rs";
+    generate_input(&path).unwrap();
+    let args = vec![
+        "rustc".to_string(),
+        "--crate-type=lib".to_string(),
+        "--crate-name".to_string(),
+        CRATE_NAME.to_string(),
+        path.to_string(),
+    ];
+    run!(args, tcx, test_stable_mir(tcx)).unwrap();
+}
+
+fn generate_input(path: &str) -> std::io::Result<()> {
+    let mut file = std::fs::File::create(path)?;
+    write!(
+        file,
+        r#"
+        #![feature(c_variadic)]
+        #![allow(unused_variables)]
+
+        pub fn fn_abi(ignore: [u8; 0], primitive: char) -> Result<usize, &'static str> {{
+            // We only care about the signature.
+            todo!()
+        }}
+
+
+        pub unsafe extern "C" fn variadic_fn(n: usize, mut args: ...) -> usize {{
+            0
+        }}
+        "#
+    )?;
+    Ok(())
+}
diff --git a/tests/ui-fulldeps/stable-mir/check_allocation.rs b/tests/ui-fulldeps/stable-mir/check_allocation.rs
index 8554630e9c9..7ce3597206b 100644
--- a/tests/ui-fulldeps/stable-mir/check_allocation.rs
+++ b/tests/ui-fulldeps/stable-mir/check_allocation.rs
@@ -209,7 +209,6 @@ fn check_len(item: CrateItem) {
     assert_eq!(alloc.read_uint(), Ok(2));
 }
 
-// Use internal API to find a function in a crate.
 fn get_item<'a>(
     items: &'a CrateItems,
     item: (ItemKind, &str),
diff --git a/tests/ui-fulldeps/stable-mir/check_defs.rs b/tests/ui-fulldeps/stable-mir/check_defs.rs
index ad667511332..e9a2599d873 100644
--- a/tests/ui-fulldeps/stable-mir/check_defs.rs
+++ b/tests/ui-fulldeps/stable-mir/check_defs.rs
@@ -69,9 +69,9 @@ fn extract_elem_ty(ty: Ty) -> Ty {
 
 /// Check signature and type of `Vec::<u8>::new` and its generic version.
 fn test_vec_new(instance: mir::mono::Instance) {
-    let sig = instance.ty().kind().fn_sig().unwrap().skip_binder();
-    assert_matches!(sig.inputs(), &[]);
-    let elem_ty = extract_elem_ty(sig.output());
+    let sig = instance.fn_abi().unwrap();
+    assert_eq!(&sig.args, &[]);
+    let elem_ty = extract_elem_ty(sig.ret.ty);
     assert_matches!(elem_ty.kind(), TyKind::RigidTy(RigidTy::Uint(UintTy::U8)));
 
     // Get the signature for Vec::<T>::new.
diff --git a/tests/ui/editions/edition-cstr-2015-2018.rs b/tests/ui/editions/edition-cstr-2015-2018.rs
new file mode 100644
index 00000000000..4c35c48646a
--- /dev/null
+++ b/tests/ui/editions/edition-cstr-2015-2018.rs
@@ -0,0 +1,62 @@
+macro_rules! construct { ($x:ident) => { $x"str" } }
+    //~^ ERROR expected one of `!`, `.`, `::`, `;`, `?`, `{`, `}`, or an operator, found `"str"`
+    //~| NOTE expected one of 8 possible tokens
+
+macro_rules! contain { () => { c"str" } }
+    //~^ ERROR expected one of `!`, `.`, `::`, `;`, `?`, `{`, `}`, or an operator, found `"str"`
+    //~| NOTE expected one of 8 possible tokens
+    //~| NOTE you may be trying to write a c-string literal
+    //~| NOTE c-string literals require Rust 2021 or later
+    //~| HELP pass `--edition 2021` to `rustc`
+    //~| NOTE for more on editions, read https://doc.rust-lang.org/edition-guide
+
+fn check_macro_construct() {
+    construct!(c); //~ NOTE in this expansion of construct!
+}
+
+fn check_macro_contain() {
+    contain!();
+    //~^ NOTE in this expansion of contain!
+    //~| NOTE in this expansion of contain!
+    //~| NOTE in this expansion of contain!
+    //~| NOTE in this expansion of contain!
+    //~| NOTE in this expansion of contain!
+}
+
+fn check_basic() {
+    c"str";
+    //~^ ERROR expected one of `!`, `.`, `::`, `;`, `?`, `{`, `}`, or an operator, found `"str"`
+    //~| NOTE expected one of 8 possible tokens
+    //~| NOTE you may be trying to write a c-string literal
+    //~| NOTE c-string literals require Rust 2021 or later
+    //~| HELP pass `--edition 2021` to `rustc`
+    //~| NOTE for more on editions, read https://doc.rust-lang.org/edition-guide
+}
+
+fn check_craw() {
+    cr"str";
+    //~^ ERROR expected one of `!`, `.`, `::`, `;`, `?`, `{`, `}`, or an operator, found `"str"`
+    //~| NOTE expected one of 8 possible tokens
+    //~| NOTE you may be trying to write a c-string literal
+    //~| NOTE c-string literals require Rust 2021 or later
+    //~| HELP pass `--edition 2021` to `rustc`
+    //~| NOTE for more on editions, read https://doc.rust-lang.org/edition-guide
+}
+
+fn check_craw_hash() {
+    cr##"str"##;
+    //~^ ERROR expected one of `!`, `.`, `::`, `;`, `?`, `{`, `}`, or an operator, found `#`
+    //~| NOTE expected one of 8 possible tokens
+    //~| NOTE you may be trying to write a c-string literal
+    //~| NOTE c-string literals require Rust 2021 or later
+    //~| HELP pass `--edition 2021` to `rustc`
+    //~| NOTE for more on editions, read https://doc.rust-lang.org/edition-guide
+}
+
+fn check_cstr_space() {
+    c "str";
+    //~^ ERROR expected one of `!`, `.`, `::`, `;`, `?`, `{`, `}`, or an operator, found `"str"`
+    //~| NOTE expected one of 8 possible tokens
+}
+
+fn main() {}
diff --git a/tests/ui/editions/edition-cstr-2015-2018.stderr b/tests/ui/editions/edition-cstr-2015-2018.stderr
new file mode 100644
index 00000000000..b864df308ef
--- /dev/null
+++ b/tests/ui/editions/edition-cstr-2015-2018.stderr
@@ -0,0 +1,67 @@
+error: expected one of `!`, `.`, `::`, `;`, `?`, `{`, `}`, or an operator, found `"str"`
+  --> $DIR/edition-cstr-2015-2018.rs:27:6
+   |
+LL |     c"str";
+   |      ^^^^^ expected one of 8 possible tokens
+   |
+   = note: you may be trying to write a c-string literal
+   = note: c-string literals require Rust 2021 or later
+   = help: pass `--edition 2021` to `rustc`
+   = note: for more on editions, read https://doc.rust-lang.org/edition-guide
+
+error: expected one of `!`, `.`, `::`, `;`, `?`, `{`, `}`, or an operator, found `"str"`
+  --> $DIR/edition-cstr-2015-2018.rs:37:7
+   |
+LL |     cr"str";
+   |       ^^^^^ expected one of 8 possible tokens
+   |
+   = note: you may be trying to write a c-string literal
+   = note: c-string literals require Rust 2021 or later
+   = help: pass `--edition 2021` to `rustc`
+   = note: for more on editions, read https://doc.rust-lang.org/edition-guide
+
+error: expected one of `!`, `.`, `::`, `;`, `?`, `{`, `}`, or an operator, found `#`
+  --> $DIR/edition-cstr-2015-2018.rs:47:7
+   |
+LL |     cr##"str"##;
+   |       ^ expected one of 8 possible tokens
+   |
+   = note: you may be trying to write a c-string literal
+   = note: c-string literals require Rust 2021 or later
+   = help: pass `--edition 2021` to `rustc`
+   = note: for more on editions, read https://doc.rust-lang.org/edition-guide
+
+error: expected one of `!`, `.`, `::`, `;`, `?`, `{`, `}`, or an operator, found `"str"`
+  --> $DIR/edition-cstr-2015-2018.rs:57:7
+   |
+LL |     c "str";
+   |       ^^^^^ expected one of 8 possible tokens
+
+error: expected one of `!`, `.`, `::`, `;`, `?`, `{`, `}`, or an operator, found `"str"`
+  --> $DIR/edition-cstr-2015-2018.rs:1:44
+   |
+LL | macro_rules! construct { ($x:ident) => { $x"str" } }
+   |                                            ^^^^^ expected one of 8 possible tokens
+...
+LL |     construct!(c);
+   |     ------------- in this macro invocation
+   |
+   = note: this error originates in the macro `construct` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error: expected one of `!`, `.`, `::`, `;`, `?`, `{`, `}`, or an operator, found `"str"`
+  --> $DIR/edition-cstr-2015-2018.rs:5:33
+   |
+LL | macro_rules! contain { () => { c"str" } }
+   |                                 ^^^^^ expected one of 8 possible tokens
+...
+LL |     contain!();
+   |     ---------- in this macro invocation
+   |
+   = note: you may be trying to write a c-string literal
+   = note: c-string literals require Rust 2021 or later
+   = help: pass `--edition 2021` to `rustc`
+   = note: for more on editions, read https://doc.rust-lang.org/edition-guide
+   = note: this error originates in the macro `contain` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error: aborting due to 6 previous errors
+
diff --git a/tests/ui/traits/issue-90662-projection-caching.rs b/tests/ui/traits/issue-90662-projection-caching.rs
index 879f30071bf..e08ab53fbb0 100644
--- a/tests/ui/traits/issue-90662-projection-caching.rs
+++ b/tests/ui/traits/issue-90662-projection-caching.rs
@@ -1,7 +1,15 @@
+// revisions: old next
+//[next] compile-flags: -Znext-solver=coherence
 // check-pass
 
 // Regression test for issue #90662
-// Tests that projection caching does not cause a spurious error
+// Tests that projection caching does not cause a spurious error.
+// Coherence relies on the following overflowing goal to still constrain
+// `?0` to `dyn Service`.
+//
+//     Projection(<ServiceImpl as Provider<TestModule>>::Interface. ?0)
+//
+// cc https://github.com/rust-lang/trait-system-refactor-initiative/issues/70.
 
 trait HasProvider<T: ?Sized> {}
 trait Provider<M> {
diff --git a/tests/ui/traits/next-solver/overflow/recursion-limit-normalizes-to-constraints.rs b/tests/ui/traits/next-solver/overflow/recursion-limit-normalizes-to-constraints.rs
new file mode 100644
index 00000000000..03ef93dc233
--- /dev/null
+++ b/tests/ui/traits/next-solver/overflow/recursion-limit-normalizes-to-constraints.rs
@@ -0,0 +1,25 @@
+// compile-flags: -Znext-solver=coherence
+// check-pass
+
+// A regression test for trait-system-refactor-initiative#70.
+
+trait Trait {
+    type Assoc;
+}
+
+struct W<T: ?Sized>(*mut T);
+impl<T: ?Sized> Trait for W<W<T>>
+where
+    W<T>: Trait,
+{
+    type Assoc = ();
+}
+
+trait NoOverlap {}
+impl<T: Trait<Assoc = u32>> NoOverlap for T {}
+// `Projection(<W<_> as Trait>::Assoc, u32)` should result in error even
+// though applying the impl results in overflow. This is necessary to match
+// the behavior of the old solver.
+impl<T: ?Sized> NoOverlap for W<T> {}
+
+fn main() {}