From ed7bdbb17b9c03fe3530e5e3f21b7c6c7879dbca Mon Sep 17 00:00:00 2001
From: Michael Goulet <michael@errs.io>
Date: Fri, 9 Aug 2024 22:02:20 -0400
Subject: [PATCH 1/8] Store do_not_recommend-ness in impl header

---
 compiler/rustc_hir_analysis/src/collect.rs     |  2 ++
 compiler/rustc_middle/src/ty/context.rs        |  6 ++++++
 compiler/rustc_middle/src/ty/mod.rs            |  1 +
 .../traits/fulfillment_errors.rs               | 18 +++---------------
 .../rustc_trait_selection/src/solve/fulfill.rs |  6 +-----
 5 files changed, 13 insertions(+), 20 deletions(-)

diff --git a/compiler/rustc_hir_analysis/src/collect.rs b/compiler/rustc_hir_analysis/src/collect.rs
index 47ff748547a..07bf5d90b55 100644
--- a/compiler/rustc_hir_analysis/src/collect.rs
+++ b/compiler/rustc_hir_analysis/src/collect.rs
@@ -1699,6 +1699,8 @@ fn impl_trait_header(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Option<ty::ImplTrai
             trait_ref: ty::EarlyBinder::bind(trait_ref),
             safety: impl_.safety,
             polarity: polarity_of_impl(tcx, def_id, impl_, item.span),
+            do_not_recommend: tcx.features().do_not_recommend
+                && tcx.has_attrs_with_path(def_id, &[sym::diagnostic, sym::do_not_recommend]),
         }
     })
 }
diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs
index 8f8fd09c9e4..dd367d38e46 100644
--- a/compiler/rustc_middle/src/ty/context.rs
+++ b/compiler/rustc_middle/src/ty/context.rs
@@ -3176,6 +3176,12 @@ impl<'tcx> TyCtxt<'tcx> {
     pub fn impl_polarity(self, def_id: impl IntoQueryParam<DefId>) -> ty::ImplPolarity {
         self.impl_trait_header(def_id).map_or(ty::ImplPolarity::Positive, |h| h.polarity)
     }
+
+    /// Whether this is a trait implementation that has `#[diagnostic::do_not_recommend]`
+    pub fn do_not_recommend_impl(self, def_id: DefId) -> bool {
+        matches!(self.def_kind(def_id), DefKind::Impl { of_trait: true })
+            && self.impl_trait_header(def_id).is_some_and(|header| header.do_not_recommend)
+    }
 }
 
 /// Parameter attributes that can only be determined by examining the body of a function instead
diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs
index 9736428e6f7..69b194045ad 100644
--- a/compiler/rustc_middle/src/ty/mod.rs
+++ b/compiler/rustc_middle/src/ty/mod.rs
@@ -262,6 +262,7 @@ pub struct ImplTraitHeader<'tcx> {
     pub trait_ref: ty::EarlyBinder<'tcx, ty::TraitRef<'tcx>>,
     pub polarity: ImplPolarity,
     pub safety: hir::Safety,
+    pub do_not_recommend: bool,
 }
 
 #[derive(Copy, Clone, PartialEq, Eq, Debug, TypeFoldable, TypeVisitable)]
diff --git a/compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs b/compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs
index 1cee82f04ea..7f7de4a963b 100644
--- a/compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs
+++ b/compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs
@@ -687,10 +687,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
         let mut applied_do_not_recommend = false;
         loop {
             if let ObligationCauseCode::ImplDerived(ref c) = base_cause {
-                if self.tcx.has_attrs_with_path(
-                    c.impl_or_alias_def_id,
-                    &[sym::diagnostic, sym::do_not_recommend],
-                ) {
+                if self.tcx.do_not_recommend_impl(c.impl_or_alias_def_id) {
                     let code = (*c.derived.parent_code).clone();
                     obligation.cause.map_code(|_| code);
                     obligation.predicate = c.derived.parent_trait_pred.upcast(self.tcx);
@@ -1630,11 +1627,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
                 .tcx
                 .all_impls(def_id)
                 // ignore `do_not_recommend` items
-                .filter(|def_id| {
-                    !self
-                        .tcx
-                        .has_attrs_with_path(*def_id, &[sym::diagnostic, sym::do_not_recommend])
-                })
+                .filter(|def_id| !self.tcx.do_not_recommend_impl(*def_id))
                 // Ignore automatically derived impls and `!Trait` impls.
                 .filter_map(|def_id| self.tcx.impl_trait_header(def_id))
                 .filter_map(|header| {
@@ -1904,12 +1897,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
         let impl_candidates = impl_candidates
             .into_iter()
             .cloned()
-            .filter(|cand| {
-                !self.tcx.has_attrs_with_path(
-                    cand.impl_def_id,
-                    &[sym::diagnostic, sym::do_not_recommend],
-                )
-            })
+            .filter(|cand| !self.tcx.do_not_recommend_impl(cand.impl_def_id))
             .collect::<Vec<_>>();
 
         let def_id = trait_ref.def_id();
diff --git a/compiler/rustc_trait_selection/src/solve/fulfill.rs b/compiler/rustc_trait_selection/src/solve/fulfill.rs
index 49fa775a0a1..de8951ef720 100644
--- a/compiler/rustc_trait_selection/src/solve/fulfill.rs
+++ b/compiler/rustc_trait_selection/src/solve/fulfill.rs
@@ -13,7 +13,6 @@ use rustc_middle::bug;
 use rustc_middle::ty::error::{ExpectedFound, TypeError};
 use rustc_middle::ty::{self, TyCtxt};
 use rustc_next_trait_solver::solve::{GenerateProofTree, SolverDelegateEvalExt as _};
-use rustc_span::symbol::sym;
 
 use super::delegate::SolverDelegate;
 use super::inspect::{self, ProofTreeInferCtxtExt, ProofTreeVisitor};
@@ -440,10 +439,7 @@ impl<'tcx> ProofTreeVisitor<'tcx> for BestObligation<'tcx> {
             source: CandidateSource::Impl(impl_def_id),
             result: _,
         } = candidate.kind()
-            && goal
-                .infcx()
-                .tcx
-                .has_attrs_with_path(impl_def_id, &[sym::diagnostic, sym::do_not_recommend])
+            && goal.infcx().tcx.do_not_recommend_impl(impl_def_id)
         {
             return ControlFlow::Break(self.obligation.clone());
         }

From 20a16bb3c54ea7523ebd0c933fe5674aea50942e Mon Sep 17 00:00:00 2001
From: Michael Goulet <michael@errs.io>
Date: Fri, 9 Aug 2024 21:14:07 -0400
Subject: [PATCH 2/8] Add test

Co-authored-by: Georg Semmler <github@weiznich.de>
---
 ...ot_apply_attribute_without_feature_flag.rs | 21 +++++++++++++++++++
 ...pply_attribute_without_feature_flag.stderr | 21 +++++++++++++++++++
 2 files changed, 42 insertions(+)
 create mode 100644 tests/ui/diagnostic_namespace/do_not_recommend/do_not_apply_attribute_without_feature_flag.rs
 create mode 100644 tests/ui/diagnostic_namespace/do_not_recommend/do_not_apply_attribute_without_feature_flag.stderr

diff --git a/tests/ui/diagnostic_namespace/do_not_recommend/do_not_apply_attribute_without_feature_flag.rs b/tests/ui/diagnostic_namespace/do_not_recommend/do_not_apply_attribute_without_feature_flag.rs
new file mode 100644
index 00000000000..5548fa2f52e
--- /dev/null
+++ b/tests/ui/diagnostic_namespace/do_not_recommend/do_not_apply_attribute_without_feature_flag.rs
@@ -0,0 +1,21 @@
+#![allow(unknown_or_malformed_diagnostic_attributes)]
+
+trait Foo {}
+
+#[diagnostic::do_not_recommend]
+impl<A> Foo for (A,) {}
+
+#[diagnostic::do_not_recommend]
+impl<A, B> Foo for (A, B) {}
+
+#[diagnostic::do_not_recommend]
+impl<A, B, C> Foo for (A, B, C) {}
+
+impl Foo for i32 {}
+
+fn check(a: impl Foo) {}
+
+fn main() {
+    check(());
+    //~^ ERROR the trait bound `(): Foo` is not satisfied
+}
diff --git a/tests/ui/diagnostic_namespace/do_not_recommend/do_not_apply_attribute_without_feature_flag.stderr b/tests/ui/diagnostic_namespace/do_not_recommend/do_not_apply_attribute_without_feature_flag.stderr
new file mode 100644
index 00000000000..e56af28f3fb
--- /dev/null
+++ b/tests/ui/diagnostic_namespace/do_not_recommend/do_not_apply_attribute_without_feature_flag.stderr
@@ -0,0 +1,21 @@
+error[E0277]: the trait bound `(): Foo` is not satisfied
+  --> $DIR/do_not_apply_attribute_without_feature_flag.rs:19:11
+   |
+LL |     check(());
+   |     ----- ^^ the trait `Foo` is not implemented for `()`
+   |     |
+   |     required by a bound introduced by this call
+   |
+   = help: the following other types implement trait `Foo`:
+             (A, B)
+             (A, B, C)
+             (A,)
+note: required by a bound in `check`
+  --> $DIR/do_not_apply_attribute_without_feature_flag.rs:16:18
+   |
+LL | fn check(a: impl Foo) {}
+   |                  ^^^ required by this bound in `check`
+
+error: aborting due to 1 previous error
+
+For more information about this error, try `rustc --explain E0277`.

From c5205e9d56d3c632e83e1e5f0853d3bd82f16c0e Mon Sep 17 00:00:00 2001
From: Michael Goulet <michael@errs.io>
Date: Sun, 11 Aug 2024 12:28:15 -0400
Subject: [PATCH 3/8] Normalize struct tail properly in borrowck and hir typeck

---
 .../src/type_check/canonical.rs               | 47 +++++++++++++++++++
 compiler/rustc_borrowck/src/type_check/mod.rs | 13 +----
 compiler/rustc_hir_typeck/src/cast.rs         |  2 +
 ...different-regions-id-trait.current.stderr} |  2 +-
 ...obj-different-regions-id-trait.next.stderr | 15 ++++++
 ...to-trait-obj-different-regions-id-trait.rs |  3 ++
 6 files changed, 70 insertions(+), 12 deletions(-)
 rename tests/ui/cast/{ptr-to-trait-obj-different-regions-id-trait.stderr => ptr-to-trait-obj-different-regions-id-trait.current.stderr} (91%)
 create mode 100644 tests/ui/cast/ptr-to-trait-obj-different-regions-id-trait.next.stderr

diff --git a/compiler/rustc_borrowck/src/type_check/canonical.rs b/compiler/rustc_borrowck/src/type_check/canonical.rs
index 86cd8b918fc..2558cf6347d 100644
--- a/compiler/rustc_borrowck/src/type_check/canonical.rs
+++ b/compiler/rustc_borrowck/src/type_check/canonical.rs
@@ -7,6 +7,7 @@ use rustc_middle::mir::ConstraintCategory;
 use rustc_middle::ty::{self, Ty, TyCtxt, TypeFoldable, Upcast};
 use rustc_span::def_id::DefId;
 use rustc_span::Span;
+use rustc_trait_selection::traits::query::type_op::custom::CustomTypeOp;
 use rustc_trait_selection::traits::query::type_op::{self, TypeOpOutput};
 use rustc_trait_selection::traits::ObligationCause;
 
@@ -165,6 +166,52 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
         result.unwrap_or(value)
     }
 
+    #[instrument(skip(self), level = "debug")]
+    pub(super) fn struct_tail(
+        &mut self,
+        ty: Ty<'tcx>,
+        location: impl NormalizeLocation,
+    ) -> Ty<'tcx> {
+        let tcx = self.tcx();
+        if self.infcx.next_trait_solver() {
+            let body = self.body;
+            let param_env = self.param_env;
+            self.fully_perform_op(
+                location.to_locations(),
+                ConstraintCategory::Boring,
+                CustomTypeOp::new(
+                    |ocx| {
+                        let structurally_normalize = |ty| {
+                            ocx.structurally_normalize(
+                                &ObligationCause::misc(
+                                    location.to_locations().span(body),
+                                    body.source.def_id().expect_local(),
+                                ),
+                                param_env,
+                                ty,
+                            )
+                            .unwrap_or_else(|_| bug!("struct tail should have been computable, since we computed it in HIR"))
+                        };
+
+                        let tail = tcx.struct_tail_with_normalize(
+                            ty,
+                            structurally_normalize,
+                            || {},
+                        );
+
+                        Ok(tail)
+                    },
+                    "normalizing struct tail",
+                ),
+            )
+            .unwrap_or_else(|guar| Ty::new_error(tcx, guar))
+        } else {
+            let mut normalize = |ty| self.normalize(ty, location);
+            let tail = tcx.struct_tail_with_normalize(ty, &mut normalize, || {});
+            normalize(tail)
+        }
+    }
+
     #[instrument(skip(self), level = "debug")]
     pub(super) fn ascribe_user_type(
         &mut self,
diff --git a/compiler/rustc_borrowck/src/type_check/mod.rs b/compiler/rustc_borrowck/src/type_check/mod.rs
index b13773ffe14..6bab0f33c19 100644
--- a/compiler/rustc_borrowck/src/type_check/mod.rs
+++ b/compiler/rustc_borrowck/src/type_check/mod.rs
@@ -2329,17 +2329,8 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
                         let cast_ty_to = CastTy::from_ty(*ty);
                         match (cast_ty_from, cast_ty_to) {
                             (Some(CastTy::Ptr(src)), Some(CastTy::Ptr(dst))) => {
-                                let mut normalize = |t| self.normalize(t, location);
-
-                                // N.B. `struct_tail_with_normalize` only "structurally resolves"
-                                // the type. It is not fully normalized, so we have to normalize it
-                                // afterwards.
-                                let src_tail =
-                                    tcx.struct_tail_with_normalize(src.ty, &mut normalize, || ());
-                                let src_tail = normalize(src_tail);
-                                let dst_tail =
-                                    tcx.struct_tail_with_normalize(dst.ty, &mut normalize, || ());
-                                let dst_tail = normalize(dst_tail);
+                                let src_tail = self.struct_tail(src.ty, location);
+                                let dst_tail = self.struct_tail(dst.ty, location);
 
                                 // This checks (lifetime part of) vtable validity for pointer casts,
                                 // which is irrelevant when there are aren't principal traits on both sides (aka only auto traits).
diff --git a/compiler/rustc_hir_typeck/src/cast.rs b/compiler/rustc_hir_typeck/src/cast.rs
index de702733904..7cd97166ed1 100644
--- a/compiler/rustc_hir_typeck/src/cast.rs
+++ b/compiler/rustc_hir_typeck/src/cast.rs
@@ -97,6 +97,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
             return Ok(Some(PointerKind::Thin));
         }
 
+        let t = self.try_structurally_resolve_type(span, t);
+
         Ok(match *t.kind() {
             ty::Slice(_) | ty::Str => Some(PointerKind::Length),
             ty::Dynamic(tty, _, ty::Dyn) => Some(PointerKind::VTable(tty)),
diff --git a/tests/ui/cast/ptr-to-trait-obj-different-regions-id-trait.stderr b/tests/ui/cast/ptr-to-trait-obj-different-regions-id-trait.current.stderr
similarity index 91%
rename from tests/ui/cast/ptr-to-trait-obj-different-regions-id-trait.stderr
rename to tests/ui/cast/ptr-to-trait-obj-different-regions-id-trait.current.stderr
index d1d598e603f..5a5b4bfcacf 100644
--- a/tests/ui/cast/ptr-to-trait-obj-different-regions-id-trait.stderr
+++ b/tests/ui/cast/ptr-to-trait-obj-different-regions-id-trait.current.stderr
@@ -1,5 +1,5 @@
 error: lifetime may not live long enough
-  --> $DIR/ptr-to-trait-obj-different-regions-id-trait.rs:21:17
+  --> $DIR/ptr-to-trait-obj-different-regions-id-trait.rs:24:17
    |
 LL | fn m<'a>() {
    |      -- lifetime `'a` defined here
diff --git a/tests/ui/cast/ptr-to-trait-obj-different-regions-id-trait.next.stderr b/tests/ui/cast/ptr-to-trait-obj-different-regions-id-trait.next.stderr
new file mode 100644
index 00000000000..5a5b4bfcacf
--- /dev/null
+++ b/tests/ui/cast/ptr-to-trait-obj-different-regions-id-trait.next.stderr
@@ -0,0 +1,15 @@
+error: lifetime may not live long enough
+  --> $DIR/ptr-to-trait-obj-different-regions-id-trait.rs:24:17
+   |
+LL | fn m<'a>() {
+   |      -- lifetime `'a` defined here
+LL |     let unsend: *const dyn Cat<'a> = &();
+LL |     let _send = unsend as *const S<dyn Cat<'static>>;
+   |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type annotation requires that `'a` must outlive `'static`
+   |
+   = note: requirement occurs because of the type `S<dyn Cat<'_>>`, which makes the generic argument `dyn Cat<'_>` invariant
+   = note: the struct `S<T>` is invariant over the parameter `T`
+   = help: see <https://doc.rust-lang.org/nomicon/subtyping.html> for more information about variance
+
+error: aborting due to 1 previous error
+
diff --git a/tests/ui/cast/ptr-to-trait-obj-different-regions-id-trait.rs b/tests/ui/cast/ptr-to-trait-obj-different-regions-id-trait.rs
index cdd55e24392..f968dca4fd3 100644
--- a/tests/ui/cast/ptr-to-trait-obj-different-regions-id-trait.rs
+++ b/tests/ui/cast/ptr-to-trait-obj-different-regions-id-trait.rs
@@ -1,3 +1,6 @@
+//@ revisions: current next
+//@ ignore-compare-mode-next-solver (explicit revisions)
+//@[next] compile-flags: -Znext-solver
 //@ check-fail
 //
 // Make sure we can't trick the compiler by using a projection.

From b5d2079fb9c9ac9f0fe594f65452b4097e71c2de Mon Sep 17 00:00:00 2001
From: Michael Goulet <michael@errs.io>
Date: Sun, 11 Aug 2024 12:30:38 -0400
Subject: [PATCH 4/8] Rename normalization functions to raw

---
 .../rustc_borrowck/src/type_check/canonical.rs   |  4 ++--
 .../rustc_const_eval/src/const_eval/valtrees.rs  |  2 +-
 compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs   |  2 +-
 compiler/rustc_middle/src/ty/layout.rs           |  2 +-
 compiler/rustc_middle/src/ty/sty.rs              |  6 +++---
 compiler/rustc_middle/src/ty/util.rs             | 16 +++++++++-------
 .../rustc_trait_selection/src/traits/project.rs  |  2 +-
 7 files changed, 18 insertions(+), 16 deletions(-)

diff --git a/compiler/rustc_borrowck/src/type_check/canonical.rs b/compiler/rustc_borrowck/src/type_check/canonical.rs
index 2558cf6347d..b58691fbeae 100644
--- a/compiler/rustc_borrowck/src/type_check/canonical.rs
+++ b/compiler/rustc_borrowck/src/type_check/canonical.rs
@@ -193,7 +193,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
                             .unwrap_or_else(|_| bug!("struct tail should have been computable, since we computed it in HIR"))
                         };
 
-                        let tail = tcx.struct_tail_with_normalize(
+                        let tail = tcx.struct_tail_raw(
                             ty,
                             structurally_normalize,
                             || {},
@@ -207,7 +207,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
             .unwrap_or_else(|guar| Ty::new_error(tcx, guar))
         } else {
             let mut normalize = |ty| self.normalize(ty, location);
-            let tail = tcx.struct_tail_with_normalize(ty, &mut normalize, || {});
+            let tail = tcx.struct_tail_raw(ty, &mut normalize, || {});
             normalize(tail)
         }
     }
diff --git a/compiler/rustc_const_eval/src/const_eval/valtrees.rs b/compiler/rustc_const_eval/src/const_eval/valtrees.rs
index 8227c045948..460c9797f36 100644
--- a/compiler/rustc_const_eval/src/const_eval/valtrees.rs
+++ b/compiler/rustc_const_eval/src/const_eval/valtrees.rs
@@ -195,7 +195,7 @@ fn reconstruct_place_meta<'tcx>(
 
     let mut last_valtree = valtree;
     // Traverse the type, and update `last_valtree` as we go.
-    let tail = tcx.struct_tail_with_normalize(
+    let tail = tcx.struct_tail_raw(
         layout.ty,
         |ty| ty,
         || {
diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs
index 841d25b54cc..b169f75796b 100644
--- a/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs
+++ b/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs
@@ -404,7 +404,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         code: traits::ObligationCauseCode<'tcx>,
     ) {
         if !ty.references_error() {
-            let tail = self.tcx.struct_tail_with_normalize(
+            let tail = self.tcx.struct_tail_raw(
                 ty,
                 |ty| {
                     if self.next_trait_solver() {
diff --git a/compiler/rustc_middle/src/ty/layout.rs b/compiler/rustc_middle/src/ty/layout.rs
index 9204405d58f..684574825e3 100644
--- a/compiler/rustc_middle/src/ty/layout.rs
+++ b/compiler/rustc_middle/src/ty/layout.rs
@@ -362,7 +362,7 @@ impl<'tcx> SizeSkeleton<'tcx> {
             ty::Ref(_, pointee, _) | ty::RawPtr(pointee, _) => {
                 let non_zero = !ty.is_unsafe_ptr();
 
-                let tail = tcx.struct_tail_with_normalize(
+                let tail = tcx.struct_tail_raw(
                     pointee,
                     |ty| match tcx.try_normalize_erasing_regions(param_env, ty) {
                         Ok(ty) => ty,
diff --git a/compiler/rustc_middle/src/ty/sty.rs b/compiler/rustc_middle/src/ty/sty.rs
index 8c97de1c59b..8781a670acb 100644
--- a/compiler/rustc_middle/src/ty/sty.rs
+++ b/compiler/rustc_middle/src/ty/sty.rs
@@ -1590,7 +1590,7 @@ impl<'tcx> Ty<'tcx> {
         tcx: TyCtxt<'tcx>,
         normalize: impl FnMut(Ty<'tcx>) -> Ty<'tcx>,
     ) -> Result<Ty<'tcx>, Ty<'tcx>> {
-        let tail = tcx.struct_tail_with_normalize(self, normalize, || {});
+        let tail = tcx.struct_tail_raw(self, normalize, || {});
         match tail.kind() {
             // Sized types
             ty::Infer(ty::IntVar(_) | ty::FloatVar(_))
@@ -1614,10 +1614,10 @@ impl<'tcx> Ty<'tcx> {
             | ty::Foreign(..)
             // `dyn*` has metadata = ().
             | ty::Dynamic(_, _, ty::DynStar)
-            // If returned by `struct_tail_with_normalize` this is a unit struct
+            // If returned by `struct_tail_raw` this is a unit struct
             // without any fields, or not a struct, and therefore is Sized.
             | ty::Adt(..)
-            // If returned by `struct_tail_with_normalize` this is the empty tuple,
+            // If returned by `struct_tail_raw` this is the empty tuple,
             // a.k.a. unit type, which is Sized
             | ty::Tuple(..) => Ok(tcx.types.unit),
 
diff --git a/compiler/rustc_middle/src/ty/util.rs b/compiler/rustc_middle/src/ty/util.rs
index 365f434a264..fc5e0c44d96 100644
--- a/compiler/rustc_middle/src/ty/util.rs
+++ b/compiler/rustc_middle/src/ty/util.rs
@@ -176,7 +176,7 @@ impl<'tcx> TyCtxt<'tcx> {
     /// if input `ty` is not a structure at all.
     pub fn struct_tail_without_normalization(self, ty: Ty<'tcx>) -> Ty<'tcx> {
         let tcx = self;
-        tcx.struct_tail_with_normalize(ty, |ty| ty, || {})
+        tcx.struct_tail_raw(ty, |ty| ty, || {})
     }
 
     /// Returns the deeply last field of nested structures, or the same type if
@@ -188,7 +188,7 @@ impl<'tcx> TyCtxt<'tcx> {
     /// normalization attempt may cause compiler bugs.
     pub fn struct_tail_for_codegen(self, ty: Ty<'tcx>, param_env: ty::ParamEnv<'tcx>) -> Ty<'tcx> {
         let tcx = self;
-        tcx.struct_tail_with_normalize(ty, |ty| tcx.normalize_erasing_regions(param_env, ty), || {})
+        tcx.struct_tail_raw(ty, |ty| tcx.normalize_erasing_regions(param_env, ty), || {})
     }
 
     /// Returns the deeply last field of nested structures, or the same type if
@@ -196,12 +196,14 @@ impl<'tcx> TyCtxt<'tcx> {
     /// and its type can be used to determine unsizing strategy.
     ///
     /// This is parameterized over the normalization strategy (i.e. how to
-    /// handle `<T as Trait>::Assoc` and `impl Trait`); pass the identity
-    /// function to indicate no normalization should take place.
+    /// handle `<T as Trait>::Assoc` and `impl Trait`). You almost certainly do
+    /// **NOT** want to pass the identity function here, unless you know what
+    /// you're doing, or you're within normalization code itself and will handle
+    /// an unnormalized tail recursively.
     ///
     /// See also `struct_tail_for_codegen`, which is suitable for use
     /// during codegen.
-    pub fn struct_tail_with_normalize(
+    pub fn struct_tail_raw(
         self,
         mut ty: Ty<'tcx>,
         mut normalize: impl FnMut(Ty<'tcx>) -> Ty<'tcx>,
@@ -281,7 +283,7 @@ impl<'tcx> TyCtxt<'tcx> {
         param_env: ty::ParamEnv<'tcx>,
     ) -> (Ty<'tcx>, Ty<'tcx>) {
         let tcx = self;
-        tcx.struct_lockstep_tails_with_normalize(source, target, |ty| {
+        tcx.struct_lockstep_tails_raw(source, target, |ty| {
             tcx.normalize_erasing_regions(param_env, ty)
         })
     }
@@ -294,7 +296,7 @@ impl<'tcx> TyCtxt<'tcx> {
     ///
     /// See also `struct_lockstep_tails_for_codegen`, which is suitable for use
     /// during codegen.
-    pub fn struct_lockstep_tails_with_normalize(
+    pub fn struct_lockstep_tails_raw(
         self,
         source: Ty<'tcx>,
         target: Ty<'tcx>,
diff --git a/compiler/rustc_trait_selection/src/traits/project.rs b/compiler/rustc_trait_selection/src/traits/project.rs
index 4b62a5c59b2..0e4233ba7bc 100644
--- a/compiler/rustc_trait_selection/src/traits/project.rs
+++ b/compiler/rustc_trait_selection/src/traits/project.rs
@@ -1110,7 +1110,7 @@ fn assemble_candidates_from_impls<'cx, 'tcx>(
                         | ty::Error(_) => false,
                     }
                 } else if tcx.is_lang_item(trait_ref.def_id, LangItem::PointeeTrait) {
-                    let tail = selcx.tcx().struct_tail_with_normalize(
+                    let tail = selcx.tcx().struct_tail_raw(
                         self_ty,
                         |ty| {
                             // We throw away any obligations we get from this, since we normalize

From f15997ffeca4c7da66e7de9e348ccb8d3cccc946 Mon Sep 17 00:00:00 2001
From: Michael Goulet <michael@errs.io>
Date: Sun, 11 Aug 2024 19:21:33 -0400
Subject: [PATCH 5/8] Remove struct_tail_no_normalization

---
 compiler/rustc_const_eval/src/const_eval/eval_queries.rs | 2 +-
 compiler/rustc_hir_typeck/src/expectation.rs             | 3 ++-
 compiler/rustc_middle/src/ty/util.rs                     | 8 --------
 compiler/rustc_trait_selection/src/traits/project.rs     | 4 ++--
 compiler/rustc_ty_utils/src/layout.rs                    | 6 +++++-
 5 files changed, 10 insertions(+), 13 deletions(-)

diff --git a/compiler/rustc_const_eval/src/const_eval/eval_queries.rs b/compiler/rustc_const_eval/src/const_eval/eval_queries.rs
index ff27e400016..96b3ec6f187 100644
--- a/compiler/rustc_const_eval/src/const_eval/eval_queries.rs
+++ b/compiler/rustc_const_eval/src/const_eval/eval_queries.rs
@@ -226,7 +226,7 @@ pub(super) fn op_to_const<'tcx>(
                 let pointee_ty = imm.layout.ty.builtin_deref(false).unwrap(); // `false` = no raw ptrs
                 debug_assert!(
                     matches!(
-                        ecx.tcx.struct_tail_without_normalization(pointee_ty).kind(),
+                        ecx.tcx.struct_tail_for_codegen(pointee_ty, ecx.param_env).kind(),
                         ty::Str | ty::Slice(..),
                     ),
                     "`ConstValue::Slice` is for slice-tailed types only, but got {}",
diff --git a/compiler/rustc_hir_typeck/src/expectation.rs b/compiler/rustc_hir_typeck/src/expectation.rs
index 91deae4174b..76ae41db5c5 100644
--- a/compiler/rustc_hir_typeck/src/expectation.rs
+++ b/compiler/rustc_hir_typeck/src/expectation.rs
@@ -70,7 +70,8 @@ impl<'a, 'tcx> Expectation<'tcx> {
     /// See the test case `test/ui/coerce-expect-unsized.rs` and #20169
     /// for examples of where this comes up,.
     pub(super) fn rvalue_hint(fcx: &FnCtxt<'a, 'tcx>, ty: Ty<'tcx>) -> Expectation<'tcx> {
-        match fcx.tcx.struct_tail_without_normalization(ty).kind() {
+        // FIXME: This is not right, even in the old solver...
+        match fcx.tcx.struct_tail_raw(ty, |ty| ty, || {}).kind() {
             ty::Slice(_) | ty::Str | ty::Dynamic(..) => ExpectRvalueLikeUnsized(ty),
             _ => ExpectHasType(ty),
         }
diff --git a/compiler/rustc_middle/src/ty/util.rs b/compiler/rustc_middle/src/ty/util.rs
index fc5e0c44d96..6be3dc423de 100644
--- a/compiler/rustc_middle/src/ty/util.rs
+++ b/compiler/rustc_middle/src/ty/util.rs
@@ -171,14 +171,6 @@ impl<'tcx> TyCtxt<'tcx> {
         }
     }
 
-    /// Attempts to returns the deeply last field of nested structures, but
-    /// does not apply any normalization in its search. Returns the same type
-    /// if input `ty` is not a structure at all.
-    pub fn struct_tail_without_normalization(self, ty: Ty<'tcx>) -> Ty<'tcx> {
-        let tcx = self;
-        tcx.struct_tail_raw(ty, |ty| ty, || {})
-    }
-
     /// Returns the deeply last field of nested structures, or the same type if
     /// not a structure at all. Corresponds to the only possible unsized field,
     /// and its type can be used to determine unsizing strategy.
diff --git a/compiler/rustc_trait_selection/src/traits/project.rs b/compiler/rustc_trait_selection/src/traits/project.rs
index 0e4233ba7bc..8a17d7ed641 100644
--- a/compiler/rustc_trait_selection/src/traits/project.rs
+++ b/compiler/rustc_trait_selection/src/traits/project.rs
@@ -1149,10 +1149,10 @@ fn assemble_candidates_from_impls<'cx, 'tcx>(
                         | ty::Never
                         // Extern types have unit metadata, according to RFC 2850
                         | ty::Foreign(_)
-                        // If returned by `struct_tail_without_normalization` this is a unit struct
+                        // If returned by `struct_tail` this is a unit struct
                         // without any fields, or not a struct, and therefore is Sized.
                         | ty::Adt(..)
-                        // If returned by `struct_tail_without_normalization` this is the empty tuple.
+                        // If returned by `struct_tail` this is the empty tuple.
                         | ty::Tuple(..)
                         // Integers and floats are always Sized, and so have unit type metadata.
                         | ty::Infer(ty::InferTy::IntVar(_) | ty::InferTy::FloatVar(..)) => true,
diff --git a/compiler/rustc_ty_utils/src/layout.rs b/compiler/rustc_ty_utils/src/layout.rs
index 1eb03fc3bd6..244a6afcf97 100644
--- a/compiler/rustc_ty_utils/src/layout.rs
+++ b/compiler/rustc_ty_utils/src/layout.rs
@@ -219,9 +219,13 @@ fn layout_of_uncached<'tcx>(
                             // its struct tail cannot be normalized either, so try to get a
                             // more descriptive layout error here, which will lead to less confusing
                             // diagnostics.
+                            //
+                            // We use the raw struct tail function here to get the first tail
+                            // that is an alias, which is likely the cause of the normalization
+                            // error.
                             match tcx.try_normalize_erasing_regions(
                                 param_env,
-                                tcx.struct_tail_without_normalization(pointee),
+                                tcx.struct_tail_raw(pointee, |ty| ty, || {}),
                             ) {
                                 Ok(_) => {}
                                 Err(better_err) => {

From 6839a8f6d55ebb00b1904cda37d03caf15144440 Mon Sep 17 00:00:00 2001
From: Ralf Jung <post@ralfj.de>
Date: Mon, 12 Aug 2024 11:32:21 +0200
Subject: [PATCH 6/8] bootstrap: clear miri ui-test deps when miri sysroot gets
 rebuilt

---
 src/bootstrap/src/core/build_steps/test.rs | 14 ++++++++------
 1 file changed, 8 insertions(+), 6 deletions(-)

diff --git a/src/bootstrap/src/core/build_steps/test.rs b/src/bootstrap/src/core/build_steps/test.rs
index 597d7733abe..6ed001d8fd5 100644
--- a/src/bootstrap/src/core/build_steps/test.rs
+++ b/src/bootstrap/src/core/build_steps/test.rs
@@ -434,7 +434,7 @@ impl Miri {
         builder: &Builder<'_>,
         compiler: Compiler,
         target: TargetSelection,
-    ) -> String {
+    ) -> PathBuf {
         let miri_sysroot = builder.out.join(compiler.host.triple).join("miri-sysroot");
         let mut cargo = builder::Cargo::new(
             builder,
@@ -467,7 +467,7 @@ impl Miri {
         // Output is "<sysroot>\n".
         let sysroot = stdout.trim_end();
         builder.verbose(|| println!("`cargo miri setup --print-sysroot` said: {sysroot:?}"));
-        sysroot.to_owned()
+        PathBuf::from(sysroot)
     }
 }
 
@@ -520,12 +520,14 @@ impl Step for Miri {
         builder.ensure(compile::Std::new(target_compiler, host));
         let host_sysroot = builder.sysroot(target_compiler);
 
-        // Miri has its own "target dir" for ui test dependencies. Make sure it gets cleared
-        // properly when rustc changes. Similar to `Builder::cargo`, we skip this in dry runs to
-        // make sure the relevant compiler has been set up properly.
+        // Miri has its own "target dir" for ui test dependencies. Make sure it gets cleared when
+        // the sysroot gets rebuilt, to avoid "found possibly newer version of crate `std`" errors.
         if !builder.config.dry_run() {
             let ui_test_dep_dir = builder.stage_out(host_compiler, Mode::ToolStd).join("miri_ui");
-            builder.clear_if_dirty(&ui_test_dep_dir, &builder.rustc(host_compiler));
+            // The mtime of `miri_sysroot` changes when the sysroot gets rebuilt (also see
+            // <https://github.com/RalfJung/rustc-build-sysroot/commit/10ebcf60b80fe2c3dc765af0ff19fdc0da4b7466>).
+            // We can hence use that directly as a signal to clear the ui test dir.
+            builder.clear_if_dirty(&ui_test_dep_dir, &miri_sysroot);
         }
 
         // Run `cargo test`.

From 6863db5219267d7a8a8e82053ee4d1eb19840575 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Jakub=20Ber=C3=A1nek?= <jakub.beranek@vsb.cz>
Date: Mon, 12 Aug 2024 18:46:06 +0200
Subject: [PATCH 7/8] Remove unused script from run-make tests

---
 tests/run-make/git_clone_sha1.sh | 23 -----------------------
 1 file changed, 23 deletions(-)
 delete mode 100644 tests/run-make/git_clone_sha1.sh

diff --git a/tests/run-make/git_clone_sha1.sh b/tests/run-make/git_clone_sha1.sh
deleted file mode 100644
index 626e4e42761..00000000000
--- a/tests/run-make/git_clone_sha1.sh
+++ /dev/null
@@ -1,23 +0,0 @@
-#!/bin/bash -x
-
-# Usage: $0 project_name url sha1
-# Get the crate with the specified sha1.
-#
-# all arguments are required.
-#
-# See below link for git usage:
-# https://stackoverflow.com/questions/3489173#14091182
-
-# Mandatory arguments:
-PROJECT_NAME=$1
-URL=$2
-SHA1=$3
-
-function err_exit() {
-    echo "ERROR:" $*
-    exit 1
-}
-
-git clone $URL $PROJECT_NAME || err_exit
-cd $PROJECT_NAME || err_exit
-git reset --hard $SHA1 || err_exit

From 027b19fa9b85c3330d2eb38970c22e44873db2fc Mon Sep 17 00:00:00 2001
From: schvv31n <tim.kurdov@gmail.com>
Date: Mon, 12 Aug 2024 18:32:31 +0100
Subject: [PATCH 8/8] std::fmt::FormatterFn -> std::fmt::FromFn

---
 library/alloc/src/fmt.rs         |  2 +-
 library/core/src/fmt/builders.rs | 19 ++++++++++++++-----
 library/core/src/fmt/mod.rs      |  2 +-
 3 files changed, 16 insertions(+), 7 deletions(-)

diff --git a/library/alloc/src/fmt.rs b/library/alloc/src/fmt.rs
index 4b9b90fc1f1..571fcd177aa 100644
--- a/library/alloc/src/fmt.rs
+++ b/library/alloc/src/fmt.rs
@@ -581,7 +581,7 @@ pub use core::fmt::Alignment;
 #[stable(feature = "rust1", since = "1.0.0")]
 pub use core::fmt::Error;
 #[unstable(feature = "debug_closure_helpers", issue = "117729")]
-pub use core::fmt::FormatterFn;
+pub use core::fmt::{from_fn, FromFn};
 #[stable(feature = "rust1", since = "1.0.0")]
 pub use core::fmt::{write, Arguments};
 #[stable(feature = "rust1", since = "1.0.0")]
diff --git a/library/core/src/fmt/builders.rs b/library/core/src/fmt/builders.rs
index 794ca1851b1..467fa17a6f3 100644
--- a/library/core/src/fmt/builders.rs
+++ b/library/core/src/fmt/builders.rs
@@ -1018,7 +1018,8 @@ impl<'a, 'b: 'a> DebugMap<'a, 'b> {
     }
 }
 
-/// Implements [`fmt::Debug`] and [`fmt::Display`] using a function.
+/// Creates a type whose [`fmt::Debug`] and [`fmt::Display`] impls are provided with the function
+/// `f`.
 ///
 /// # Examples
 ///
@@ -1030,17 +1031,25 @@ impl<'a, 'b: 'a> DebugMap<'a, 'b> {
 /// assert_eq!(format!("{}", value), "a");
 /// assert_eq!(format!("{:?}", value), "'a'");
 ///
-/// let wrapped = fmt::FormatterFn(|f| write!(f, "{value:?}"));
+/// let wrapped = fmt::from_fn(|f| write!(f, "{value:?}"));
 /// assert_eq!(format!("{}", wrapped), "'a'");
 /// assert_eq!(format!("{:?}", wrapped), "'a'");
 /// ```
 #[unstable(feature = "debug_closure_helpers", issue = "117729")]
-pub struct FormatterFn<F>(pub F)
+pub fn from_fn<F: Fn(&mut fmt::Formatter<'_>) -> fmt::Result>(f: F) -> FromFn<F> {
+    FromFn(f)
+}
+
+/// Implements [`fmt::Debug`] and [`fmt::Display`] using a function.
+///
+/// Created with [`from_fn`].
+#[unstable(feature = "debug_closure_helpers", issue = "117729")]
+pub struct FromFn<F>(F)
 where
     F: Fn(&mut fmt::Formatter<'_>) -> fmt::Result;
 
 #[unstable(feature = "debug_closure_helpers", issue = "117729")]
-impl<F> fmt::Debug for FormatterFn<F>
+impl<F> fmt::Debug for FromFn<F>
 where
     F: Fn(&mut fmt::Formatter<'_>) -> fmt::Result,
 {
@@ -1050,7 +1059,7 @@ where
 }
 
 #[unstable(feature = "debug_closure_helpers", issue = "117729")]
-impl<F> fmt::Display for FormatterFn<F>
+impl<F> fmt::Display for FromFn<F>
 where
     F: Fn(&mut fmt::Formatter<'_>) -> fmt::Result,
 {
diff --git a/library/core/src/fmt/mod.rs b/library/core/src/fmt/mod.rs
index 60c0dc76852..485ad4aee19 100644
--- a/library/core/src/fmt/mod.rs
+++ b/library/core/src/fmt/mod.rs
@@ -34,7 +34,7 @@ pub enum Alignment {
 }
 
 #[unstable(feature = "debug_closure_helpers", issue = "117729")]
-pub use self::builders::FormatterFn;
+pub use self::builders::{from_fn, FromFn};
 #[stable(feature = "debug_builders", since = "1.2.0")]
 pub use self::builders::{DebugList, DebugMap, DebugSet, DebugStruct, DebugTuple};