about summary refs log tree commit diff
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2024-12-03 09:47:39 +0000
committerbors <bors@rust-lang.org>2024-12-03 09:47:39 +0000
commitae3703cdf271b07cbc7cbaeda0ea8ab6bba60160 (patch)
tree877a715e925340171b87e61918a7cbcf1c7770c6
parentefdd9e802053caeb52103945df858e87f837e59a (diff)
parent8ae11145cefdd3cf3fe693ca871a29c91050ab82 (diff)
downloadrust-ae3703cdf271b07cbc7cbaeda0ea8ab6bba60160.tar.gz
rust-ae3703cdf271b07cbc7cbaeda0ea8ab6bba60160.zip
Auto merge of #133788 - matthiaskrgr:rollup-1p100a8, r=matthiaskrgr
Rollup of 6 pull requests

Successful merges:

 - #132723 (Unify `sysroot_target_{bin,lib}dir` handling)
 - #133041 (Print name of env var in `--print=deployment-target`)
 - #133325 (Reimplement `~const` trait specialization)
 - #133395 (Add simd_relaxed_fma intrinsic)
 - #133517 (Deeply normalize when computing implied outlives bounds)
 - #133785 (Add const evaluation error UI test.)

r? `@ghost`
`@rustbot` modify labels: rollup
-rw-r--r--compiler/rustc_codegen_cranelift/src/intrinsics/simd.rs3
-rw-r--r--compiler/rustc_codegen_gcc/src/intrinsic/simd.rs1
-rw-r--r--compiler/rustc_codegen_llvm/src/intrinsic.rs2
-rw-r--r--compiler/rustc_codegen_ssa/src/back/apple.rs2
-rw-r--r--compiler/rustc_data_structures/src/obligation_forest/mod.rs4
-rw-r--r--compiler/rustc_driver_impl/src/lib.rs5
-rw-r--r--compiler/rustc_hir_analysis/messages.ftl2
-rw-r--r--compiler/rustc_hir_analysis/src/check/intrinsic.rs4
-rw-r--r--compiler/rustc_hir_analysis/src/check/wfcheck.rs3
-rw-r--r--compiler/rustc_hir_analysis/src/errors.rs7
-rw-r--r--compiler/rustc_hir_analysis/src/impl_wf_check/min_specialization.rs26
-rw-r--r--compiler/rustc_infer/src/traits/engine.rs2
-rw-r--r--compiler/rustc_span/src/symbol.rs1
-rw-r--r--compiler/rustc_trait_selection/src/solve/fulfill.rs4
-rw-r--r--compiler/rustc_trait_selection/src/traits/fulfill.rs4
-rw-r--r--compiler/rustc_trait_selection/src/traits/normalize.rs11
-rw-r--r--compiler/rustc_trait_selection/src/traits/query/type_op/implied_outlives_bounds.rs10
-rw-r--r--compiler/rustc_trait_selection/src/traits/specialize/mod.rs150
-rw-r--r--library/core/src/intrinsics/simd.rs14
-rw-r--r--src/bootstrap/src/core/builder/mod.rs95
-rw-r--r--src/bootstrap/src/core/builder/tests.rs46
-rw-r--r--tests/run-make/apple-deployment-target/rmake.rs34
-rw-r--r--tests/run-make/apple-sdk-version/rmake.rs3
-rw-r--r--tests/ui/consts/const-eval-fail-too-big.rs12
-rw-r--r--tests/ui/consts/const-eval-fail-too-big.stderr9
-rw-r--r--tests/ui/higher-ranked/structually-relate-aliases.rs1
-rw-r--r--tests/ui/higher-ranked/structually-relate-aliases.stderr13
-rw-r--r--tests/ui/impl-trait/in-trait/alias-bounds-when-not-wf.stderr4
-rw-r--r--tests/ui/print-request/macos-target.rs1
-rw-r--r--tests/ui/print-request/macos-target.stdout2
-rw-r--r--tests/ui/simd/intrinsic/float-math-pass.rs4
-rw-r--r--tests/ui/traits/const-traits/overlap-const-with-nonconst.min_spec.stderr14
-rw-r--r--tests/ui/traits/const-traits/overlap-const-with-nonconst.rs38
-rw-r--r--tests/ui/traits/const-traits/overlap-const-with-nonconst.spec.stderr24
-rw-r--r--tests/ui/traits/const-traits/specialization/const-default-bound-non-const-specialized-bound.stderr26
-rw-r--r--tests/ui/traits/const-traits/specialization/const-default-impl-non-const-specialized-impl.min_spec.stderr12
-rw-r--r--tests/ui/traits/const-traits/specialization/const-default-impl-non-const-specialized-impl.rs8
-rw-r--r--tests/ui/traits/const-traits/specialization/const-default-impl-non-const-specialized-impl.spec.stderr22
-rw-r--r--tests/ui/traits/const-traits/specialization/const-default-impl-non-const-specialized-impl.stderr8
-rw-r--r--tests/ui/traits/const-traits/specializing-constness.rs3
-rw-r--r--tests/ui/traits/const-traits/specializing-constness.stderr8
-rw-r--r--tests/ui/traits/next-solver/issue-118950-root-region.rs2
-rw-r--r--tests/ui/traits/next-solver/issue-118950-root-region.stderr13
-rw-r--r--tests/ui/traits/next-solver/normalize-in-implied_outlives_bounds.rs46
44 files changed, 535 insertions, 168 deletions
diff --git a/compiler/rustc_codegen_cranelift/src/intrinsics/simd.rs b/compiler/rustc_codegen_cranelift/src/intrinsics/simd.rs
index f787b8a6fd9..e0ebe30752a 100644
--- a/compiler/rustc_codegen_cranelift/src/intrinsics/simd.rs
+++ b/compiler/rustc_codegen_cranelift/src/intrinsics/simd.rs
@@ -415,7 +415,8 @@ pub(super) fn codegen_simd_intrinsic_call<'tcx>(
             });
         }
 
-        sym::simd_fma => {
+        // FIXME: simd_relaxed_fma doesn't relax to non-fused multiply-add
+        sym::simd_fma | sym::simd_relaxed_fma => {
             intrinsic_args!(fx, args => (a, b, c); intrinsic);
 
             if !a.layout().ty.is_simd() {
diff --git a/compiler/rustc_codegen_gcc/src/intrinsic/simd.rs b/compiler/rustc_codegen_gcc/src/intrinsic/simd.rs
index 604678a9af4..79d1a06dd46 100644
--- a/compiler/rustc_codegen_gcc/src/intrinsic/simd.rs
+++ b/compiler/rustc_codegen_gcc/src/intrinsic/simd.rs
@@ -772,6 +772,7 @@ pub fn generic_simd_intrinsic<'a, 'gcc, 'tcx>(
             sym::simd_flog => "log",
             sym::simd_floor => "floor",
             sym::simd_fma => "fma",
+            sym::simd_relaxed_fma => "fma", // FIXME: this should relax to non-fused multiply-add when necessary
             sym::simd_fpowi => "__builtin_powi",
             sym::simd_fpow => "pow",
             sym::simd_fsin => "sin",
diff --git a/compiler/rustc_codegen_llvm/src/intrinsic.rs b/compiler/rustc_codegen_llvm/src/intrinsic.rs
index da7f94e8cf7..d8b055137b3 100644
--- a/compiler/rustc_codegen_llvm/src/intrinsic.rs
+++ b/compiler/rustc_codegen_llvm/src/intrinsic.rs
@@ -1534,6 +1534,7 @@ fn generic_simd_intrinsic<'ll, 'tcx>(
             sym::simd_flog => ("log", bx.type_func(&[vec_ty], vec_ty)),
             sym::simd_floor => ("floor", bx.type_func(&[vec_ty], vec_ty)),
             sym::simd_fma => ("fma", bx.type_func(&[vec_ty, vec_ty, vec_ty], vec_ty)),
+            sym::simd_relaxed_fma => ("fmuladd", bx.type_func(&[vec_ty, vec_ty, vec_ty], vec_ty)),
             sym::simd_fpowi => ("powi", bx.type_func(&[vec_ty, bx.type_i32()], vec_ty)),
             sym::simd_fpow => ("pow", bx.type_func(&[vec_ty, vec_ty], vec_ty)),
             sym::simd_fsin => ("sin", bx.type_func(&[vec_ty], vec_ty)),
@@ -1572,6 +1573,7 @@ fn generic_simd_intrinsic<'ll, 'tcx>(
             | sym::simd_fpowi
             | sym::simd_fsin
             | sym::simd_fsqrt
+            | sym::simd_relaxed_fma
             | sym::simd_round
             | sym::simd_trunc
     ) {
diff --git a/compiler/rustc_codegen_ssa/src/back/apple.rs b/compiler/rustc_codegen_ssa/src/back/apple.rs
index 93d90cd16b2..d9c5c3e5af9 100644
--- a/compiler/rustc_codegen_ssa/src/back/apple.rs
+++ b/compiler/rustc_codegen_ssa/src/back/apple.rs
@@ -97,7 +97,7 @@ fn minimum_deployment_target(target: &Target) -> OSVersion {
 }
 
 /// Name of the environment variable used to fetch the deployment target on the given OS.
-fn deployment_target_env_var(os: &str) -> &'static str {
+pub fn deployment_target_env_var(os: &str) -> &'static str {
     match os {
         "macos" => "MACOSX_DEPLOYMENT_TARGET",
         "ios" => "IPHONEOS_DEPLOYMENT_TARGET",
diff --git a/compiler/rustc_data_structures/src/obligation_forest/mod.rs b/compiler/rustc_data_structures/src/obligation_forest/mod.rs
index 34a2464972a..78d69a66edc 100644
--- a/compiler/rustc_data_structures/src/obligation_forest/mod.rs
+++ b/compiler/rustc_data_structures/src/obligation_forest/mod.rs
@@ -415,6 +415,10 @@ impl<O: ForestObligation> ObligationForest<O> {
             .collect()
     }
 
+    pub fn has_pending_obligations(&self) -> bool {
+        self.nodes.iter().any(|node| node.state.get() == NodeState::Pending)
+    }
+
     fn insert_into_error_cache(&mut self, index: usize) {
         let node = &self.nodes[index];
         self.error_cache
diff --git a/compiler/rustc_driver_impl/src/lib.rs b/compiler/rustc_driver_impl/src/lib.rs
index 85eaae8a104..5b472bb9b81 100644
--- a/compiler/rustc_driver_impl/src/lib.rs
+++ b/compiler/rustc_driver_impl/src/lib.rs
@@ -867,8 +867,9 @@ fn print_crate_info(
             DeploymentTarget => {
                 if sess.target.is_like_osx {
                     println_info!(
-                        "deployment_target={}",
-                        apple::pretty_version(apple::deployment_target(sess))
+                        "{}={}",
+                        apple::deployment_target_env_var(&sess.target.os),
+                        apple::pretty_version(apple::deployment_target(sess)),
                     )
                 } else {
                     #[allow(rustc::diagnostic_outside_of_impl)]
diff --git a/compiler/rustc_hir_analysis/messages.ftl b/compiler/rustc_hir_analysis/messages.ftl
index cb658111392..070d63b48b7 100644
--- a/compiler/rustc_hir_analysis/messages.ftl
+++ b/compiler/rustc_hir_analysis/messages.ftl
@@ -113,8 +113,6 @@ hir_analysis_const_param_ty_impl_on_unsized =
     the trait `ConstParamTy` may not be implemented for this type
     .label = type is not `Sized`
 
-hir_analysis_const_specialize = cannot specialize on const impl with non-const impl
-
 hir_analysis_copy_impl_on_non_adt =
     the trait `Copy` cannot be implemented for this type
     .label = type is not a structure or enumeration
diff --git a/compiler/rustc_hir_analysis/src/check/intrinsic.rs b/compiler/rustc_hir_analysis/src/check/intrinsic.rs
index 3e33120901f..7434bbf180b 100644
--- a/compiler/rustc_hir_analysis/src/check/intrinsic.rs
+++ b/compiler/rustc_hir_analysis/src/check/intrinsic.rs
@@ -641,7 +641,9 @@ pub fn check_intrinsic_type(
             | sym::simd_round
             | sym::simd_trunc => (1, 0, vec![param(0)], param(0)),
             sym::simd_fpowi => (1, 0, vec![param(0), tcx.types.i32], param(0)),
-            sym::simd_fma => (1, 0, vec![param(0), param(0), param(0)], param(0)),
+            sym::simd_fma | sym::simd_relaxed_fma => {
+                (1, 0, vec![param(0), param(0), param(0)], param(0))
+            }
             sym::simd_gather => (3, 0, vec![param(0), param(1), param(2)], param(0)),
             sym::simd_masked_load => (3, 0, vec![param(0), param(1), param(2)], param(2)),
             sym::simd_masked_store => (3, 0, vec![param(0), param(1), param(2)], tcx.types.unit),
diff --git a/compiler/rustc_hir_analysis/src/check/wfcheck.rs b/compiler/rustc_hir_analysis/src/check/wfcheck.rs
index ed3ae1e12b9..2b33da3c49a 100644
--- a/compiler/rustc_hir_analysis/src/check/wfcheck.rs
+++ b/compiler/rustc_hir_analysis/src/check/wfcheck.rs
@@ -117,13 +117,12 @@ where
     }
     f(&mut wfcx)?;
 
-    let assumed_wf_types = wfcx.ocx.assumed_wf_types_and_report_errors(param_env, body_def_id)?;
-
     let errors = wfcx.select_all_or_error();
     if !errors.is_empty() {
         return Err(infcx.err_ctxt().report_fulfillment_errors(errors));
     }
 
+    let assumed_wf_types = wfcx.ocx.assumed_wf_types_and_report_errors(param_env, body_def_id)?;
     debug!(?assumed_wf_types);
 
     let infcx_compat = infcx.fork();
diff --git a/compiler/rustc_hir_analysis/src/errors.rs b/compiler/rustc_hir_analysis/src/errors.rs
index 51115b11e86..4142dcff226 100644
--- a/compiler/rustc_hir_analysis/src/errors.rs
+++ b/compiler/rustc_hir_analysis/src/errors.rs
@@ -1080,13 +1080,6 @@ pub(crate) struct EmptySpecialization {
 }
 
 #[derive(Diagnostic)]
-#[diag(hir_analysis_const_specialize)]
-pub(crate) struct ConstSpecialize {
-    #[primary_span]
-    pub span: Span,
-}
-
-#[derive(Diagnostic)]
 #[diag(hir_analysis_static_specialize)]
 pub(crate) struct StaticSpecialize {
     #[primary_span]
diff --git a/compiler/rustc_hir_analysis/src/impl_wf_check/min_specialization.rs b/compiler/rustc_hir_analysis/src/impl_wf_check/min_specialization.rs
index 246643d8074..ee55e1bc21a 100644
--- a/compiler/rustc_hir_analysis/src/impl_wf_check/min_specialization.rs
+++ b/compiler/rustc_hir_analysis/src/impl_wf_check/min_specialization.rs
@@ -66,7 +66,6 @@
 //! on traits with methods can.
 
 use rustc_data_structures::fx::FxHashSet;
-use rustc_hir as hir;
 use rustc_hir::def_id::{DefId, LocalDefId};
 use rustc_infer::infer::TyCtxtInferExt;
 use rustc_infer::infer::outlives::env::OutlivesEnvironment;
@@ -134,7 +133,6 @@ fn check_always_applicable(
         unconstrained_parent_impl_args(tcx, impl2_def_id, impl2_args)
     };
 
-    res = res.and(check_constness(tcx, impl1_def_id, impl2_node, span));
     res = res.and(check_static_lifetimes(tcx, &parent_args, span));
     res = res.and(check_duplicate_params(tcx, impl1_args, parent_args, span));
     res = res.and(check_predicates(tcx, impl1_def_id, impl1_args, impl2_node, impl2_args, span));
@@ -157,30 +155,6 @@ fn check_has_items(
     Ok(())
 }
 
-/// Check that the specializing impl `impl1` is at least as const as the base
-/// impl `impl2`
-fn check_constness(
-    tcx: TyCtxt<'_>,
-    impl1_def_id: LocalDefId,
-    impl2_node: Node,
-    span: Span,
-) -> Result<(), ErrorGuaranteed> {
-    if impl2_node.is_from_trait() {
-        // This isn't a specialization
-        return Ok(());
-    }
-
-    let impl1_constness = tcx.constness(impl1_def_id.to_def_id());
-    let impl2_constness = tcx.constness(impl2_node.def_id());
-
-    if let hir::Constness::Const = impl2_constness {
-        if let hir::Constness::NotConst = impl1_constness {
-            return Err(tcx.dcx().emit_err(errors::ConstSpecialize { span }));
-        }
-    }
-    Ok(())
-}
-
 /// Given a specializing impl `impl1`, and the base impl `impl2`, returns two
 /// generic parameters `(S1, S2)` that equate their trait references.
 /// The returned types are expressed in terms of the generics of `impl1`.
diff --git a/compiler/rustc_infer/src/traits/engine.rs b/compiler/rustc_infer/src/traits/engine.rs
index ba1516655b0..51282b900ed 100644
--- a/compiler/rustc_infer/src/traits/engine.rs
+++ b/compiler/rustc_infer/src/traits/engine.rs
@@ -84,6 +84,8 @@ pub trait TraitEngine<'tcx, E: 'tcx>: 'tcx {
         self.collect_remaining_errors(infcx)
     }
 
+    fn has_pending_obligations(&self) -> bool;
+
     fn pending_obligations(&self) -> PredicateObligations<'tcx>;
 
     /// Among all pending obligations, collect those are stalled on a inference variable which has
diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs
index e94c0a5ea6e..5fa8ce835ed 100644
--- a/compiler/rustc_span/src/symbol.rs
+++ b/compiler/rustc_span/src/symbol.rs
@@ -1844,6 +1844,7 @@ symbols! {
         simd_reduce_mul_unordered,
         simd_reduce_or,
         simd_reduce_xor,
+        simd_relaxed_fma,
         simd_rem,
         simd_round,
         simd_saturating_add,
diff --git a/compiler/rustc_trait_selection/src/solve/fulfill.rs b/compiler/rustc_trait_selection/src/solve/fulfill.rs
index 0f90c45d032..2b2623a050e 100644
--- a/compiler/rustc_trait_selection/src/solve/fulfill.rs
+++ b/compiler/rustc_trait_selection/src/solve/fulfill.rs
@@ -199,6 +199,10 @@ where
         errors
     }
 
+    fn has_pending_obligations(&self) -> bool {
+        !self.obligations.pending.is_empty() || !self.obligations.overflowed.is_empty()
+    }
+
     fn pending_obligations(&self) -> PredicateObligations<'tcx> {
         self.obligations.clone_pending()
     }
diff --git a/compiler/rustc_trait_selection/src/traits/fulfill.rs b/compiler/rustc_trait_selection/src/traits/fulfill.rs
index 03e483f555d..7529ee128f5 100644
--- a/compiler/rustc_trait_selection/src/traits/fulfill.rs
+++ b/compiler/rustc_trait_selection/src/traits/fulfill.rs
@@ -213,6 +213,10 @@ where
         }
     }
 
+    fn has_pending_obligations(&self) -> bool {
+        self.predicates.has_pending_obligations()
+    }
+
     fn pending_obligations(&self) -> PredicateObligations<'tcx> {
         self.predicates.map_pending_obligations(|o| o.obligation.clone())
     }
diff --git a/compiler/rustc_trait_selection/src/traits/normalize.rs b/compiler/rustc_trait_selection/src/traits/normalize.rs
index e99c5eacbd8..ad62b456ad4 100644
--- a/compiler/rustc_trait_selection/src/traits/normalize.rs
+++ b/compiler/rustc_trait_selection/src/traits/normalize.rs
@@ -7,6 +7,7 @@ use rustc_infer::traits::{
     FromSolverError, Normalized, Obligation, PredicateObligations, TraitEngine,
 };
 use rustc_macros::extension;
+use rustc_middle::span_bug;
 use rustc_middle::traits::{ObligationCause, ObligationCauseCode};
 use rustc_middle::ty::{
     self, Ty, TyCtxt, TypeFoldable, TypeFolder, TypeSuperFoldable, TypeVisitable, TypeVisitableExt,
@@ -63,10 +64,18 @@ impl<'tcx> At<'_, 'tcx> {
         if self.infcx.next_trait_solver() {
             crate::solve::deeply_normalize(self, value)
         } else {
+            if fulfill_cx.has_pending_obligations() {
+                let pending_obligations = fulfill_cx.pending_obligations();
+                span_bug!(
+                    pending_obligations[0].cause.span,
+                    "deeply_normalize should not be called with pending obligations: \
+                    {pending_obligations:#?}"
+                );
+            }
             let value = self
                 .normalize(value)
                 .into_value_registering_obligations(self.infcx, &mut *fulfill_cx);
-            let errors = fulfill_cx.select_where_possible(self.infcx);
+            let errors = fulfill_cx.select_all_or_error(self.infcx);
             let value = self.infcx.resolve_vars_if_possible(value);
             if errors.is_empty() { Ok(value) } else { Err(errors) }
         }
diff --git a/compiler/rustc_trait_selection/src/traits/query/type_op/implied_outlives_bounds.rs b/compiler/rustc_trait_selection/src/traits/query/type_op/implied_outlives_bounds.rs
index c6e41e57f0c..fe47e837dfb 100644
--- a/compiler/rustc_trait_selection/src/traits/query/type_op/implied_outlives_bounds.rs
+++ b/compiler/rustc_trait_selection/src/traits/query/type_op/implied_outlives_bounds.rs
@@ -59,12 +59,16 @@ pub fn compute_implied_outlives_bounds_inner<'tcx>(
     param_env: ty::ParamEnv<'tcx>,
     ty: Ty<'tcx>,
 ) -> Result<Vec<OutlivesBound<'tcx>>, NoSolution> {
-    let normalize_op = |ty| {
-        let ty = ocx.normalize(&ObligationCause::dummy(), param_env, ty);
+    let normalize_op = |ty| -> Result<_, NoSolution> {
+        // We must normalize the type so we can compute the right outlives components.
+        // for example, if we have some constrained param type like `T: Trait<Out = U>`,
+        // and we know that `&'a T::Out` is WF, then we want to imply `U: 'a`.
+        let ty = ocx
+            .deeply_normalize(&ObligationCause::dummy(), param_env, ty)
+            .map_err(|_| NoSolution)?;
         if !ocx.select_all_or_error().is_empty() {
             return Err(NoSolution);
         }
-        let ty = ocx.infcx.resolve_vars_if_possible(ty);
         let ty = OpportunisticRegionResolver::new(&ocx.infcx).fold_ty(ty);
         Ok(ty)
     };
diff --git a/compiler/rustc_trait_selection/src/traits/specialize/mod.rs b/compiler/rustc_trait_selection/src/traits/specialize/mod.rs
index a9cd705465e..1430cfae51f 100644
--- a/compiler/rustc_trait_selection/src/traits/specialize/mod.rs
+++ b/compiler/rustc_trait_selection/src/traits/specialize/mod.rs
@@ -15,6 +15,7 @@ use rustc_data_structures::fx::FxIndexSet;
 use rustc_errors::codes::*;
 use rustc_errors::{Diag, EmissionGuarantee};
 use rustc_hir::def_id::{DefId, LocalDefId};
+use rustc_infer::traits::Obligation;
 use rustc_middle::bug;
 use rustc_middle::query::LocalCrate;
 use rustc_middle::ty::print::PrintTraitRefExt as _;
@@ -224,21 +225,30 @@ pub(super) fn specialization_enabled_in(tcx: TyCtxt<'_>, _: LocalCrate) -> bool
     tcx.features().specialization() || tcx.features().min_specialization()
 }
 
-/// Is `impl1` a specialization of `impl2`?
+/// Is `specializing_impl_def_id` a specialization of `parent_impl_def_id`?
 ///
-/// Specialization is determined by the sets of types to which the impls apply;
-/// `impl1` specializes `impl2` if it applies to a subset of the types `impl2` applies
-/// to.
+/// For every type that could apply to `specializing_impl_def_id`, we prove that
+/// the `parent_impl_def_id` also applies (i.e. it has a valid impl header and
+/// its where-clauses hold).
+///
+/// For the purposes of const traits, we also check that the specializing
+/// impl is not more restrictive than the parent impl. That is, if the
+/// `parent_impl_def_id` is a const impl (conditionally based off of some `~const`
+/// bounds), then `specializing_impl_def_id` must also be const for the same
+/// set of types.
 #[instrument(skip(tcx), level = "debug")]
-pub(super) fn specializes(tcx: TyCtxt<'_>, (impl1_def_id, impl2_def_id): (DefId, DefId)) -> bool {
+pub(super) fn specializes(
+    tcx: TyCtxt<'_>,
+    (specializing_impl_def_id, parent_impl_def_id): (DefId, DefId),
+) -> bool {
     // We check that the specializing impl comes from a crate that has specialization enabled,
     // or if the specializing impl is marked with `allow_internal_unstable`.
     //
     // We don't really care if the specialized impl (the parent) is in a crate that has
     // specialization enabled, since it's not being specialized, and it's already been checked
     // for coherence.
-    if !tcx.specialization_enabled_in(impl1_def_id.krate) {
-        let span = tcx.def_span(impl1_def_id);
+    if !tcx.specialization_enabled_in(specializing_impl_def_id.krate) {
+        let span = tcx.def_span(specializing_impl_def_id);
         if !span.allows_unstable(sym::specialization)
             && !span.allows_unstable(sym::min_specialization)
         {
@@ -246,7 +256,7 @@ pub(super) fn specializes(tcx: TyCtxt<'_>, (impl1_def_id, impl2_def_id): (DefId,
         }
     }
 
-    let impl1_trait_header = tcx.impl_trait_header(impl1_def_id).unwrap();
+    let specializing_impl_trait_header = tcx.impl_trait_header(specializing_impl_def_id).unwrap();
 
     // We determine whether there's a subset relationship by:
     //
@@ -261,27 +271,123 @@ pub(super) fn specializes(tcx: TyCtxt<'_>, (impl1_def_id, impl2_def_id): (DefId,
     // See RFC 1210 for more details and justification.
 
     // Currently we do not allow e.g., a negative impl to specialize a positive one
-    if impl1_trait_header.polarity != tcx.impl_polarity(impl2_def_id) {
+    if specializing_impl_trait_header.polarity != tcx.impl_polarity(parent_impl_def_id) {
         return false;
     }
 
-    // create a parameter environment corresponding to an identity instantiation of impl1,
-    // i.e. the most generic instantiation of impl1.
-    let param_env = tcx.param_env(impl1_def_id);
+    // create a parameter environment corresponding to an identity instantiation of the specializing impl,
+    // i.e. the most generic instantiation of the specializing impl.
+    let param_env = tcx.param_env(specializing_impl_def_id);
 
-    // Create an infcx, taking the predicates of impl1 as assumptions:
+    // Create an infcx, taking the predicates of the specializing impl as assumptions:
     let infcx = tcx.infer_ctxt().build(TypingMode::non_body_analysis());
 
-    // Attempt to prove that impl2 applies, given all of the above.
-    fulfill_implication(
-        &infcx,
+    let specializing_impl_trait_ref =
+        specializing_impl_trait_header.trait_ref.instantiate_identity();
+    let cause = &ObligationCause::dummy();
+    debug!(
+        "fulfill_implication({:?}, trait_ref={:?} |- {:?} applies)",
+        param_env, specializing_impl_trait_ref, parent_impl_def_id
+    );
+
+    // Attempt to prove that the parent impl applies, given all of the above.
+
+    let ocx = ObligationCtxt::new(&infcx);
+    let specializing_impl_trait_ref = ocx.normalize(cause, param_env, specializing_impl_trait_ref);
+
+    if !ocx.select_all_or_error().is_empty() {
+        infcx.dcx().span_delayed_bug(
+            infcx.tcx.def_span(specializing_impl_def_id),
+            format!("failed to fully normalize {specializing_impl_trait_ref}"),
+        );
+        return false;
+    }
+
+    let parent_args = infcx.fresh_args_for_item(DUMMY_SP, parent_impl_def_id);
+    let parent_impl_trait_ref = ocx.normalize(
+        cause,
         param_env,
-        impl1_trait_header.trait_ref.instantiate_identity(),
-        impl1_def_id,
-        impl2_def_id,
-        &ObligationCause::dummy(),
-    )
-    .is_ok()
+        infcx
+            .tcx
+            .impl_trait_ref(parent_impl_def_id)
+            .expect("expected source impl to be a trait impl")
+            .instantiate(infcx.tcx, parent_args),
+    );
+
+    // do the impls unify? If not, no specialization.
+    let Ok(()) = ocx.eq(cause, param_env, specializing_impl_trait_ref, parent_impl_trait_ref)
+    else {
+        return false;
+    };
+
+    // Now check that the source trait ref satisfies all the where clauses of the target impl.
+    // This is not just for correctness; we also need this to constrain any params that may
+    // only be referenced via projection predicates.
+    let predicates = ocx.normalize(
+        cause,
+        param_env,
+        infcx.tcx.predicates_of(parent_impl_def_id).instantiate(infcx.tcx, parent_args),
+    );
+    let obligations = predicates_for_generics(|_, _| cause.clone(), param_env, predicates);
+    ocx.register_obligations(obligations);
+
+    let errors = ocx.select_all_or_error();
+    if !errors.is_empty() {
+        // no dice!
+        debug!(
+            "fulfill_implication: for impls on {:?} and {:?}, \
+                 could not fulfill: {:?} given {:?}",
+            specializing_impl_trait_ref,
+            parent_impl_trait_ref,
+            errors,
+            param_env.caller_bounds()
+        );
+        return false;
+    }
+
+    // If the parent impl is const, then the specializing impl must be const,
+    // and it must not be *more restrictive* than the parent impl (that is,
+    // it cannot be const in fewer cases than the parent impl).
+    if tcx.is_conditionally_const(parent_impl_def_id) {
+        if !tcx.is_conditionally_const(specializing_impl_def_id) {
+            return false;
+        }
+
+        let const_conditions = ocx.normalize(
+            cause,
+            param_env,
+            infcx.tcx.const_conditions(parent_impl_def_id).instantiate(infcx.tcx, parent_args),
+        );
+        ocx.register_obligations(const_conditions.into_iter().map(|(trait_ref, _)| {
+            Obligation::new(
+                infcx.tcx,
+                cause.clone(),
+                param_env,
+                trait_ref.to_host_effect_clause(infcx.tcx, ty::BoundConstness::Maybe),
+            )
+        }));
+
+        let errors = ocx.select_all_or_error();
+        if !errors.is_empty() {
+            // no dice!
+            debug!(
+                "fulfill_implication: for impls on {:?} and {:?}, \
+                 could not fulfill: {:?} given {:?}",
+                specializing_impl_trait_ref,
+                parent_impl_trait_ref,
+                errors,
+                param_env.caller_bounds()
+            );
+            return false;
+        }
+    }
+
+    debug!(
+        "fulfill_implication: an impl for {:?} specializes {:?}",
+        specializing_impl_trait_ref, parent_impl_trait_ref
+    );
+
+    true
 }
 
 /// Query provider for `specialization_graph_of`.
diff --git a/library/core/src/intrinsics/simd.rs b/library/core/src/intrinsics/simd.rs
index 5ddca9c4dce..0d24b0558c5 100644
--- a/library/core/src/intrinsics/simd.rs
+++ b/library/core/src/intrinsics/simd.rs
@@ -612,6 +612,20 @@ extern "rust-intrinsic" {
     #[rustc_nounwind]
     pub fn simd_fma<T>(x: T, y: T, z: T) -> T;
 
+    /// Computes `(x*y) + z` for each element, non-deterministically executing either
+    /// a fused multiply-add or two operations with rounding of the intermediate result.
+    ///
+    /// The operation is fused if the code generator determines that target instruction
+    /// set has support for a fused operation, and that the fused operation is more efficient
+    /// than the equivalent, separate pair of mul and add instructions. It is unspecified
+    /// whether or not a fused operation is selected, and that may depend on optimization
+    /// level and context, for example.
+    ///
+    /// `T` must be a vector of floats.
+    #[cfg(not(bootstrap))]
+    #[rustc_nounwind]
+    pub fn simd_relaxed_fma<T>(x: T, y: T, z: T) -> T;
+
     // Computes the sine of each element.
     ///
     /// `T` must be a vector of floats.
diff --git a/src/bootstrap/src/core/builder/mod.rs b/src/bootstrap/src/core/builder/mod.rs
index 73bc7195ac2..026c26479d3 100644
--- a/src/bootstrap/src/core/builder/mod.rs
+++ b/src/bootstrap/src/core/builder/mod.rs
@@ -765,6 +765,54 @@ impl Kind {
     }
 }
 
+#[derive(Debug, Clone, Hash, PartialEq, Eq)]
+struct Libdir {
+    compiler: Compiler,
+    target: TargetSelection,
+}
+
+impl Step for Libdir {
+    type Output = PathBuf;
+
+    fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
+        run.never()
+    }
+
+    fn run(self, builder: &Builder<'_>) -> PathBuf {
+        let relative_sysroot_libdir = builder.sysroot_libdir_relative(self.compiler);
+        let sysroot = builder.sysroot(self.compiler).join(relative_sysroot_libdir).join("rustlib");
+
+        if !builder.config.dry_run() {
+            // Avoid deleting the `rustlib/` directory we just copied (in `impl Step for
+            // Sysroot`).
+            if !builder.download_rustc() {
+                let sysroot_target_libdir = sysroot.join(self.target).join("lib");
+                builder.verbose(|| {
+                    eprintln!(
+                        "Removing sysroot {} to avoid caching bugs",
+                        sysroot_target_libdir.display()
+                    )
+                });
+                let _ = fs::remove_dir_all(&sysroot_target_libdir);
+                t!(fs::create_dir_all(&sysroot_target_libdir));
+            }
+
+            if self.compiler.stage == 0 {
+                // The stage 0 compiler for the build triple is always pre-built. Ensure that
+                // `libLLVM.so` ends up in the target libdir, so that ui-fulldeps tests can use
+                // it when run.
+                dist::maybe_install_llvm_target(
+                    builder,
+                    self.compiler.host,
+                    &builder.sysroot(self.compiler),
+                );
+            }
+        }
+
+        sysroot
+    }
+}
+
 impl<'a> Builder<'a> {
     fn get_step_descriptions(kind: Kind) -> Vec<StepDescription> {
         macro_rules! describe {
@@ -1165,56 +1213,13 @@ impl<'a> Builder<'a> {
 
     /// Returns the bindir for a compiler's sysroot.
     pub fn sysroot_target_bindir(&self, compiler: Compiler, target: TargetSelection) -> PathBuf {
-        self.sysroot_target_libdir(compiler, target).parent().unwrap().join("bin")
+        self.ensure(Libdir { compiler, target }).join(target).join("bin")
     }
 
     /// Returns the libdir where the standard library and other artifacts are
     /// found for a compiler's sysroot.
     pub fn sysroot_target_libdir(&self, compiler: Compiler, target: TargetSelection) -> PathBuf {
-        #[derive(Debug, Clone, Hash, PartialEq, Eq)]
-        struct Libdir {
-            compiler: Compiler,
-            target: TargetSelection,
-        }
-        impl Step for Libdir {
-            type Output = PathBuf;
-
-            fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
-                run.never()
-            }
-
-            fn run(self, builder: &Builder<'_>) -> PathBuf {
-                let lib = builder.sysroot_libdir_relative(self.compiler);
-                let sysroot = builder
-                    .sysroot(self.compiler)
-                    .join(lib)
-                    .join("rustlib")
-                    .join(self.target)
-                    .join("lib");
-                // Avoid deleting the rustlib/ directory we just copied
-                // (in `impl Step for Sysroot`).
-                if !builder.download_rustc() {
-                    builder.verbose(|| {
-                        println!("Removing sysroot {} to avoid caching bugs", sysroot.display())
-                    });
-                    let _ = fs::remove_dir_all(&sysroot);
-                    t!(fs::create_dir_all(&sysroot));
-                }
-
-                if self.compiler.stage == 0 {
-                    // The stage 0 compiler for the build triple is always pre-built.
-                    // Ensure that `libLLVM.so` ends up in the target libdir, so that ui-fulldeps tests can use it when run.
-                    dist::maybe_install_llvm_target(
-                        builder,
-                        self.compiler.host,
-                        &builder.sysroot(self.compiler),
-                    );
-                }
-
-                sysroot
-            }
-        }
-        self.ensure(Libdir { compiler, target })
+        self.ensure(Libdir { compiler, target }).join(target).join("lib")
     }
 
     pub fn sysroot_codegen_backends(&self, compiler: Compiler) -> PathBuf {
diff --git a/src/bootstrap/src/core/builder/tests.rs b/src/bootstrap/src/core/builder/tests.rs
index a1c8bff0db9..b2ffbd9c70f 100644
--- a/src/bootstrap/src/core/builder/tests.rs
+++ b/src/bootstrap/src/core/builder/tests.rs
@@ -738,3 +738,49 @@ mod dist {
         ]);
     }
 }
+
+mod sysroot_target_dirs {
+    use super::{
+        Build, Builder, Compiler, TEST_TRIPLE_1, TEST_TRIPLE_2, TargetSelection, configure,
+    };
+
+    #[test]
+    fn test_sysroot_target_libdir() {
+        let build = Build::new(configure("build", &[TEST_TRIPLE_1], &[TEST_TRIPLE_1]));
+        let builder = Builder::new(&build);
+        let target_triple_1 = TargetSelection::from_user(TEST_TRIPLE_1);
+        let compiler = Compiler { stage: 1, host: target_triple_1 };
+        let target_triple_2 = TargetSelection::from_user(TEST_TRIPLE_2);
+        let actual = builder.sysroot_target_libdir(compiler, target_triple_2);
+
+        assert_eq!(
+            builder
+                .sysroot(compiler)
+                .join(builder.sysroot_libdir_relative(compiler))
+                .join("rustlib")
+                .join(TEST_TRIPLE_2)
+                .join("lib"),
+            actual
+        );
+    }
+
+    #[test]
+    fn test_sysroot_target_bindir() {
+        let build = Build::new(configure("build", &[TEST_TRIPLE_1], &[TEST_TRIPLE_1]));
+        let builder = Builder::new(&build);
+        let target_triple_1 = TargetSelection::from_user(TEST_TRIPLE_1);
+        let compiler = Compiler { stage: 1, host: target_triple_1 };
+        let target_triple_2 = TargetSelection::from_user(TEST_TRIPLE_2);
+        let actual = builder.sysroot_target_bindir(compiler, target_triple_2);
+
+        assert_eq!(
+            builder
+                .sysroot(compiler)
+                .join(builder.sysroot_libdir_relative(compiler))
+                .join("rustlib")
+                .join(TEST_TRIPLE_2)
+                .join("bin"),
+            actual
+        );
+    }
+}
diff --git a/tests/run-make/apple-deployment-target/rmake.rs b/tests/run-make/apple-deployment-target/rmake.rs
index fed6d310770..0ae95cb1f4b 100644
--- a/tests/run-make/apple-deployment-target/rmake.rs
+++ b/tests/run-make/apple-deployment-target/rmake.rs
@@ -24,21 +24,31 @@ fn minos(file: &str, version: &str) {
 
 fn main() {
     // These versions should generally be higher than the default versions
-    let (env_var, example_version, higher_example_version) = match apple_os() {
-        "macos" => ("MACOSX_DEPLOYMENT_TARGET", "12.0", "13.0"),
+    let (example_version, higher_example_version) = match apple_os() {
+        "macos" => ("12.0", "13.0"),
         // armv7s-apple-ios and i386-apple-ios only supports iOS 10.0
-        "ios" if target() == "armv7s-apple-ios" || target() == "i386-apple-ios" => {
-            ("IPHONEOS_DEPLOYMENT_TARGET", "10.0", "10.0")
-        }
-        "ios" => ("IPHONEOS_DEPLOYMENT_TARGET", "15.0", "16.0"),
-        "watchos" => ("WATCHOS_DEPLOYMENT_TARGET", "7.0", "9.0"),
-        "tvos" => ("TVOS_DEPLOYMENT_TARGET", "14.0", "15.0"),
-        "visionos" => ("XROS_DEPLOYMENT_TARGET", "1.1", "1.2"),
+        "ios" if target() == "armv7s-apple-ios" || target() == "i386-apple-ios" => ("10.0", "10.0"),
+        "ios" => ("15.0", "16.0"),
+        "watchos" => ("7.0", "9.0"),
+        "tvos" => ("14.0", "15.0"),
+        "visionos" => ("1.1", "1.2"),
         _ => unreachable!(),
     };
-    let default_version =
-        rustc().target(target()).env_remove(env_var).print("deployment-target").run().stdout_utf8();
-    let default_version = default_version.strip_prefix("deployment_target=").unwrap().trim();
+
+    // Remove env vars to get `rustc`'s default
+    let output = rustc()
+        .target(target())
+        .env_remove("MACOSX_DEPLOYMENT_TARGET")
+        .env_remove("IPHONEOS_DEPLOYMENT_TARGET")
+        .env_remove("WATCHOS_DEPLOYMENT_TARGET")
+        .env_remove("TVOS_DEPLOYMENT_TARGET")
+        .env_remove("XROS_DEPLOYMENT_TARGET")
+        .print("deployment-target")
+        .run()
+        .stdout_utf8();
+    let (env_var, default_version) = output.split_once('=').unwrap();
+    let env_var = env_var.trim();
+    let default_version = default_version.trim();
 
     // Test that version makes it to the object file.
     run_in_tmpdir(|| {
diff --git a/tests/run-make/apple-sdk-version/rmake.rs b/tests/run-make/apple-sdk-version/rmake.rs
index 6463ec00403..43e80577204 100644
--- a/tests/run-make/apple-sdk-version/rmake.rs
+++ b/tests/run-make/apple-sdk-version/rmake.rs
@@ -26,8 +26,7 @@ fn main() {
     // Fetch rustc's inferred deployment target.
     let current_deployment_target =
         rustc().target(target()).print("deployment-target").run().stdout_utf8();
-    let current_deployment_target =
-        current_deployment_target.strip_prefix("deployment_target=").unwrap().trim();
+    let current_deployment_target = current_deployment_target.split('=').last().unwrap().trim();
 
     // Fetch current SDK version via. xcrun.
     //
diff --git a/tests/ui/consts/const-eval-fail-too-big.rs b/tests/ui/consts/const-eval-fail-too-big.rs
new file mode 100644
index 00000000000..4b5dbc1d7a4
--- /dev/null
+++ b/tests/ui/consts/const-eval-fail-too-big.rs
@@ -0,0 +1,12 @@
+//Error output test for #78834: Type is too big for the target architecture
+struct B<
+    A: Sized = [(); {
+                   let x = [0u8; !0usize];
+                   //~^ ERROR evaluation of constant value failed
+                   1
+               }],
+> {
+    a: A,
+}
+
+fn main() {}
diff --git a/tests/ui/consts/const-eval-fail-too-big.stderr b/tests/ui/consts/const-eval-fail-too-big.stderr
new file mode 100644
index 00000000000..ae666483233
--- /dev/null
+++ b/tests/ui/consts/const-eval-fail-too-big.stderr
@@ -0,0 +1,9 @@
+error[E0080]: evaluation of constant value failed
+  --> $DIR/const-eval-fail-too-big.rs:4:28
+   |
+LL |                    let x = [0u8; !0usize];
+   |                            ^^^^^^^^^^^^^^ values of the type `[u8; usize::MAX]` are too big for the target architecture
+
+error: aborting due to 1 previous error
+
+For more information about this error, try `rustc --explain E0080`.
diff --git a/tests/ui/higher-ranked/structually-relate-aliases.rs b/tests/ui/higher-ranked/structually-relate-aliases.rs
index 73c2cd23d86..1ed3767643a 100644
--- a/tests/ui/higher-ranked/structually-relate-aliases.rs
+++ b/tests/ui/higher-ranked/structually-relate-aliases.rs
@@ -12,6 +12,5 @@ impl<T> Overlap<T> for T {}
 
 impl<T> Overlap<for<'a> fn(&'a (), Assoc<'a, T>)> for T {}
 //~^ ERROR the trait bound `for<'a> T: ToUnit<'a>` is not satisfied
-//~| ERROR the trait bound `for<'a> T: ToUnit<'a>` is not satisfied
 
 fn main() {}
diff --git a/tests/ui/higher-ranked/structually-relate-aliases.stderr b/tests/ui/higher-ranked/structually-relate-aliases.stderr
index e9d91e45e21..cf3e4cc85b9 100644
--- a/tests/ui/higher-ranked/structually-relate-aliases.stderr
+++ b/tests/ui/higher-ranked/structually-relate-aliases.stderr
@@ -10,17 +10,6 @@ help: consider restricting type parameter `T`
 LL | impl<T: for<'a> ToUnit<'a>> Overlap<for<'a> fn(&'a (), Assoc<'a, T>)> for T {}
    |       ++++++++++++++++++++
 
-error[E0277]: the trait bound `for<'a> T: ToUnit<'a>` is not satisfied
-  --> $DIR/structually-relate-aliases.rs:13:17
-   |
-LL | impl<T> Overlap<for<'a> fn(&'a (), Assoc<'a, T>)> for T {}
-   |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `for<'a> ToUnit<'a>` is not implemented for `T`
-   |
-help: consider restricting type parameter `T`
-   |
-LL | impl<T: for<'a> ToUnit<'a>> Overlap<for<'a> fn(&'a (), Assoc<'a, T>)> for T {}
-   |       ++++++++++++++++++++
-
-error: aborting due to 2 previous errors
+error: aborting due to 1 previous error
 
 For more information about this error, try `rustc --explain E0277`.
diff --git a/tests/ui/impl-trait/in-trait/alias-bounds-when-not-wf.stderr b/tests/ui/impl-trait/in-trait/alias-bounds-when-not-wf.stderr
index 79581066a3a..1cfc2a6d944 100644
--- a/tests/ui/impl-trait/in-trait/alias-bounds-when-not-wf.stderr
+++ b/tests/ui/impl-trait/in-trait/alias-bounds-when-not-wf.stderr
@@ -8,10 +8,10 @@ LL | #![feature(lazy_type_alias)]
    = note: `#[warn(incomplete_features)]` on by default
 
 error[E0277]: the trait bound `usize: Foo` is not satisfied
-  --> $DIR/alias-bounds-when-not-wf.rs:16:13
+  --> $DIR/alias-bounds-when-not-wf.rs:16:15
    |
 LL | fn hello(_: W<A<usize>>) {}
-   |             ^^^^^^^^^^^ the trait `Foo` is not implemented for `usize`
+   |               ^^^^^^^^ the trait `Foo` is not implemented for `usize`
    |
 help: this trait has no implementations, consider adding one
   --> $DIR/alias-bounds-when-not-wf.rs:6:1
diff --git a/tests/ui/print-request/macos-target.rs b/tests/ui/print-request/macos-target.rs
index 197edd02474..af74babbed4 100644
--- a/tests/ui/print-request/macos-target.rs
+++ b/tests/ui/print-request/macos-target.rs
@@ -1,5 +1,6 @@
 //@ only-apple
 //@ compile-flags: --print deployment-target
+//@ normalize-stdout-test: "\w*_DEPLOYMENT_TARGET" -> "$$OS_DEPLOYMENT_TARGET"
 //@ normalize-stdout-test: "\d+\." -> "$$CURRENT_MAJOR_VERSION."
 //@ normalize-stdout-test: "\d+" -> "$$CURRENT_MINOR_VERSION"
 //@ check-pass
diff --git a/tests/ui/print-request/macos-target.stdout b/tests/ui/print-request/macos-target.stdout
index f55ef568ed6..34ade570969 100644
--- a/tests/ui/print-request/macos-target.stdout
+++ b/tests/ui/print-request/macos-target.stdout
@@ -1 +1 @@
-deployment_target=$CURRENT_MAJOR_VERSION.$CURRENT_MINOR_VERSION
+$OS_DEPLOYMENT_TARGET=$CURRENT_MAJOR_VERSION.$CURRENT_MINOR_VERSION
diff --git a/tests/ui/simd/intrinsic/float-math-pass.rs b/tests/ui/simd/intrinsic/float-math-pass.rs
index 9b14d410acb..24b9941133e 100644
--- a/tests/ui/simd/intrinsic/float-math-pass.rs
+++ b/tests/ui/simd/intrinsic/float-math-pass.rs
@@ -23,6 +23,7 @@ extern "rust-intrinsic" {
     fn simd_fexp<T>(x: T) -> T;
     fn simd_fexp2<T>(x: T) -> T;
     fn simd_fma<T>(x: T, y: T, z: T) -> T;
+    fn simd_relaxed_fma<T>(x: T, y: T, z: T) -> T;
     fn simd_flog<T>(x: T) -> T;
     fn simd_flog10<T>(x: T) -> T;
     fn simd_flog2<T>(x: T) -> T;
@@ -77,6 +78,9 @@ fn main() {
         let r = simd_fma(x, h, h);
         assert_approx_eq!(x, r);
 
+        let r = simd_relaxed_fma(x, h, h);
+        assert_approx_eq!(x, r);
+
         let r = simd_fsqrt(x);
         assert_approx_eq!(x, r);
 
diff --git a/tests/ui/traits/const-traits/overlap-const-with-nonconst.min_spec.stderr b/tests/ui/traits/const-traits/overlap-const-with-nonconst.min_spec.stderr
new file mode 100644
index 00000000000..bd822970ad1
--- /dev/null
+++ b/tests/ui/traits/const-traits/overlap-const-with-nonconst.min_spec.stderr
@@ -0,0 +1,14 @@
+error[E0119]: conflicting implementations of trait `Foo` for type `(_,)`
+  --> $DIR/overlap-const-with-nonconst.rs:23:1
+   |
+LL | / impl<T> const Foo for T
+LL | | where
+LL | |     T: ~const Bar,
+   | |__________________- first implementation here
+...
+LL |   impl<T> Foo for (T,) {
+   |   ^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `(_,)`
+
+error: aborting due to 1 previous error
+
+For more information about this error, try `rustc --explain E0119`.
diff --git a/tests/ui/traits/const-traits/overlap-const-with-nonconst.rs b/tests/ui/traits/const-traits/overlap-const-with-nonconst.rs
new file mode 100644
index 00000000000..eb66d03faa6
--- /dev/null
+++ b/tests/ui/traits/const-traits/overlap-const-with-nonconst.rs
@@ -0,0 +1,38 @@
+//@ revisions: spec min_spec
+
+#![feature(const_trait_impl)]
+#![cfg_attr(spec, feature(specialization))]
+//[spec]~^ WARN the feature `specialization` is incomplete
+#![cfg_attr(min_spec, feature(min_specialization))]
+
+#[const_trait]
+trait Bar {}
+impl<T> const Bar for T {}
+
+#[const_trait]
+trait Foo {
+    fn method(&self);
+}
+impl<T> const Foo for T
+where
+    T: ~const Bar,
+{
+    default fn method(&self) {}
+}
+// specializing impl:
+impl<T> Foo for (T,) {
+//~^ ERROR conflicting implementations
+    fn method(&self) {
+        println!("hi");
+    }
+}
+
+const fn dispatch<T: ~const Bar + Copy>(t: T) {
+    t.method();
+}
+
+fn main() {
+    const {
+        dispatch(((),));
+    }
+}
diff --git a/tests/ui/traits/const-traits/overlap-const-with-nonconst.spec.stderr b/tests/ui/traits/const-traits/overlap-const-with-nonconst.spec.stderr
new file mode 100644
index 00000000000..cbdcb45f6be
--- /dev/null
+++ b/tests/ui/traits/const-traits/overlap-const-with-nonconst.spec.stderr
@@ -0,0 +1,24 @@
+warning: the feature `specialization` is incomplete and may not be safe to use and/or cause compiler crashes
+  --> $DIR/overlap-const-with-nonconst.rs:4:27
+   |
+LL | #![cfg_attr(spec, feature(specialization))]
+   |                           ^^^^^^^^^^^^^^
+   |
+   = note: see issue #31844 <https://github.com/rust-lang/rust/issues/31844> for more information
+   = help: consider using `min_specialization` instead, which is more stable and complete
+   = note: `#[warn(incomplete_features)]` on by default
+
+error[E0119]: conflicting implementations of trait `Foo` for type `(_,)`
+  --> $DIR/overlap-const-with-nonconst.rs:23:1
+   |
+LL | / impl<T> const Foo for T
+LL | | where
+LL | |     T: ~const Bar,
+   | |__________________- first implementation here
+...
+LL |   impl<T> Foo for (T,) {
+   |   ^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `(_,)`
+
+error: aborting due to 1 previous error; 1 warning emitted
+
+For more information about this error, try `rustc --explain E0119`.
diff --git a/tests/ui/traits/const-traits/specialization/const-default-bound-non-const-specialized-bound.stderr b/tests/ui/traits/const-traits/specialization/const-default-bound-non-const-specialized-bound.stderr
index bffc60c65fc..9166b8ca5d2 100644
--- a/tests/ui/traits/const-traits/specialization/const-default-bound-non-const-specialized-bound.stderr
+++ b/tests/ui/traits/const-traits/specialization/const-default-bound-non-const-specialized-bound.stderr
@@ -1,11 +1,31 @@
-error: cannot specialize on const impl with non-const impl
+error[E0119]: conflicting implementations of trait `Bar`
   --> $DIR/const-default-bound-non-const-specialized-bound.rs:28:1
    |
+LL | / impl<T> const Bar for T
+LL | | where
+LL | |     T: ~const Foo,
+   | |__________________- first implementation here
+...
 LL | / impl<T> Bar for T
 LL | | where
 LL | |     T: Foo, //FIXME ~ ERROR missing `~const` qualifier
 LL | |     T: Specialize,
-   | |__________________^
+   | |__________________^ conflicting implementation
+
+error[E0119]: conflicting implementations of trait `Baz`
+  --> $DIR/const-default-bound-non-const-specialized-bound.rs:48:1
+   |
+LL | / impl<T> const Baz for T
+LL | | where
+LL | |     T: ~const Foo,
+   | |__________________- first implementation here
+...
+LL | / impl<T> const Baz for T //FIXME ~ ERROR conflicting implementations of trait `Baz`
+LL | | where
+LL | |     T: Foo,
+LL | |     T: Specialize,
+   | |__________________^ conflicting implementation
 
-error: aborting due to 1 previous error
+error: aborting due to 2 previous errors
 
+For more information about this error, try `rustc --explain E0119`.
diff --git a/tests/ui/traits/const-traits/specialization/const-default-impl-non-const-specialized-impl.min_spec.stderr b/tests/ui/traits/const-traits/specialization/const-default-impl-non-const-specialized-impl.min_spec.stderr
new file mode 100644
index 00000000000..38fc5ddfbef
--- /dev/null
+++ b/tests/ui/traits/const-traits/specialization/const-default-impl-non-const-specialized-impl.min_spec.stderr
@@ -0,0 +1,12 @@
+error[E0119]: conflicting implementations of trait `Value` for type `FortyTwo`
+  --> $DIR/const-default-impl-non-const-specialized-impl.rs:22:1
+   |
+LL | impl<T> const Value for T {
+   | ------------------------- first implementation here
+...
+LL | impl Value for FortyTwo {
+   | ^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `FortyTwo`
+
+error: aborting due to 1 previous error
+
+For more information about this error, try `rustc --explain E0119`.
diff --git a/tests/ui/traits/const-traits/specialization/const-default-impl-non-const-specialized-impl.rs b/tests/ui/traits/const-traits/specialization/const-default-impl-non-const-specialized-impl.rs
index a3bb9b3f93e..acf0a967a88 100644
--- a/tests/ui/traits/const-traits/specialization/const-default-impl-non-const-specialized-impl.rs
+++ b/tests/ui/traits/const-traits/specialization/const-default-impl-non-const-specialized-impl.rs
@@ -1,7 +1,10 @@
 // Tests that specializing trait impls must be at least as const as the default impl.
+//@ revisions: spec min_spec
 
 #![feature(const_trait_impl)]
-#![feature(min_specialization)]
+#![cfg_attr(spec, feature(specialization))]
+//[spec]~^ WARN the feature `specialization` is incomplete
+#![cfg_attr(min_spec, feature(min_specialization))]
 
 #[const_trait]
 trait Value {
@@ -16,7 +19,8 @@ impl<T> const Value for T {
 
 struct FortyTwo;
 
-impl Value for FortyTwo { //~ ERROR cannot specialize on const impl with non-const impl
+impl Value for FortyTwo {
+    //~^ ERROR conflicting implementations
     fn value() -> u32 {
         println!("You can't do that (constly)");
         42
diff --git a/tests/ui/traits/const-traits/specialization/const-default-impl-non-const-specialized-impl.spec.stderr b/tests/ui/traits/const-traits/specialization/const-default-impl-non-const-specialized-impl.spec.stderr
new file mode 100644
index 00000000000..b59c42f5189
--- /dev/null
+++ b/tests/ui/traits/const-traits/specialization/const-default-impl-non-const-specialized-impl.spec.stderr
@@ -0,0 +1,22 @@
+warning: the feature `specialization` is incomplete and may not be safe to use and/or cause compiler crashes
+  --> $DIR/const-default-impl-non-const-specialized-impl.rs:5:27
+   |
+LL | #![cfg_attr(spec, feature(specialization))]
+   |                           ^^^^^^^^^^^^^^
+   |
+   = note: see issue #31844 <https://github.com/rust-lang/rust/issues/31844> for more information
+   = help: consider using `min_specialization` instead, which is more stable and complete
+   = note: `#[warn(incomplete_features)]` on by default
+
+error[E0119]: conflicting implementations of trait `Value` for type `FortyTwo`
+  --> $DIR/const-default-impl-non-const-specialized-impl.rs:22:1
+   |
+LL | impl<T> const Value for T {
+   | ------------------------- first implementation here
+...
+LL | impl Value for FortyTwo {
+   | ^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `FortyTwo`
+
+error: aborting due to 1 previous error; 1 warning emitted
+
+For more information about this error, try `rustc --explain E0119`.
diff --git a/tests/ui/traits/const-traits/specialization/const-default-impl-non-const-specialized-impl.stderr b/tests/ui/traits/const-traits/specialization/const-default-impl-non-const-specialized-impl.stderr
deleted file mode 100644
index e356621ba47..00000000000
--- a/tests/ui/traits/const-traits/specialization/const-default-impl-non-const-specialized-impl.stderr
+++ /dev/null
@@ -1,8 +0,0 @@
-error: cannot specialize on const impl with non-const impl
-  --> $DIR/const-default-impl-non-const-specialized-impl.rs:19:1
-   |
-LL | impl Value for FortyTwo {
-   | ^^^^^^^^^^^^^^^^^^^^^^^
-
-error: aborting due to 1 previous error
-
diff --git a/tests/ui/traits/const-traits/specializing-constness.rs b/tests/ui/traits/const-traits/specializing-constness.rs
index 632121924a6..94b6da7124d 100644
--- a/tests/ui/traits/const-traits/specializing-constness.rs
+++ b/tests/ui/traits/const-traits/specializing-constness.rs
@@ -21,8 +21,7 @@ impl<T: ~const Spec> const A for T {
 }
 
 impl<T: Spec + Sup> A for T {
-//~^ ERROR: cannot specialize
-//FIXME(const_trait_impl) ~| ERROR: missing `~const` qualifier
+    //~^ ERROR conflicting implementations of trait `A`
     fn a() -> u32 {
         3
     }
diff --git a/tests/ui/traits/const-traits/specializing-constness.stderr b/tests/ui/traits/const-traits/specializing-constness.stderr
index 21e21c2cb71..2ca70b53e4e 100644
--- a/tests/ui/traits/const-traits/specializing-constness.stderr
+++ b/tests/ui/traits/const-traits/specializing-constness.stderr
@@ -1,8 +1,12 @@
-error: cannot specialize on const impl with non-const impl
+error[E0119]: conflicting implementations of trait `A`
   --> $DIR/specializing-constness.rs:23:1
    |
+LL | impl<T: ~const Spec> const A for T {
+   | ---------------------------------- first implementation here
+...
 LL | impl<T: Spec + Sup> A for T {
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation
 
 error: aborting due to 1 previous error
 
+For more information about this error, try `rustc --explain E0119`.
diff --git a/tests/ui/traits/next-solver/issue-118950-root-region.rs b/tests/ui/traits/next-solver/issue-118950-root-region.rs
index e1bd234a275..8fe53d6773b 100644
--- a/tests/ui/traits/next-solver/issue-118950-root-region.rs
+++ b/tests/ui/traits/next-solver/issue-118950-root-region.rs
@@ -18,6 +18,6 @@ impl<T> Overlap<T> for T {}
 
 impl<T> Overlap<for<'a> fn(Assoc<'a, T>)> for T where Missing: Overlap<T> {}
 //~^ ERROR cannot find type `Missing` in this scope
-//~| ERROR the trait bound `for<'a> *const T: ToUnit<'a>` is not satisfied
+//~| ERROR the trait bound `T: Overlap<for<'a> fn(Assoc<'a, T>)>` is not satisfied
 
 fn main() {}
diff --git a/tests/ui/traits/next-solver/issue-118950-root-region.stderr b/tests/ui/traits/next-solver/issue-118950-root-region.stderr
index f6545c6ebf9..09162970d33 100644
--- a/tests/ui/traits/next-solver/issue-118950-root-region.stderr
+++ b/tests/ui/traits/next-solver/issue-118950-root-region.stderr
@@ -26,17 +26,16 @@ LL | trait ToUnit<'a> {
    | ^^^^^^^^^^^^^^^^
 
  WARN rustc_infer::infer::relate::generalize may incompletely handle alias type: AliasTy { args: ['^0.Named(DefId(0:15 ~ issue_118950_root_region[d54f]::{impl#1}::'a), "'a"), ?1t], def_id: DefId(0:8 ~ issue_118950_root_region[d54f]::Assoc), .. }
-error[E0277]: the trait bound `for<'a> *const T: ToUnit<'a>` is not satisfied
-  --> $DIR/issue-118950-root-region.rs:19:17
+error[E0277]: the trait bound `T: Overlap<for<'a> fn(Assoc<'a, T>)>` is not satisfied
+  --> $DIR/issue-118950-root-region.rs:19:47
    |
 LL | impl<T> Overlap<for<'a> fn(Assoc<'a, T>)> for T where Missing: Overlap<T> {}
-   |                 ^^^^^^^^^^^^^^^^^^^^^^^^ the trait `for<'a> ToUnit<'a>` is not implemented for `*const T`
+   |                                               ^ the trait `Overlap<for<'a> fn(Assoc<'a, T>)>` is not implemented for `T`
    |
-help: this trait has no implementations, consider adding one
-  --> $DIR/issue-118950-root-region.rs:8:1
+help: consider further restricting type parameter `T`
    |
-LL | trait ToUnit<'a> {
-   | ^^^^^^^^^^^^^^^^
+LL | impl<T> Overlap<for<'a> fn(Assoc<'a, T>)> for T where Missing: Overlap<T>, T: Overlap<for<'a> fn(Assoc<'a, T>)> {}
+   |                                                                          ++++++++++++++++++++++++++++++++++++++
 
 error: aborting due to 3 previous errors; 1 warning emitted
 
diff --git a/tests/ui/traits/next-solver/normalize-in-implied_outlives_bounds.rs b/tests/ui/traits/next-solver/normalize-in-implied_outlives_bounds.rs
new file mode 100644
index 00000000000..1dca19d28e9
--- /dev/null
+++ b/tests/ui/traits/next-solver/normalize-in-implied_outlives_bounds.rs
@@ -0,0 +1,46 @@
+//@ check-pass
+//@ compile-flags: -Znext-solver
+
+// Minimized example from `rustc_type_ir` that demonstrates a missing deep normalization
+// in the new solver when computing the implies outlives bounds of an impl.
+
+use std::marker::PhantomData;
+use std::ops::Deref;
+
+pub struct SearchGraph<D: Delegate, X = <D as Delegate>::Cx> {
+    d: PhantomData<D>,
+    x: PhantomData<X>,
+}
+
+pub trait Delegate {
+    type Cx;
+}
+
+struct SearchGraphDelegate<D: SolverDelegate> {
+    _marker: PhantomData<D>,
+}
+
+impl<D> Delegate for SearchGraphDelegate<D>
+where
+    D: SolverDelegate,
+{
+    type Cx = D::Interner;
+}
+
+pub trait SolverDelegate {
+    type Interner;
+}
+
+struct EvalCtxt<'a, D, I>
+where
+    D: SolverDelegate<Interner = I>,
+{
+    search_graph: &'a SearchGraph<SearchGraphDelegate<D>>,
+}
+
+impl<'a, D, I> EvalCtxt<'a, D, <D as SolverDelegate>::Interner>
+where
+    D: SolverDelegate<Interner = I>
+{}
+
+fn main() {}