about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--.github/workflows/ci.yml4
-rw-r--r--Cargo.lock1
-rw-r--r--compiler/rustc_ast_ir/src/visit.rs2
-rw-r--r--compiler/rustc_const_eval/src/interpret/validity.rs8
-rw-r--r--compiler/rustc_const_eval/src/interpret/visitor.rs10
-rw-r--r--compiler/rustc_driver_impl/src/lib.rs1
-rw-r--r--compiler/rustc_hir_analysis/src/check/intrinsic.rs4
-rw-r--r--compiler/rustc_hir_typeck/src/closure.rs17
-rw-r--r--compiler/rustc_interface/src/util.rs19
-rw-r--r--compiler/rustc_lint/Cargo.toml1
-rw-r--r--compiler/rustc_lint/src/non_local_def.rs34
-rw-r--r--compiler/rustc_metadata/src/locator.rs99
-rw-r--r--compiler/rustc_metadata/src/rmeta/decoder.rs24
-rw-r--r--compiler/rustc_middle/src/ty/instance.rs2
-rw-r--r--compiler/rustc_middle/src/ty/sty.rs7
-rw-r--r--compiler/rustc_parse/src/parser/diagnostics.rs2
-rw-r--r--compiler/rustc_query_system/src/query/job.rs22
-rw-r--r--compiler/rustc_query_system/src/query/mod.rs2
-rw-r--r--compiler/rustc_span/src/symbol.rs1
-rw-r--r--compiler/rustc_ty_utils/src/instance.rs37
-rw-r--r--compiler/rustc_type_ir/src/lib.rs14
-rw-r--r--library/alloc/src/boxed.rs24
-rw-r--r--library/core/src/any.rs11
-rw-r--r--library/core/src/intrinsics.rs14
-rw-r--r--library/core/src/ptr/const_ptr.rs6
-rw-r--r--library/core/src/ptr/mut_ptr.rs6
-rw-r--r--src/ci/docker/host-x86_64/x86_64-gnu-llvm-17/Dockerfile4
-rw-r--r--src/ci/docker/host-x86_64/x86_64-gnu-llvm-18/Dockerfile55
-rw-r--r--src/ci/github-actions/ci.yml5
-rw-r--r--src/tools/miri/src/borrow_tracker/mod.rs15
-rw-r--r--src/tools/miri/src/borrow_tracker/stacked_borrows/mod.rs34
-rw-r--r--src/tools/miri/src/borrow_tracker/tree_borrows/mod.rs33
-rw-r--r--src/tools/miri/src/shims/intrinsics/mod.rs13
-rw-r--r--src/tools/miri/tests/pass/box-custom-alloc-aliasing.rs123
-rw-r--r--src/tools/tidy/src/main.rs2
-rw-r--r--src/tools/tidy/src/ui_tests.rs5
-rw-r--r--tests/ui/lint/non_local_definitions.rs22
-rw-r--r--tests/ui/lint/non_local_definitions.stderr50
-rw-r--r--tests/ui/parser/help-set-edition-ice-122130.rs5
-rw-r--r--tests/ui/parser/help-set-edition-ice-122130.stderr21
-rw-r--r--tests/ui/trait-bounds/ice-unsized-struct-arg-issue-121612.rs13
-rw-r--r--tests/ui/trait-bounds/ice-unsized-struct-arg-issue-121612.stderr57
-rw-r--r--tests/ui/trait-bounds/ice-unsized-struct-arg-issue2-121424.rs9
-rw-r--r--tests/ui/trait-bounds/ice-unsized-struct-arg-issue2-121424.stderr30
44 files changed, 697 insertions, 171 deletions
diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
index 1d1056de25c..cd13ce35007 100644
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -315,6 +315,10 @@ jobs:
           - name: x86_64-gnu-distcheck
             os: ubuntu-20.04-8core-32gb
             env: {}
+          - name: x86_64-gnu-llvm-18
+            env:
+              RUST_BACKTRACE: 1
+            os: ubuntu-20.04-8core-32gb
           - name: x86_64-gnu-llvm-17
             env:
               RUST_BACKTRACE: 1
diff --git a/Cargo.lock b/Cargo.lock
index 218fa5a6842..1254421aa58 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -4133,7 +4133,6 @@ dependencies = [
  "rustc_target",
  "rustc_trait_selection",
  "rustc_type_ir",
- "smallvec",
  "tracing",
  "unicode-security",
 ]
diff --git a/compiler/rustc_ast_ir/src/visit.rs b/compiler/rustc_ast_ir/src/visit.rs
index dec9f7a47d0..f6d6bf3a3e3 100644
--- a/compiler/rustc_ast_ir/src/visit.rs
+++ b/compiler/rustc_ast_ir/src/visit.rs
@@ -14,7 +14,7 @@ impl VisitorResult for () {
     type Residual = !;
 
     #[cfg(not(feature = "nightly"))]
-    type Residual = core::ops::Infallible;
+    type Residual = core::convert::Infallible;
 
     fn output() -> Self {}
     fn from_residual(_: Self::Residual) -> Self {}
diff --git a/compiler/rustc_const_eval/src/interpret/validity.rs b/compiler/rustc_const_eval/src/interpret/validity.rs
index ff1cb43db86..c568f9acfd3 100644
--- a/compiler/rustc_const_eval/src/interpret/validity.rs
+++ b/compiler/rustc_const_eval/src/interpret/validity.rs
@@ -17,8 +17,8 @@ use rustc_middle::mir::interpret::{
     ExpectedKind, InterpError, InvalidMetaKind, Misalignment, PointerKind, Provenance,
     ValidationErrorInfo, ValidationErrorKind, ValidationErrorKind::*,
 };
-use rustc_middle::ty;
 use rustc_middle::ty::layout::{LayoutOf, TyAndLayout};
+use rustc_middle::ty::{self, Ty};
 use rustc_span::symbol::{sym, Symbol};
 use rustc_target::abi::{
     Abi, FieldIdx, Scalar as ScalarAbi, Size, VariantIdx, Variants, WrappingRange,
@@ -783,7 +783,11 @@ impl<'rt, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> ValueVisitor<'mir, 'tcx, M>
     }
 
     #[inline]
-    fn visit_box(&mut self, op: &OpTy<'tcx, M::Provenance>) -> InterpResult<'tcx> {
+    fn visit_box(
+        &mut self,
+        _box_ty: Ty<'tcx>,
+        op: &OpTy<'tcx, M::Provenance>,
+    ) -> InterpResult<'tcx> {
         self.check_safe_pointer(op, PointerKind::Box)?;
         Ok(())
     }
diff --git a/compiler/rustc_const_eval/src/interpret/visitor.rs b/compiler/rustc_const_eval/src/interpret/visitor.rs
index b200ecbf73a..0e824f3f592 100644
--- a/compiler/rustc_const_eval/src/interpret/visitor.rs
+++ b/compiler/rustc_const_eval/src/interpret/visitor.rs
@@ -3,7 +3,7 @@
 
 use rustc_index::IndexVec;
 use rustc_middle::mir::interpret::InterpResult;
-use rustc_middle::ty;
+use rustc_middle::ty::{self, Ty};
 use rustc_target::abi::FieldIdx;
 use rustc_target::abi::{FieldsShape, VariantIdx, Variants};
 
@@ -47,10 +47,10 @@ pub trait ValueVisitor<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>>: Sized {
         Ok(())
     }
     /// Visits the given value as the pointer of a `Box`. There is nothing to recurse into.
-    /// The type of `v` will be a raw pointer, but this is a field of `Box<T>` and the
-    /// pointee type is the actual `T`.
+    /// The type of `v` will be a raw pointer to `T`, but this is a field of `Box<T>` and the
+    /// pointee type is the actual `T`. `box_ty` provides the full type of the `Box` itself.
     #[inline(always)]
-    fn visit_box(&mut self, _v: &Self::V) -> InterpResult<'tcx> {
+    fn visit_box(&mut self, _box_ty: Ty<'tcx>, _v: &Self::V) -> InterpResult<'tcx> {
         Ok(())
     }
 
@@ -144,7 +144,7 @@ pub trait ValueVisitor<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>>: Sized {
                 assert_eq!(nonnull_ptr.layout().fields.count(), 1);
                 let raw_ptr = self.ecx().project_field(&nonnull_ptr, 0)?; // the actual raw ptr
                 // ... whose only field finally is a raw ptr we can dereference.
-                self.visit_box(&raw_ptr)?;
+                self.visit_box(ty, &raw_ptr)?;
 
                 // The second `Box` field is the allocator, which we recursively check for validity
                 // like in regular structs.
diff --git a/compiler/rustc_driver_impl/src/lib.rs b/compiler/rustc_driver_impl/src/lib.rs
index e06d1d245b2..2802f44cda7 100644
--- a/compiler/rustc_driver_impl/src/lib.rs
+++ b/compiler/rustc_driver_impl/src/lib.rs
@@ -676,6 +676,7 @@ fn list_metadata(early_dcx: &EarlyDiagCtxt, sess: &Session, metadata_loader: &dy
                 metadata_loader,
                 &mut v,
                 &sess.opts.unstable_opts.ls,
+                sess.cfg_version,
             )
             .unwrap();
             safe_println!("{}", String::from_utf8(v).unwrap());
diff --git a/compiler/rustc_hir_analysis/src/check/intrinsic.rs b/compiler/rustc_hir_analysis/src/check/intrinsic.rs
index 95c51cc0486..5a74bdc8a84 100644
--- a/compiler/rustc_hir_analysis/src/check/intrinsic.rs
+++ b/compiler/rustc_hir_analysis/src/check/intrinsic.rs
@@ -657,6 +657,10 @@ pub fn check_intrinsic_type(
             sym::simd_shuffle => (3, 0, vec![param(0), param(0), param(1)], param(2)),
             sym::simd_shuffle_generic => (2, 1, vec![param(0), param(0)], param(1)),
 
+            sym::retag_box_to_raw => {
+                (2, 0, vec![Ty::new_mut_ptr(tcx, param(0))], Ty::new_mut_ptr(tcx, param(0)))
+            }
+
             other => {
                 tcx.dcx().emit_err(UnrecognizedIntrinsicFunction { span, name: other });
                 return;
diff --git a/compiler/rustc_hir_typeck/src/closure.rs b/compiler/rustc_hir_typeck/src/closure.rs
index 1ff961a9089..c17af666eb9 100644
--- a/compiler/rustc_hir_typeck/src/closure.rs
+++ b/compiler/rustc_hir_typeck/src/closure.rs
@@ -19,7 +19,7 @@ use rustc_target::spec::abi::Abi;
 use rustc_trait_selection::traits;
 use rustc_trait_selection::traits::error_reporting::ArgKind;
 use rustc_trait_selection::traits::error_reporting::InferCtxtExt as _;
-use std::cmp;
+use rustc_type_ir::ClosureKind;
 use std::iter;
 use std::ops::ControlFlow;
 
@@ -437,10 +437,17 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                 };
 
                 if let Some(found_kind) = found_kind {
-                    expected_kind = Some(
-                        expected_kind
-                            .map_or_else(|| found_kind, |current| cmp::min(current, found_kind)),
-                    );
+                    // always use the closure kind that is more permissive.
+                    match (expected_kind, found_kind) {
+                        (None, _) => expected_kind = Some(found_kind),
+                        (Some(ClosureKind::FnMut), ClosureKind::Fn) => {
+                            expected_kind = Some(ClosureKind::Fn)
+                        }
+                        (Some(ClosureKind::FnOnce), ClosureKind::Fn | ClosureKind::FnMut) => {
+                            expected_kind = Some(found_kind)
+                        }
+                        _ => {}
+                    }
                 }
             }
         }
diff --git a/compiler/rustc_interface/src/util.rs b/compiler/rustc_interface/src/util.rs
index 0d50200133c..23bd2dac57e 100644
--- a/compiler/rustc_interface/src/util.rs
+++ b/compiler/rustc_interface/src/util.rs
@@ -101,10 +101,11 @@ pub(crate) fn run_in_thread_pool_with_globals<F: FnOnce() -> R + Send, R: Send>(
     threads: usize,
     f: F,
 ) -> R {
-    use rustc_data_structures::{jobserver, sync::FromDyn};
+    use rustc_data_structures::{defer, jobserver, sync::FromDyn};
     use rustc_middle::ty::tls;
     use rustc_query_impl::QueryCtxt;
-    use rustc_query_system::query::{deadlock, QueryContext};
+    use rustc_query_system::query::{break_query_cycles, QueryContext};
+    use std::process;
 
     let registry = sync::Registry::new(std::num::NonZero::new(threads).unwrap());
 
@@ -128,7 +129,19 @@ pub(crate) fn run_in_thread_pool_with_globals<F: FnOnce() -> R + Send, R: Send>(
             let query_map =
                 FromDyn::from(tls::with(|tcx| QueryCtxt::new(tcx).collect_active_jobs()));
             let registry = rayon_core::Registry::current();
-            thread::spawn(move || deadlock(query_map.into_inner(), &registry));
+            thread::Builder::new()
+                .name("rustc query cycle handler".to_string())
+                .spawn(move || {
+                    let on_panic = defer(|| {
+                        eprintln!("query cycle handler thread panicked, aborting process");
+                        // We need to abort here as we failed to resolve the deadlock,
+                        // otherwise the compiler could just hang,
+                        process::abort();
+                    });
+                    break_query_cycles(query_map.into_inner(), &registry);
+                    on_panic.disable();
+                })
+                .unwrap();
         });
     if let Some(size) = get_stack_size() {
         builder = builder.stack_size(size);
diff --git a/compiler/rustc_lint/Cargo.toml b/compiler/rustc_lint/Cargo.toml
index 2271321b8bf..fa1133e7780 100644
--- a/compiler/rustc_lint/Cargo.toml
+++ b/compiler/rustc_lint/Cargo.toml
@@ -23,7 +23,6 @@ rustc_span = { path = "../rustc_span" }
 rustc_target = { path = "../rustc_target" }
 rustc_trait_selection = { path = "../rustc_trait_selection" }
 rustc_type_ir = { path = "../rustc_type_ir" }
-smallvec = { version = "1.8.1", features = ["union", "may_dangle"] }
 tracing = "0.1"
 unicode-security = "0.1.0"
 # tidy-alphabetical-end
diff --git a/compiler/rustc_lint/src/non_local_def.rs b/compiler/rustc_lint/src/non_local_def.rs
index a4fd5a7c45f..7c4d92d3ce0 100644
--- a/compiler/rustc_lint/src/non_local_def.rs
+++ b/compiler/rustc_lint/src/non_local_def.rs
@@ -2,8 +2,6 @@ use rustc_hir::{def::DefKind, Body, Item, ItemKind, Node, Path, QPath, TyKind};
 use rustc_span::def_id::{DefId, LOCAL_CRATE};
 use rustc_span::{sym, symbol::kw, ExpnKind, MacroKind};
 
-use smallvec::{smallvec, SmallVec};
-
 use crate::lints::{NonLocalDefinitionsCargoUpdateNote, NonLocalDefinitionsDiag};
 use crate::{LateContext, LateLintPass, LintContext};
 
@@ -85,7 +83,7 @@ impl<'tcx> LateLintPass<'tcx> for NonLocalDefinitions {
             if let Some(def_id) = oexpn.macro_def_id
                 && let ExpnKind::Macro(macro_kind, macro_name) = oexpn.kind
                 && def_id.krate != LOCAL_CRATE
-                && std::env::var_os("CARGO").is_some()
+                && rustc_session::utils::was_invoked_from_cargo()
             {
                 Some(NonLocalDefinitionsCargoUpdateNote {
                     macro_kind: macro_kind.descr(),
@@ -114,25 +112,25 @@ impl<'tcx> LateLintPass<'tcx> for NonLocalDefinitions {
                 // is using local items and so we don't lint on it.
 
                 // We also ignore anon-const in item by including the anon-const
-                // parent as well; and since it's quite uncommon, we use smallvec
-                // to avoid unnecessary heap allocations.
-                let local_parents: SmallVec<[DefId; 1]> = if parent_def_kind == DefKind::Const
+                // parent as well.
+                let parent_parent = if parent_def_kind == DefKind::Const
                     && parent_opt_item_name == Some(kw::Underscore)
                 {
-                    smallvec![parent, cx.tcx.parent(parent)]
+                    Some(cx.tcx.parent(parent))
                 } else {
-                    smallvec![parent]
+                    None
                 };
 
                 let self_ty_has_local_parent = match impl_.self_ty.kind {
                     TyKind::Path(QPath::Resolved(_, ty_path)) => {
-                        path_has_local_parent(ty_path, cx, &*local_parents)
+                        path_has_local_parent(ty_path, cx, parent, parent_parent)
                     }
                     TyKind::TraitObject([principle_poly_trait_ref, ..], _, _) => {
                         path_has_local_parent(
                             principle_poly_trait_ref.trait_ref.path,
                             cx,
-                            &*local_parents,
+                            parent,
+                            parent_parent,
                         )
                     }
                     TyKind::TraitObject([], _, _)
@@ -154,7 +152,7 @@ impl<'tcx> LateLintPass<'tcx> for NonLocalDefinitions {
 
                 let of_trait_has_local_parent = impl_
                     .of_trait
-                    .map(|of_trait| path_has_local_parent(of_trait.path, cx, &*local_parents))
+                    .map(|of_trait| path_has_local_parent(of_trait.path, cx, parent, parent_parent))
                     .unwrap_or(false);
 
                 // If none of them have a local parent (LOGICAL NOR) this means that
@@ -218,6 +216,16 @@ impl<'tcx> LateLintPass<'tcx> for NonLocalDefinitions {
 ///    std::convert::PartialEq<Foo<Bar>>
 ///    ^^^^^^^^^^^^^^^^^^^^^^^
 /// ```
-fn path_has_local_parent(path: &Path<'_>, cx: &LateContext<'_>, local_parents: &[DefId]) -> bool {
-    path.res.opt_def_id().is_some_and(|did| local_parents.contains(&cx.tcx.parent(did)))
+fn path_has_local_parent(
+    path: &Path<'_>,
+    cx: &LateContext<'_>,
+    impl_parent: DefId,
+    impl_parent_parent: Option<DefId>,
+) -> bool {
+    path.res.opt_def_id().is_some_and(|did| {
+        did.is_local() && {
+            let res_parent = cx.tcx.parent(did);
+            res_parent == impl_parent || Some(res_parent) == impl_parent_parent
+        }
+    })
 }
diff --git a/compiler/rustc_metadata/src/locator.rs b/compiler/rustc_metadata/src/locator.rs
index dcccace12b0..10bbebb3871 100644
--- a/compiler/rustc_metadata/src/locator.rs
+++ b/compiler/rustc_metadata/src/locator.rs
@@ -569,31 +569,47 @@ impl<'a> CrateLocator<'a> {
                 debug!("skipping empty file");
                 continue;
             }
-            let (hash, metadata) =
-                match get_metadata_section(self.target, flavor, &lib, self.metadata_loader) {
-                    Ok(blob) => {
-                        if let Some(h) = self.crate_matches(&blob, &lib) {
-                            (h, blob)
-                        } else {
-                            info!("metadata mismatch");
-                            continue;
-                        }
-                    }
-                    Err(MetadataError::LoadFailure(err)) => {
-                        info!("no metadata found: {}", err);
-                        // The file was present and created by the same compiler version, but we
-                        // couldn't load it for some reason. Give a hard error instead of silently
-                        // ignoring it, but only if we would have given an error anyway.
-                        self.crate_rejections
-                            .via_invalid
-                            .push(CrateMismatch { path: lib, got: err });
-                        continue;
-                    }
-                    Err(err @ MetadataError::NotPresent(_)) => {
-                        info!("no metadata found: {}", err);
+            let (hash, metadata) = match get_metadata_section(
+                self.target,
+                flavor,
+                &lib,
+                self.metadata_loader,
+                self.cfg_version,
+            ) {
+                Ok(blob) => {
+                    if let Some(h) = self.crate_matches(&blob, &lib) {
+                        (h, blob)
+                    } else {
+                        info!("metadata mismatch");
                         continue;
                     }
-                };
+                }
+                Err(MetadataError::VersionMismatch { expected_version, found_version }) => {
+                    // The file was present and created by the same compiler version, but we
+                    // couldn't load it for some reason. Give a hard error instead of silently
+                    // ignoring it, but only if we would have given an error anyway.
+                    info!(
+                        "Rejecting via version: expected {} got {}",
+                        expected_version, found_version
+                    );
+                    self.crate_rejections
+                        .via_version
+                        .push(CrateMismatch { path: lib, got: found_version });
+                    continue;
+                }
+                Err(MetadataError::LoadFailure(err)) => {
+                    info!("no metadata found: {}", err);
+                    // The file was present and created by the same compiler version, but we
+                    // couldn't load it for some reason. Give a hard error instead of silently
+                    // ignoring it, but only if we would have given an error anyway.
+                    self.crate_rejections.via_invalid.push(CrateMismatch { path: lib, got: err });
+                    continue;
+                }
+                Err(err @ MetadataError::NotPresent(_)) => {
+                    info!("no metadata found: {}", err);
+                    continue;
+                }
+            };
             // If we see multiple hashes, emit an error about duplicate candidates.
             if slot.as_ref().is_some_and(|s| s.0 != hash) {
                 if let Some(candidates) = err_data {
@@ -648,16 +664,6 @@ impl<'a> CrateLocator<'a> {
     }
 
     fn crate_matches(&mut self, metadata: &MetadataBlob, libpath: &Path) -> Option<Svh> {
-        let rustc_version = rustc_version(self.cfg_version);
-        let found_version = metadata.get_rustc_version();
-        if found_version != rustc_version {
-            info!("Rejecting via version: expected {} got {}", rustc_version, found_version);
-            self.crate_rejections
-                .via_version
-                .push(CrateMismatch { path: libpath.to_path_buf(), got: found_version });
-            return None;
-        }
-
         let header = metadata.get_header();
         if header.is_proc_macro_crate != self.is_proc_macro {
             info!(
@@ -770,6 +776,7 @@ fn get_metadata_section<'p>(
     flavor: CrateFlavor,
     filename: &'p Path,
     loader: &dyn MetadataLoader,
+    cfg_version: &'static str,
 ) -> Result<MetadataBlob, MetadataError<'p>> {
     if !filename.exists() {
         return Err(MetadataError::NotPresent(filename));
@@ -847,13 +854,18 @@ fn get_metadata_section<'p>(
         }
     };
     let blob = MetadataBlob(raw_bytes);
-    if blob.is_compatible() {
-        Ok(blob)
-    } else {
-        Err(MetadataError::LoadFailure(format!(
+    match blob.check_compatibility(cfg_version) {
+        Ok(()) => Ok(blob),
+        Err(None) => Err(MetadataError::LoadFailure(format!(
             "invalid metadata version found: {}",
             filename.display()
-        )))
+        ))),
+        Err(Some(found_version)) => {
+            return Err(MetadataError::VersionMismatch {
+                expected_version: rustc_version(cfg_version),
+                found_version,
+            });
+        }
     }
 }
 
@@ -864,9 +876,10 @@ pub fn list_file_metadata(
     metadata_loader: &dyn MetadataLoader,
     out: &mut dyn Write,
     ls_kinds: &[String],
+    cfg_version: &'static str,
 ) -> IoResult<()> {
     let flavor = get_flavor_from_path(path);
-    match get_metadata_section(target, flavor, path, metadata_loader) {
+    match get_metadata_section(target, flavor, path, metadata_loader, cfg_version) {
         Ok(metadata) => metadata.list_crate_metadata(out, ls_kinds),
         Err(msg) => write!(out, "{msg}\n"),
     }
@@ -932,6 +945,8 @@ enum MetadataError<'a> {
     NotPresent(&'a Path),
     /// The file was present and invalid.
     LoadFailure(String),
+    /// The file was present, but compiled with a different rustc version.
+    VersionMismatch { expected_version: String, found_version: String },
 }
 
 impl fmt::Display for MetadataError<'_> {
@@ -941,6 +956,12 @@ impl fmt::Display for MetadataError<'_> {
                 f.write_str(&format!("no such file: '{}'", filename.display()))
             }
             MetadataError::LoadFailure(msg) => f.write_str(msg),
+            MetadataError::VersionMismatch { expected_version, found_version } => {
+                f.write_str(&format!(
+                    "rustc version mismatch. expected {}, found {}",
+                    expected_version, found_version,
+                ))
+            }
         }
     }
 }
diff --git a/compiler/rustc_metadata/src/rmeta/decoder.rs b/compiler/rustc_metadata/src/rmeta/decoder.rs
index da384007c22..0467cf2969f 100644
--- a/compiler/rustc_metadata/src/rmeta/decoder.rs
+++ b/compiler/rustc_metadata/src/rmeta/decoder.rs
@@ -684,13 +684,25 @@ impl<'a, 'tcx, I: Idx, T> Decodable<DecodeContext<'a, 'tcx>> for LazyTable<I, T>
 implement_ty_decoder!(DecodeContext<'a, 'tcx>);
 
 impl MetadataBlob {
-    pub(crate) fn is_compatible(&self) -> bool {
-        self.blob().starts_with(METADATA_HEADER)
-    }
+    pub(crate) fn check_compatibility(
+        &self,
+        cfg_version: &'static str,
+    ) -> Result<(), Option<String>> {
+        if !self.blob().starts_with(METADATA_HEADER) {
+            if self.blob().starts_with(b"rust") {
+                return Err(Some("<unknown rustc version>".to_owned()));
+            }
+            return Err(None);
+        }
 
-    pub(crate) fn get_rustc_version(&self) -> String {
-        LazyValue::<String>::from_position(NonZero::new(METADATA_HEADER.len() + 8).unwrap())
-            .decode(self)
+        let found_version =
+            LazyValue::<String>::from_position(NonZero::new(METADATA_HEADER.len() + 8).unwrap())
+                .decode(self);
+        if rustc_version(cfg_version) != found_version {
+            return Err(Some(found_version));
+        }
+
+        Ok(())
     }
 
     fn root_pos(&self) -> NonZero<usize> {
diff --git a/compiler/rustc_middle/src/ty/instance.rs b/compiler/rustc_middle/src/ty/instance.rs
index 9fc8d418f5b..814c3629b08 100644
--- a/compiler/rustc_middle/src/ty/instance.rs
+++ b/compiler/rustc_middle/src/ty/instance.rs
@@ -30,7 +30,7 @@ pub struct Instance<'tcx> {
     pub args: GenericArgsRef<'tcx>,
 }
 
-#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)]
+#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)]
 #[derive(TyEncodable, TyDecodable, HashStable, TypeFoldable, TypeVisitable, Lift)]
 pub enum InstanceDef<'tcx> {
     /// A user-defined callable item.
diff --git a/compiler/rustc_middle/src/ty/sty.rs b/compiler/rustc_middle/src/ty/sty.rs
index 427c0f04bd1..39b5d3b6ea7 100644
--- a/compiler/rustc_middle/src/ty/sty.rs
+++ b/compiler/rustc_middle/src/ty/sty.rs
@@ -2008,13 +2008,10 @@ impl<'tcx> Ty<'tcx> {
                     // Single-argument Box is always global. (for "minicore" tests)
                     return true;
                 };
-                if let Some(alloc_adt) = alloc.expect_ty().ty_adt_def() {
+                alloc.expect_ty().ty_adt_def().is_some_and(|alloc_adt| {
                     let global_alloc = tcx.require_lang_item(LangItem::GlobalAlloc, None);
                     alloc_adt.did() == global_alloc
-                } else {
-                    // Allocator is not an ADT...
-                    false
-                }
+                })
             }
             _ => false,
         }
diff --git a/compiler/rustc_parse/src/parser/diagnostics.rs b/compiler/rustc_parse/src/parser/diagnostics.rs
index 2f7ac7d3a12..de088b9364b 100644
--- a/compiler/rustc_parse/src/parser/diagnostics.rs
+++ b/compiler/rustc_parse/src/parser/diagnostics.rs
@@ -667,7 +667,7 @@ impl<'a> Parser<'a> {
         {
             err.note("you may be trying to write a c-string literal");
             err.note("c-string literals require Rust 2021 or later");
-            HelpUseLatestEdition::new().add_to_diagnostic(&mut err);
+            err.subdiagnostic(self.dcx(), HelpUseLatestEdition::new());
         }
 
         // `pub` may be used for an item or `pub(crate)`
diff --git a/compiler/rustc_query_system/src/query/job.rs b/compiler/rustc_query_system/src/query/job.rs
index 1a54a229357..248a741af90 100644
--- a/compiler/rustc_query_system/src/query/job.rs
+++ b/compiler/rustc_query_system/src/query/job.rs
@@ -17,10 +17,9 @@ use std::num::NonZero;
 use {
     parking_lot::{Condvar, Mutex},
     rustc_data_structures::fx::FxHashSet,
-    rustc_data_structures::{defer, jobserver},
+    rustc_data_structures::jobserver,
     rustc_span::DUMMY_SP,
     std::iter,
-    std::process,
     std::sync::Arc,
 };
 
@@ -514,12 +513,7 @@ fn remove_cycle(
 /// There may be multiple cycles involved in a deadlock, so this searches
 /// all active queries for cycles before finally resuming all the waiters at once.
 #[cfg(parallel_compiler)]
-pub fn deadlock(query_map: QueryMap, registry: &rayon_core::Registry) {
-    let on_panic = defer(|| {
-        eprintln!("deadlock handler panicked, aborting process");
-        process::abort();
-    });
-
+pub fn break_query_cycles(query_map: QueryMap, registry: &rayon_core::Registry) {
     let mut wakelist = Vec::new();
     let mut jobs: Vec<QueryJobId> = query_map.keys().cloned().collect();
 
@@ -539,19 +533,17 @@ pub fn deadlock(query_map: QueryMap, registry: &rayon_core::Registry) {
     // X to Y due to Rayon waiting and a true dependency from Y to X. The algorithm here
     // only considers the true dependency and won't detect a cycle.
     if !found_cycle {
-        if query_map.len() == 0 {
-            panic!("deadlock detected without any query!")
-        } else {
-            panic!("deadlock detected! current query map:\n{:#?}", query_map);
-        }
+        panic!(
+            "deadlock detected as we're unable to find a query cycle to break\n\
+            current query map:\n{:#?}",
+            query_map
+        );
     }
 
     // FIXME: Ensure this won't cause a deadlock before we return
     for waiter in wakelist.into_iter() {
         waiter.notify(registry);
     }
-
-    on_panic.disable();
 }
 
 #[inline(never)]
diff --git a/compiler/rustc_query_system/src/query/mod.rs b/compiler/rustc_query_system/src/query/mod.rs
index 0aefe553a34..01b9d458f1e 100644
--- a/compiler/rustc_query_system/src/query/mod.rs
+++ b/compiler/rustc_query_system/src/query/mod.rs
@@ -3,7 +3,7 @@ pub use self::plumbing::*;
 
 mod job;
 #[cfg(parallel_compiler)]
-pub use self::job::deadlock;
+pub use self::job::break_query_cycles;
 pub use self::job::{
     print_query_stack, report_cycle, QueryInfo, QueryJob, QueryJobId, QueryJobInfo, QueryMap,
 };
diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs
index 80c4dcb6b18..62b7ff8a449 100644
--- a/compiler/rustc_span/src/symbol.rs
+++ b/compiler/rustc_span/src/symbol.rs
@@ -1450,6 +1450,7 @@ symbols! {
         residual,
         result,
         resume,
+        retag_box_to_raw,
         return_position_impl_trait_in_trait,
         return_type_notation,
         rhs,
diff --git a/compiler/rustc_ty_utils/src/instance.rs b/compiler/rustc_ty_utils/src/instance.rs
index 381681fb1f4..2816bcc888b 100644
--- a/compiler/rustc_ty_utils/src/instance.rs
+++ b/compiler/rustc_ty_utils/src/instance.rs
@@ -7,6 +7,7 @@ use rustc_middle::ty::GenericArgsRef;
 use rustc_middle::ty::{self, Instance, TyCtxt, TypeVisitableExt};
 use rustc_span::sym;
 use rustc_trait_selection::traits;
+use rustc_type_ir::ClosureKind;
 use traits::{translate_args, Reveal};
 
 use crate::errors::UnexpectedFnPtrAssociatedItem;
@@ -296,23 +297,25 @@ fn resolve_associated_item<'tcx>(
             {
                 match *rcvr_args.type_at(0).kind() {
                     ty::CoroutineClosure(coroutine_closure_def_id, args) => {
-                        // If we're computing `AsyncFnOnce`/`AsyncFnMut` for a by-ref closure,
-                        // or `AsyncFnOnce` for a by-mut closure, then construct a new body that
-                        // has the right return types.
-                        //
-                        // Specifically, `AsyncFnMut` for a by-ref coroutine-closure just needs
-                        // to have its input and output types fixed (`&mut self` and returning
-                        // `i16` coroutine kind).
-                        if target_kind > args.as_coroutine_closure().kind() {
-                            Some(Instance {
-                                def: ty::InstanceDef::ConstructCoroutineInClosureShim {
-                                    coroutine_closure_def_id,
-                                    target_kind,
-                                },
-                                args,
-                            })
-                        } else {
-                            Some(Instance::new(coroutine_closure_def_id, args))
+                        match (target_kind, args.as_coroutine_closure().kind()) {
+                            (ClosureKind::FnOnce | ClosureKind::FnMut, ClosureKind::Fn)
+                            | (ClosureKind::FnOnce, ClosureKind::FnMut) => {
+                                // If we're computing `AsyncFnOnce`/`AsyncFnMut` for a by-ref closure,
+                                // or `AsyncFnOnce` for a by-mut closure, then construct a new body that
+                                // has the right return types.
+                                //
+                                // Specifically, `AsyncFnMut` for a by-ref coroutine-closure just needs
+                                // to have its input and output types fixed (`&mut self` and returning
+                                // `i16` coroutine kind).
+                                Some(Instance {
+                                    def: ty::InstanceDef::ConstructCoroutineInClosureShim {
+                                        coroutine_closure_def_id,
+                                        target_kind,
+                                    },
+                                    args,
+                                })
+                            }
+                            _ => Some(Instance::new(coroutine_closure_def_id, args)),
                         }
                     }
                     ty::Closure(closure_def_id, args) => {
diff --git a/compiler/rustc_type_ir/src/lib.rs b/compiler/rustc_type_ir/src/lib.rs
index 2ded1b956e5..c01baa58ae7 100644
--- a/compiler/rustc_type_ir/src/lib.rs
+++ b/compiler/rustc_type_ir/src/lib.rs
@@ -369,12 +369,9 @@ rustc_index::newtype_index! {
 ///
 /// You can get the environment type of a closure using
 /// `tcx.closure_env_ty()`.
-#[derive(Clone, Copy, PartialOrd, Ord, PartialEq, Eq, Hash, Debug)]
+#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)]
 #[cfg_attr(feature = "nightly", derive(Encodable, Decodable, HashStable_NoContext))]
 pub enum ClosureKind {
-    // Warning: Ordering is significant here! The ordering is chosen
-    // because the trait Fn is a subtrait of FnMut and so in turn, and
-    // hence we order it so that Fn < FnMut < FnOnce.
     Fn,
     FnMut,
     FnOnce,
@@ -394,8 +391,15 @@ impl ClosureKind {
 
     /// Returns `true` if a type that impls this closure kind
     /// must also implement `other`.
+    #[rustfmt::skip]
     pub fn extends(self, other: ClosureKind) -> bool {
-        self <= other
+        use ClosureKind::*;
+        match (self, other) {
+              (Fn, Fn | FnMut | FnOnce)
+            | (FnMut,   FnMut | FnOnce)
+            | (FnOnce,          FnOnce) => true,
+            _ => false,
+        }
     }
 }
 
diff --git a/library/alloc/src/boxed.rs b/library/alloc/src/boxed.rs
index 2736e5ee6c5..304f607000b 100644
--- a/library/alloc/src/boxed.rs
+++ b/library/alloc/src/boxed.rs
@@ -155,6 +155,7 @@ use core::error::Error;
 use core::fmt;
 use core::future::Future;
 use core::hash::{Hash, Hasher};
+use core::intrinsics::retag_box_to_raw;
 use core::iter::FusedIterator;
 use core::marker::Tuple;
 use core::marker::Unsize;
@@ -1110,8 +1111,16 @@ impl<T: ?Sized, A: Allocator> Box<T, A> {
     #[unstable(feature = "allocator_api", issue = "32838")]
     #[inline]
     pub fn into_raw_with_allocator(b: Self) -> (*mut T, A) {
-        let (leaked, alloc) = Box::into_unique(b);
-        (leaked.as_ptr(), alloc)
+        // This is the transition point from `Box` to raw pointers. For Stacked Borrows, these casts
+        // are relevant -- if this is a global allocator Box and we just get the pointer from `b.0`,
+        // it will have `Unique` permission, which is not what we want from a raw pointer. We could
+        // fix that by going through `&mut`, but then if this is *not* a global allocator Box, we'd
+        // be adding uniqueness assertions that we do not want. So for Miri's sake we pass this
+        // pointer through an intrinsic for box-to-raw casts, which can do the right thing wrt the
+        // aliasing model.
+        let b = mem::ManuallyDrop::new(b);
+        let alloc = unsafe { ptr::read(&b.1) };
+        (unsafe { retag_box_to_raw::<T, A>(b.0.as_ptr()) }, alloc)
     }
 
     #[unstable(
@@ -1122,13 +1131,8 @@ impl<T: ?Sized, A: Allocator> Box<T, A> {
     #[inline]
     #[doc(hidden)]
     pub fn into_unique(b: Self) -> (Unique<T>, A) {
-        // Box is recognized as a "unique pointer" by Stacked Borrows, but internally it is a
-        // raw pointer for the type system. Turning it directly into a raw pointer would not be
-        // recognized as "releasing" the unique pointer to permit aliased raw accesses,
-        // so all raw pointer methods have to go through `Box::leak`. Turning *that* to a raw pointer
-        // behaves correctly.
-        let alloc = unsafe { ptr::read(&b.1) };
-        (Unique::from(Box::leak(b)), alloc)
+        let (ptr, alloc) = Box::into_raw_with_allocator(b);
+        unsafe { (Unique::from(&mut *ptr), alloc) }
     }
 
     /// Returns a reference to the underlying allocator.
@@ -1184,7 +1188,7 @@ impl<T: ?Sized, A: Allocator> Box<T, A> {
     where
         A: 'a,
     {
-        unsafe { &mut *mem::ManuallyDrop::new(b).0.as_ptr() }
+        unsafe { &mut *Box::into_raw(b) }
     }
 
     /// Converts a `Box<T>` into a `Pin<Box<T>>`. If `T` does not implement [`Unpin`], then
diff --git a/library/core/src/any.rs b/library/core/src/any.rs
index e8f00e8760e..a4252d0c9e0 100644
--- a/library/core/src/any.rs
+++ b/library/core/src/any.rs
@@ -605,7 +605,9 @@ impl dyn Any + Send + Sync {
 #[derive(Clone, Copy, Debug, Eq, PartialOrd, Ord)]
 #[stable(feature = "rust1", since = "1.0.0")]
 pub struct TypeId {
-    t: u128,
+    // We avoid using `u128` because that imposes higher alignment requirements on many platforms.
+    // See issue #115620 for more information.
+    t: (u64, u64),
 }
 
 #[stable(feature = "rust1", since = "1.0.0")]
@@ -637,7 +639,10 @@ impl TypeId {
     #[rustc_const_unstable(feature = "const_type_id", issue = "77125")]
     pub const fn of<T: ?Sized + 'static>() -> TypeId {
         let t: u128 = intrinsics::type_id::<T>();
-        TypeId { t }
+
+        let t1 = (t >> 64) as u64;
+        let t2 = t as u64;
+        TypeId { t: (t1, t2) }
     }
 }
 
@@ -657,7 +662,7 @@ impl hash::Hash for TypeId {
         // - It is correct to do so -- only hashing a subset of `self` is still
         //   with an `Eq` implementation that considers the entire value, as
         //   ours does.
-        (self.t as u64).hash(state);
+        self.t.1.hash(state);
     }
 }
 
diff --git a/library/core/src/intrinsics.rs b/library/core/src/intrinsics.rs
index aff1c589e62..6b5be700f57 100644
--- a/library/core/src/intrinsics.rs
+++ b/library/core/src/intrinsics.rs
@@ -2695,6 +2695,19 @@ pub unsafe fn vtable_size(_ptr: *const ()) -> usize {
     unreachable!()
 }
 
+/// Retag a box pointer as part of casting it to a raw pointer. This is the `Box` equivalent of
+/// `(x: &mut T) as *mut T`. The input pointer must be the pointer of a `Box` (passed as raw pointer
+/// to avoid all questions around move semantics and custom allocators), and `A` must be the `Box`'s
+/// allocator.
+#[unstable(feature = "core_intrinsics", issue = "none")]
+#[rustc_nounwind]
+#[cfg_attr(not(bootstrap), rustc_intrinsic)]
+#[cfg_attr(bootstrap, inline)]
+pub unsafe fn retag_box_to_raw<T: ?Sized, A>(ptr: *mut T) -> *mut T {
+    // Miri needs to adjust the provenance, but for regular codegen this is not needed
+    ptr
+}
+
 // Some functions are defined here because they accidentally got made
 // available in this module on stable. See <https://github.com/rust-lang/rust/issues/15702>.
 // (`transmute` also falls into this category, but it cannot be wrapped due to the
@@ -3120,6 +3133,7 @@ pub(crate) const fn miri_promise_symbolic_alignment(ptr: *const (), align: usize
 
     const fn compiletime(_ptr: *const (), _align: usize) {}
 
+    #[cfg_attr(not(bootstrap), allow(unused_unsafe))] // on bootstrap bump, remove unsafe block
     // SAFETY: the extra behavior at runtime is for UB checks only.
     unsafe {
         const_eval_select((ptr, align), compiletime, runtime);
diff --git a/library/core/src/ptr/const_ptr.rs b/library/core/src/ptr/const_ptr.rs
index 0c69bf2aef9..90dbc798fcf 100644
--- a/library/core/src/ptr/const_ptr.rs
+++ b/library/core/src/ptr/const_ptr.rs
@@ -1628,12 +1628,12 @@ impl<T: ?Sized> *const T {
         #[inline]
         const fn const_impl(ptr: *const (), align: usize) -> bool {
             // We can't use the address of `self` in a `const fn`, so we use `align_offset` instead.
-            // The cast to `()` is used to
-            //   1. deal with fat pointers; and
-            //   2. ensure that `align_offset` doesn't actually try to compute an offset.
             ptr.align_offset(align) == 0
         }
 
+        // The cast to `()` is used to
+        //   1. deal with fat pointers; and
+        //   2. ensure that `align_offset` (in `const_impl`) doesn't actually try to compute an offset.
         #[cfg_attr(not(bootstrap), allow(unused_unsafe))] // on bootstrap bump, remove unsafe block
         // SAFETY: The two versions are equivalent at runtime.
         unsafe {
diff --git a/library/core/src/ptr/mut_ptr.rs b/library/core/src/ptr/mut_ptr.rs
index 5ce3b1f298c..6a9033a144d 100644
--- a/library/core/src/ptr/mut_ptr.rs
+++ b/library/core/src/ptr/mut_ptr.rs
@@ -1900,12 +1900,12 @@ impl<T: ?Sized> *mut T {
         #[inline]
         const fn const_impl(ptr: *mut (), align: usize) -> bool {
             // We can't use the address of `self` in a `const fn`, so we use `align_offset` instead.
-            // The cast to `()` is used to
-            //   1. deal with fat pointers; and
-            //   2. ensure that `align_offset` doesn't actually try to compute an offset.
             ptr.align_offset(align) == 0
         }
 
+        // The cast to `()` is used to
+        //   1. deal with fat pointers; and
+        //   2. ensure that `align_offset` (in `const_impl`) doesn't actually try to compute an offset.
         #[cfg_attr(not(bootstrap), allow(unused_unsafe))] // on bootstrap bump, remove unsafe block
         // SAFETY: The two versions are equivalent at runtime.
         unsafe {
diff --git a/src/ci/docker/host-x86_64/x86_64-gnu-llvm-17/Dockerfile b/src/ci/docker/host-x86_64/x86_64-gnu-llvm-17/Dockerfile
index fe30a953441..1eedfe3f09b 100644
--- a/src/ci/docker/host-x86_64/x86_64-gnu-llvm-17/Dockerfile
+++ b/src/ci/docker/host-x86_64/x86_64-gnu-llvm-17/Dockerfile
@@ -42,6 +42,10 @@ RUN sh /scripts/sccache.sh
 ENV NO_DOWNLOAD_CI_LLVM 1
 ENV EXTERNAL_LLVM 1
 
+# This is not the latest LLVM version, so some components required by tests may
+# be missing.
+ENV IS_NOT_LATEST_LLVM 1
+
 # Using llvm-link-shared due to libffi issues -- see #34486
 ENV RUST_CONFIGURE_ARGS \
       --build=x86_64-unknown-linux-gnu \
diff --git a/src/ci/docker/host-x86_64/x86_64-gnu-llvm-18/Dockerfile b/src/ci/docker/host-x86_64/x86_64-gnu-llvm-18/Dockerfile
new file mode 100644
index 00000000000..e8383500dfc
--- /dev/null
+++ b/src/ci/docker/host-x86_64/x86_64-gnu-llvm-18/Dockerfile
@@ -0,0 +1,55 @@
+FROM ubuntu:24.04
+
+ARG DEBIAN_FRONTEND=noninteractive
+
+RUN apt-get update && apt-get install -y --no-install-recommends \
+  g++ \
+  gcc-multilib \
+  make \
+  ninja-build \
+  file \
+  curl \
+  ca-certificates \
+  python3 \
+  git \
+  cmake \
+  sudo \
+  gdb \
+  llvm-18-tools \
+  llvm-18-dev \
+  libedit-dev \
+  libssl-dev \
+  pkg-config \
+  zlib1g-dev \
+  xz-utils \
+  nodejs \
+  mingw-w64 \
+  libgccjit-13-dev \
+  && rm -rf /var/lib/apt/lists/*
+
+# Note: libgccjit needs to match the default gcc version for the linker to find it.
+
+# Install powershell (universal package) so we can test x.ps1 on Linux
+# FIXME: need a "universal" version that supports libicu74, but for now it still works to ignore that dep.
+RUN curl -sL "https://github.com/PowerShell/PowerShell/releases/download/v7.3.1/powershell_7.3.1-1.deb_amd64.deb" > powershell.deb && \
+    dpkg --ignore-depends=libicu72 -i powershell.deb && \
+    rm -f powershell.deb
+
+COPY scripts/sccache.sh /scripts/
+RUN sh /scripts/sccache.sh
+
+# We are disabling CI LLVM since this builder is intentionally using a host
+# LLVM, rather than the typical src/llvm-project LLVM.
+ENV NO_DOWNLOAD_CI_LLVM 1
+ENV EXTERNAL_LLVM 1
+
+# Using llvm-link-shared due to libffi issues -- see #34486
+ENV RUST_CONFIGURE_ARGS \
+      --build=x86_64-unknown-linux-gnu \
+      --llvm-root=/usr/lib/llvm-18 \
+      --enable-llvm-link-shared \
+      --set rust.thin-lto-import-instr-limit=10
+
+COPY host-x86_64/x86_64-gnu-llvm-16/script.sh /tmp/
+
+ENV SCRIPT /tmp/script.sh
diff --git a/src/ci/github-actions/ci.yml b/src/ci/github-actions/ci.yml
index 2ba5d357a1d..c392ccec3dc 100644
--- a/src/ci/github-actions/ci.yml
+++ b/src/ci/github-actions/ci.yml
@@ -510,6 +510,11 @@ jobs:
           - name: x86_64-gnu-distcheck
             <<: *job-linux-8c
 
+          - name: x86_64-gnu-llvm-18
+            env:
+              RUST_BACKTRACE: 1
+            <<: *job-linux-8c
+
           - name: x86_64-gnu-llvm-17
             env:
               RUST_BACKTRACE: 1
diff --git a/src/tools/miri/src/borrow_tracker/mod.rs b/src/tools/miri/src/borrow_tracker/mod.rs
index 262f7c449d2..884b8a3b9bc 100644
--- a/src/tools/miri/src/borrow_tracker/mod.rs
+++ b/src/tools/miri/src/borrow_tracker/mod.rs
@@ -5,7 +5,7 @@ use std::num::NonZero;
 use smallvec::SmallVec;
 
 use rustc_data_structures::fx::{FxHashMap, FxHashSet};
-use rustc_middle::mir::RetagKind;
+use rustc_middle::{mir::RetagKind, ty::Ty};
 use rustc_target::abi::Size;
 
 use crate::*;
@@ -291,6 +291,19 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
         }
     }
 
+    fn retag_box_to_raw(
+        &mut self,
+        val: &ImmTy<'tcx, Provenance>,
+        alloc_ty: Ty<'tcx>,
+    ) -> InterpResult<'tcx, ImmTy<'tcx, Provenance>> {
+        let this = self.eval_context_mut();
+        let method = this.machine.borrow_tracker.as_ref().unwrap().borrow().borrow_tracker_method;
+        match method {
+            BorrowTrackerMethod::StackedBorrows => this.sb_retag_box_to_raw(val, alloc_ty),
+            BorrowTrackerMethod::TreeBorrows => this.tb_retag_box_to_raw(val, alloc_ty),
+        }
+    }
+
     fn retag_place_contents(
         &mut self,
         kind: RetagKind,
diff --git a/src/tools/miri/src/borrow_tracker/stacked_borrows/mod.rs b/src/tools/miri/src/borrow_tracker/stacked_borrows/mod.rs
index 86d22229714..6eed62d7edc 100644
--- a/src/tools/miri/src/borrow_tracker/stacked_borrows/mod.rs
+++ b/src/tools/miri/src/borrow_tracker/stacked_borrows/mod.rs
@@ -865,6 +865,24 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
         this.sb_retag_reference(val, new_perm, RetagInfo { cause, in_field: false })
     }
 
+    fn sb_retag_box_to_raw(
+        &mut self,
+        val: &ImmTy<'tcx, Provenance>,
+        alloc_ty: Ty<'tcx>,
+    ) -> InterpResult<'tcx, ImmTy<'tcx, Provenance>> {
+        let this = self.eval_context_mut();
+        let is_global_alloc = alloc_ty.ty_adt_def().is_some_and(|adt| {
+            let global_alloc = this.tcx.require_lang_item(rustc_hir::LangItem::GlobalAlloc, None);
+            adt.did() == global_alloc
+        });
+        if is_global_alloc {
+            // Retag this as-if it was a mutable reference.
+            this.sb_retag_ptr_value(RetagKind::Raw, val)
+        } else {
+            Ok(val.clone())
+        }
+    }
+
     fn sb_retag_place_contents(
         &mut self,
         kind: RetagKind,
@@ -916,10 +934,18 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
                 self.ecx
             }
 
-            fn visit_box(&mut self, place: &PlaceTy<'tcx, Provenance>) -> InterpResult<'tcx> {
-                // Boxes get a weak protectors, since they may be deallocated.
-                let new_perm = NewPermission::from_box_ty(place.layout.ty, self.kind, self.ecx);
-                self.retag_ptr_inplace(place, new_perm)
+            fn visit_box(
+                &mut self,
+                box_ty: Ty<'tcx>,
+                place: &PlaceTy<'tcx, Provenance>,
+            ) -> InterpResult<'tcx> {
+                // Only boxes for the global allocator get any special treatment.
+                if box_ty.is_box_global(*self.ecx.tcx) {
+                    // Boxes get a weak protectors, since they may be deallocated.
+                    let new_perm = NewPermission::from_box_ty(place.layout.ty, self.kind, self.ecx);
+                    self.retag_ptr_inplace(place, new_perm)?;
+                }
+                Ok(())
             }
 
             fn visit_value(&mut self, place: &PlaceTy<'tcx, Provenance>) -> InterpResult<'tcx> {
diff --git a/src/tools/miri/src/borrow_tracker/tree_borrows/mod.rs b/src/tools/miri/src/borrow_tracker/tree_borrows/mod.rs
index 4b944ea88f5..ae38ce6e753 100644
--- a/src/tools/miri/src/borrow_tracker/tree_borrows/mod.rs
+++ b/src/tools/miri/src/borrow_tracker/tree_borrows/mod.rs
@@ -392,6 +392,15 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
         }
     }
 
+    fn tb_retag_box_to_raw(
+        &mut self,
+        val: &ImmTy<'tcx, Provenance>,
+        _alloc_ty: Ty<'tcx>,
+    ) -> InterpResult<'tcx, ImmTy<'tcx, Provenance>> {
+        // Casts to raw pointers are NOPs in Tree Borrows.
+        Ok(val.clone())
+    }
+
     /// Retag all pointers that are stored in this place.
     fn tb_retag_place_contents(
         &mut self,
@@ -441,14 +450,22 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
             /// Regardless of how `Unique` is handled, Boxes are always reborrowed.
             /// When `Unique` is also reborrowed, then it behaves exactly like `Box`
             /// except for the fact that `Box` has a non-zero-sized reborrow.
-            fn visit_box(&mut self, place: &PlaceTy<'tcx, Provenance>) -> InterpResult<'tcx> {
-                let new_perm = NewPermission::from_unique_ty(
-                    place.layout.ty,
-                    self.kind,
-                    self.ecx,
-                    /* zero_size */ false,
-                );
-                self.retag_ptr_inplace(place, new_perm)
+            fn visit_box(
+                &mut self,
+                box_ty: Ty<'tcx>,
+                place: &PlaceTy<'tcx, Provenance>,
+            ) -> InterpResult<'tcx> {
+                // Only boxes for the global allocator get any special treatment.
+                if box_ty.is_box_global(*self.ecx.tcx) {
+                    let new_perm = NewPermission::from_unique_ty(
+                        place.layout.ty,
+                        self.kind,
+                        self.ecx,
+                        /* zero_size */ false,
+                    );
+                    self.retag_ptr_inplace(place, new_perm)?;
+                }
+                Ok(())
             }
 
             fn visit_value(&mut self, place: &PlaceTy<'tcx, Provenance>) -> InterpResult<'tcx> {
diff --git a/src/tools/miri/src/shims/intrinsics/mod.rs b/src/tools/miri/src/shims/intrinsics/mod.rs
index 46f0c771cb5..075ce44fbce 100644
--- a/src/tools/miri/src/shims/intrinsics/mod.rs
+++ b/src/tools/miri/src/shims/intrinsics/mod.rs
@@ -129,6 +129,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
                 this.write_bytes_ptr(ptr, iter::repeat(val_byte).take(byte_count.bytes_usize()))?;
             }
 
+            // Memory model / provenance manipulation
             "ptr_mask" => {
                 let [ptr, mask] = check_arg_count(args)?;
 
@@ -139,6 +140,18 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
 
                 this.write_pointer(Pointer::new(ptr.provenance, masked_addr), dest)?;
             }
+            "retag_box_to_raw" => {
+                let [ptr] = check_arg_count(args)?;
+                let alloc_ty = generic_args[1].expect_ty();
+
+                let val = this.read_immediate(ptr)?;
+                let new_val = if this.machine.borrow_tracker.is_some() {
+                    this.retag_box_to_raw(&val, alloc_ty)?
+                } else {
+                    val
+                };
+                this.write_immediate(*new_val, dest)?;
+            }
 
             // We want to return either `true` or `false` at random, or else something like
             // ```
diff --git a/src/tools/miri/tests/pass/box-custom-alloc-aliasing.rs b/src/tools/miri/tests/pass/box-custom-alloc-aliasing.rs
new file mode 100644
index 00000000000..541e5f244db
--- /dev/null
+++ b/src/tools/miri/tests/pass/box-custom-alloc-aliasing.rs
@@ -0,0 +1,123 @@
+//! Regression test for <https://github.com/rust-lang/miri/issues/3341>:
+//! If `Box` has a local allocator, then it can't be `noalias` as the allocator
+//! may want to access allocator state based on the data pointer.
+
+//@revisions: stack tree
+//@[tree]compile-flags: -Zmiri-tree-borrows
+#![feature(allocator_api)]
+#![feature(strict_provenance)]
+
+use std::{
+    alloc::{AllocError, Allocator, Layout},
+    cell::{Cell, UnsafeCell},
+    ptr::{self, addr_of, NonNull},
+    thread::{self, ThreadId},
+    mem,
+};
+
+const BIN_SIZE: usize = 8;
+
+// A bin represents a collection of blocks of a specific layout.
+#[repr(align(128))]
+struct MyBin {
+    top: Cell<usize>,
+    thread_id: ThreadId,
+    memory: UnsafeCell<[usize; BIN_SIZE]>,
+}
+
+impl MyBin {
+    fn pop(&self) -> Option<NonNull<u8>> {
+        let top = self.top.get();
+        if top == BIN_SIZE {
+            return None;
+        }
+        // Cast the *entire* thing to a raw pointer to not restrict its provenance.
+        let bin = self as *const MyBin;
+        let base_ptr = UnsafeCell::raw_get(unsafe{ addr_of!((*bin).memory )}).cast::<usize>();
+        let ptr = unsafe { NonNull::new_unchecked(base_ptr.add(top)) };
+        self.top.set(top + 1);
+        Some(ptr.cast())
+    }
+
+    // Pretends to not be a throwaway allocation method like this. A more realistic
+    // substitute is using intrusive linked lists, which requires access to the
+    // metadata of this bin as well.
+    unsafe fn push(&self, ptr: NonNull<u8>) {
+        // For now just check that this really is in this bin.
+        let start = self.memory.get().addr();
+        let end = start + BIN_SIZE * mem::size_of::<usize>();
+        let addr = ptr.addr().get();
+        assert!((start..end).contains(&addr));
+    }
+}
+
+// A collection of bins.
+struct MyAllocator {
+    thread_id: ThreadId,
+    // Pretends to be some complex collection of bins, such as an array of linked lists.
+    bins: Box<[MyBin; 1]>,
+}
+
+impl MyAllocator {
+    fn new() -> Self {
+        let thread_id = thread::current().id();
+        MyAllocator {
+            thread_id,
+            bins: Box::new(
+                [MyBin {
+                    top: Cell::new(0),
+                    thread_id,
+                    memory: UnsafeCell::default(),
+                }; 1],
+            ),
+        }
+    }
+
+    // Pretends to be expensive finding a suitable bin for the layout.
+    fn find_bin(&self, layout: Layout) -> Option<&MyBin> {
+        if layout == Layout::new::<usize>() {
+            Some(&self.bins[0])
+        } else {
+            None
+        }
+    }
+}
+
+unsafe impl Allocator for MyAllocator {
+    fn allocate(&self, layout: Layout) -> Result<NonNull<[u8]>, AllocError> {
+        // Expensive bin search.
+        let bin = self.find_bin(layout).ok_or(AllocError)?;
+        let ptr = bin.pop().ok_or(AllocError)?;
+        Ok(NonNull::slice_from_raw_parts(ptr, layout.size()))
+    }
+
+    unsafe fn deallocate(&self, ptr: NonNull<u8>, _layout: Layout) {
+        // Since manually finding the corresponding bin of `ptr` is very expensive,
+        // doing pointer arithmetics is preferred.
+        // But this means we access `top` via `ptr` rather than `self`!
+        // That is fundamentally the source of the aliasing trouble in this example.
+        let their_bin = ptr.as_ptr().map_addr(|addr| addr & !127).cast::<MyBin>();
+        let thread_id = ptr::read(ptr::addr_of!((*their_bin).thread_id));
+        if self.thread_id == thread_id {
+            unsafe { (*their_bin).push(ptr) };
+        } else {
+            todo!("Deallocating from another thread")
+        }
+    }
+}
+
+// Make sure to involve `Box` in allocating these,
+// as that's where `noalias` may come from.
+fn v<T, A: Allocator>(t: T, a: A) -> Vec<T, A> {
+    (Box::new_in([t], a) as Box<[T], A>).into_vec()
+}
+
+fn main() {
+    assert!(mem::size_of::<MyBin>() <= 128); // if it grows bigger, the trick to access the "header" no longer works
+    let my_alloc = MyAllocator::new();
+    let a = v(1usize, &my_alloc);
+    let b = v(2usize, &my_alloc);
+    assert_eq!(a[0] + 1, b[0]);
+    assert_eq!(addr_of!(a[0]).wrapping_add(1), addr_of!(b[0]));
+    drop((a, b));
+}
diff --git a/src/tools/tidy/src/main.rs b/src/tools/tidy/src/main.rs
index 4b98c91319d..2bce246c308 100644
--- a/src/tools/tidy/src/main.rs
+++ b/src/tools/tidy/src/main.rs
@@ -102,7 +102,7 @@ fn main() {
         check!(tests_placement, &root_path);
         check!(tests_revision_unpaired_stdout_stderr, &tests_path);
         check!(debug_artifacts, &tests_path);
-        check!(ui_tests, &tests_path, bless);
+        check!(ui_tests, &root_path, bless);
         check!(mir_opt_tests, &tests_path, bless);
         check!(rustdoc_gui_tests, &tests_path);
         check!(rustdoc_css_themes, &librustdoc_path);
diff --git a/src/tools/tidy/src/ui_tests.rs b/src/tools/tidy/src/ui_tests.rs
index 39b14adfea4..c946554b98f 100644
--- a/src/tools/tidy/src/ui_tests.rs
+++ b/src/tools/tidy/src/ui_tests.rs
@@ -99,7 +99,8 @@ fn check_entries(tests_path: &Path, bad: &mut bool) {
     }
 }
 
-pub fn check(path: &Path, bless: bool, bad: &mut bool) {
+pub fn check(root_path: &Path, bless: bool, bad: &mut bool) {
+    let path = &root_path.join("tests");
     check_entries(&path, bad);
 
     // the list of files in ui tests that are allowed to start with `issue-XXXX`
@@ -193,7 +194,7 @@ pub fn check(path: &Path, bless: bool, bad: &mut bool) {
 */
 [
 "#;
-        let tidy_src = std::env::current_dir().unwrap().join("src/tools/tidy/src");
+        let tidy_src = root_path.join("src/tools/tidy/src");
         // instead of overwriting the file, recreate it and use an "atomic rename"
         // so we don't bork things on panic or a contributor using Ctrl+C
         let blessed_issues_path = tidy_src.join("issues_blessed.txt");
diff --git a/tests/ui/lint/non_local_definitions.rs b/tests/ui/lint/non_local_definitions.rs
index bbcc8189871..eee582a6f11 100644
--- a/tests/ui/lint/non_local_definitions.rs
+++ b/tests/ui/lint/non_local_definitions.rs
@@ -1,7 +1,7 @@
 //@ check-pass
 //@ edition:2021
 //@ aux-build:non_local_macro.rs
-//@ rustc-env:CARGO=/usr/bin/cargo
+//@ rustc-env:CARGO_CRATE_NAME=non_local_def
 
 #![feature(inline_const)]
 #![warn(non_local_definitions)]
@@ -245,6 +245,26 @@ fn bad() {
     //~^ WARN non-local `impl` definition
 }
 
+trait Uto9 {}
+trait Uto10 {}
+const _: u32 = {
+    let _a = || {
+        impl Uto9 for Test {}
+        //~^ WARN non-local `impl` definition
+
+        1
+    };
+
+    type A = [u32; {
+        impl Uto10 for Test {}
+        //~^ WARN non-local `impl` definition
+
+        1
+    }];
+
+    1
+};
+
 struct UwU<T>(T);
 
 fn fun() {
diff --git a/tests/ui/lint/non_local_definitions.stderr b/tests/ui/lint/non_local_definitions.stderr
index b9583ae983f..ef74e262f9d 100644
--- a/tests/ui/lint/non_local_definitions.stderr
+++ b/tests/ui/lint/non_local_definitions.stderr
@@ -442,7 +442,29 @@ LL |     impl<T> Uto8 for T {}
    = note: this lint may become deny-by-default in the edition 2024 and higher, see the tracking issue <https://github.com/rust-lang/rust/issues/120363>
 
 warning: non-local `impl` definition, they should be avoided as they go against expectation
-  --> $DIR/non_local_definitions.rs:253:5
+  --> $DIR/non_local_definitions.rs:252:9
+   |
+LL |         impl Uto9 for Test {}
+   |         ^^^^^^^^^^^^^^^^^^^^^
+   |
+   = help: move this `impl` block outside the of the current closure `<unnameable>` and up 2 bodies
+   = note: an `impl` definition is non-local if it is nested inside an item and neither the type nor the trait are at the same nesting level as the `impl` block
+   = note: one exception to the rule are anon-const (`const _: () = { ... }`) at top-level module and anon-const at the same nesting as the trait or type
+   = note: this lint may become deny-by-default in the edition 2024 and higher, see the tracking issue <https://github.com/rust-lang/rust/issues/120363>
+
+warning: non-local `impl` definition, they should be avoided as they go against expectation
+  --> $DIR/non_local_definitions.rs:259:9
+   |
+LL |         impl Uto10 for Test {}
+   |         ^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = help: move this `impl` block outside the of the current constant expression `<unnameable>` and up 2 bodies
+   = note: an `impl` definition is non-local if it is nested inside an item and neither the type nor the trait are at the same nesting level as the `impl` block
+   = note: one exception to the rule are anon-const (`const _: () = { ... }`) at top-level module and anon-const at the same nesting as the trait or type
+   = note: this lint may become deny-by-default in the edition 2024 and higher, see the tracking issue <https://github.com/rust-lang/rust/issues/120363>
+
+warning: non-local `impl` definition, they should be avoided as they go against expectation
+  --> $DIR/non_local_definitions.rs:273:5
    |
 LL | /     impl Default for UwU<OwO> {
 LL | |
@@ -458,7 +480,7 @@ LL | |     }
    = note: this lint may become deny-by-default in the edition 2024 and higher, see the tracking issue <https://github.com/rust-lang/rust/issues/120363>
 
 warning: non-local `impl` definition, they should be avoided as they go against expectation
-  --> $DIR/non_local_definitions.rs:264:5
+  --> $DIR/non_local_definitions.rs:284:5
    |
 LL | /     impl From<Cat> for () {
 LL | |
@@ -474,7 +496,7 @@ LL | |     }
    = note: this lint may become deny-by-default in the edition 2024 and higher, see the tracking issue <https://github.com/rust-lang/rust/issues/120363>
 
 warning: non-local `impl` definition, they should be avoided as they go against expectation
-  --> $DIR/non_local_definitions.rs:273:5
+  --> $DIR/non_local_definitions.rs:293:5
    |
 LL | /     impl AsRef<Cat> for () {
 LL | |
@@ -488,7 +510,7 @@ LL | |     }
    = note: this lint may become deny-by-default in the edition 2024 and higher, see the tracking issue <https://github.com/rust-lang/rust/issues/120363>
 
 warning: non-local `impl` definition, they should be avoided as they go against expectation
-  --> $DIR/non_local_definitions.rs:284:5
+  --> $DIR/non_local_definitions.rs:304:5
    |
 LL | /     impl PartialEq<B> for G {
 LL | |
@@ -504,7 +526,7 @@ LL | |     }
    = note: this lint may become deny-by-default in the edition 2024 and higher, see the tracking issue <https://github.com/rust-lang/rust/issues/120363>
 
 warning: non-local `impl` definition, they should be avoided as they go against expectation
-  --> $DIR/non_local_definitions.rs:301:5
+  --> $DIR/non_local_definitions.rs:321:5
    |
 LL | /     impl PartialEq<Dog> for &Dog {
 LL | |
@@ -520,7 +542,7 @@ LL | |     }
    = note: this lint may become deny-by-default in the edition 2024 and higher, see the tracking issue <https://github.com/rust-lang/rust/issues/120363>
 
 warning: non-local `impl` definition, they should be avoided as they go against expectation
-  --> $DIR/non_local_definitions.rs:308:5
+  --> $DIR/non_local_definitions.rs:328:5
    |
 LL | /     impl PartialEq<()> for Dog {
 LL | |
@@ -536,7 +558,7 @@ LL | |     }
    = note: this lint may become deny-by-default in the edition 2024 and higher, see the tracking issue <https://github.com/rust-lang/rust/issues/120363>
 
 warning: non-local `impl` definition, they should be avoided as they go against expectation
-  --> $DIR/non_local_definitions.rs:315:5
+  --> $DIR/non_local_definitions.rs:335:5
    |
 LL | /     impl PartialEq<()> for &Dog {
 LL | |
@@ -552,7 +574,7 @@ LL | |     }
    = note: this lint may become deny-by-default in the edition 2024 and higher, see the tracking issue <https://github.com/rust-lang/rust/issues/120363>
 
 warning: non-local `impl` definition, they should be avoided as they go against expectation
-  --> $DIR/non_local_definitions.rs:322:5
+  --> $DIR/non_local_definitions.rs:342:5
    |
 LL | /     impl PartialEq<Dog> for () {
 LL | |
@@ -568,7 +590,7 @@ LL | |     }
    = note: this lint may become deny-by-default in the edition 2024 and higher, see the tracking issue <https://github.com/rust-lang/rust/issues/120363>
 
 warning: non-local `impl` definition, they should be avoided as they go against expectation
-  --> $DIR/non_local_definitions.rs:344:5
+  --> $DIR/non_local_definitions.rs:364:5
    |
 LL | /     impl From<Wrap<Wrap<Lion>>> for () {
 LL | |
@@ -584,7 +606,7 @@ LL | |     }
    = note: this lint may become deny-by-default in the edition 2024 and higher, see the tracking issue <https://github.com/rust-lang/rust/issues/120363>
 
 warning: non-local `impl` definition, they should be avoided as they go against expectation
-  --> $DIR/non_local_definitions.rs:351:5
+  --> $DIR/non_local_definitions.rs:371:5
    |
 LL | /     impl From<()> for Wrap<Lion> {
 LL | |
@@ -600,7 +622,7 @@ LL | |     }
    = note: this lint may become deny-by-default in the edition 2024 and higher, see the tracking issue <https://github.com/rust-lang/rust/issues/120363>
 
 warning: non-local `impl` definition, they should be avoided as they go against expectation
-  --> $DIR/non_local_definitions.rs:364:13
+  --> $DIR/non_local_definitions.rs:384:13
    |
 LL |             impl MacroTrait for OutsideStruct {}
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -615,7 +637,7 @@ LL | m!();
    = note: this warning originates in the macro `m` (in Nightly builds, run with -Z macro-backtrace for more info)
 
 warning: non-local `impl` definition, they should be avoided as they go against expectation
-  --> $DIR/non_local_definitions.rs:374:1
+  --> $DIR/non_local_definitions.rs:394:1
    |
 LL | non_local_macro::non_local_impl!(CargoUpdate);
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -628,7 +650,7 @@ LL | non_local_macro::non_local_impl!(CargoUpdate);
    = note: this warning originates in the macro `non_local_macro::non_local_impl` (in Nightly builds, run with -Z macro-backtrace for more info)
 
 warning: non-local `macro_rules!` definition, they should be avoided as they go against expectation
-  --> $DIR/non_local_definitions.rs:377:1
+  --> $DIR/non_local_definitions.rs:397:1
    |
 LL | non_local_macro::non_local_macro_rules!(my_macro);
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -640,5 +662,5 @@ LL | non_local_macro::non_local_macro_rules!(my_macro);
    = note: the macro `non_local_macro::non_local_macro_rules` may come from an old version of the `non_local_macro` crate, try updating your dependency with `cargo update -p non_local_macro`
    = note: this warning originates in the macro `non_local_macro::non_local_macro_rules` (in Nightly builds, run with -Z macro-backtrace for more info)
 
-warning: 50 warnings emitted
+warning: 52 warnings emitted
 
diff --git a/tests/ui/parser/help-set-edition-ice-122130.rs b/tests/ui/parser/help-set-edition-ice-122130.rs
new file mode 100644
index 00000000000..bc5af04ecbc
--- /dev/null
+++ b/tests/ui/parser/help-set-edition-ice-122130.rs
@@ -0,0 +1,5 @@
+enum will {
+    s#[c"owned_box"]
+    //~^ERROR expected one of `(`, `,`, `=`, `{`, or `}`, found `#`
+    //~|ERROR expected item, found `"owned_box"`
+}
diff --git a/tests/ui/parser/help-set-edition-ice-122130.stderr b/tests/ui/parser/help-set-edition-ice-122130.stderr
new file mode 100644
index 00000000000..fe4d212f2db
--- /dev/null
+++ b/tests/ui/parser/help-set-edition-ice-122130.stderr
@@ -0,0 +1,21 @@
+error: expected one of `(`, `,`, `=`, `{`, or `}`, found `#`
+  --> $DIR/help-set-edition-ice-122130.rs:2:6
+   |
+LL |     s#[c"owned_box"]
+   |      ^ expected one of `(`, `,`, `=`, `{`, or `}`
+   |
+   = note: you may be trying to write a c-string literal
+   = note: c-string literals require Rust 2021 or later
+   = help: pass `--edition 2021` to `rustc`
+   = note: for more on editions, read https://doc.rust-lang.org/edition-guide
+
+error: expected item, found `"owned_box"`
+  --> $DIR/help-set-edition-ice-122130.rs:2:9
+   |
+LL |     s#[c"owned_box"]
+   |         ^^^^^^^^^^^ expected item
+   |
+   = note: for a full list of items that can appear in modules, see <https://doc.rust-lang.org/reference/items.html>
+
+error: aborting due to 2 previous errors
+
diff --git a/tests/ui/trait-bounds/ice-unsized-struct-arg-issue-121612.rs b/tests/ui/trait-bounds/ice-unsized-struct-arg-issue-121612.rs
new file mode 100644
index 00000000000..5ca4f49c3ba
--- /dev/null
+++ b/tests/ui/trait-bounds/ice-unsized-struct-arg-issue-121612.rs
@@ -0,0 +1,13 @@
+// Regression test for issue #121612
+
+trait Trait {}
+impl Trait for bool {}
+struct MySlice<T: FnOnce(&T, Idx) -> Idx>(bool, T);
+//~^ ERROR cannot find type `Idx` in this scope
+//~| ERROR cannot find type `Idx` in this scope
+type MySliceBool = MySlice<[bool]>;
+const MYSLICE_GOOD: &MySliceBool = &MySlice(true, [false]);
+//~^ ERROR the size for values of type `[bool]` cannot be known at compilation time
+//~| ERROR the size for values of type `[bool]` cannot be known at compilation time
+
+fn main() {}
diff --git a/tests/ui/trait-bounds/ice-unsized-struct-arg-issue-121612.stderr b/tests/ui/trait-bounds/ice-unsized-struct-arg-issue-121612.stderr
new file mode 100644
index 00000000000..0be80e9479f
--- /dev/null
+++ b/tests/ui/trait-bounds/ice-unsized-struct-arg-issue-121612.stderr
@@ -0,0 +1,57 @@
+error[E0412]: cannot find type `Idx` in this scope
+  --> $DIR/ice-unsized-struct-arg-issue-121612.rs:5:30
+   |
+LL | struct MySlice<T: FnOnce(&T, Idx) -> Idx>(bool, T);
+   |                              ^^^ not found in this scope
+
+error[E0412]: cannot find type `Idx` in this scope
+  --> $DIR/ice-unsized-struct-arg-issue-121612.rs:5:38
+   |
+LL | struct MySlice<T: FnOnce(&T, Idx) -> Idx>(bool, T);
+   |                                      ^^^ not found in this scope
+
+error[E0277]: the size for values of type `[bool]` cannot be known at compilation time
+  --> $DIR/ice-unsized-struct-arg-issue-121612.rs:9:22
+   |
+LL | const MYSLICE_GOOD: &MySliceBool = &MySlice(true, [false]);
+   |                      ^^^^^^^^^^^ doesn't have a size known at compile-time
+   |
+   = help: the trait `Sized` is not implemented for `[bool]`
+note: required by an implicit `Sized` bound in `MySlice`
+  --> $DIR/ice-unsized-struct-arg-issue-121612.rs:5:16
+   |
+LL | struct MySlice<T: FnOnce(&T, Idx) -> Idx>(bool, T);
+   |                ^ required by the implicit `Sized` requirement on this type parameter in `MySlice`
+help: you could relax the implicit `Sized` bound on `T` if it were used through indirection like `&T` or `Box<T>`
+  --> $DIR/ice-unsized-struct-arg-issue-121612.rs:5:16
+   |
+LL | struct MySlice<T: FnOnce(&T, Idx) -> Idx>(bool, T);
+   |                ^                                - ...if indirection were used here: `Box<T>`
+   |                |
+   |                this could be changed to `T: ?Sized`...
+
+error[E0277]: the size for values of type `[bool]` cannot be known at compilation time
+  --> $DIR/ice-unsized-struct-arg-issue-121612.rs:9:22
+   |
+LL | const MYSLICE_GOOD: &MySliceBool = &MySlice(true, [false]);
+   |                      ^^^^^^^^^^^ doesn't have a size known at compile-time
+   |
+   = help: the trait `Sized` is not implemented for `[bool]`
+note: required by an implicit `Sized` bound in `MySlice`
+  --> $DIR/ice-unsized-struct-arg-issue-121612.rs:5:16
+   |
+LL | struct MySlice<T: FnOnce(&T, Idx) -> Idx>(bool, T);
+   |                ^ required by the implicit `Sized` requirement on this type parameter in `MySlice`
+help: you could relax the implicit `Sized` bound on `T` if it were used through indirection like `&T` or `Box<T>`
+  --> $DIR/ice-unsized-struct-arg-issue-121612.rs:5:16
+   |
+LL | struct MySlice<T: FnOnce(&T, Idx) -> Idx>(bool, T);
+   |                ^                                - ...if indirection were used here: `Box<T>`
+   |                |
+   |                this could be changed to `T: ?Sized`...
+   = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
+
+error: aborting due to 4 previous errors
+
+Some errors have detailed explanations: E0277, E0412.
+For more information about an error, try `rustc --explain E0277`.
diff --git a/tests/ui/trait-bounds/ice-unsized-struct-arg-issue2-121424.rs b/tests/ui/trait-bounds/ice-unsized-struct-arg-issue2-121424.rs
new file mode 100644
index 00000000000..1a9266e05de
--- /dev/null
+++ b/tests/ui/trait-bounds/ice-unsized-struct-arg-issue2-121424.rs
@@ -0,0 +1,9 @@
+// Regression test for issue #121424
+#[repr(C)]
+struct MySlice<T: Copy>(bool, T);
+type MySliceBool = MySlice<[bool]>;
+const MYSLICE_GOOD: &MySliceBool = &MySlice(true, [false]);
+//~^ ERROR the trait bound `[bool]: Copy` is not satisfied
+//~| ERROR the trait bound `[bool]: Copy` is not satisfied
+
+fn main() {}
diff --git a/tests/ui/trait-bounds/ice-unsized-struct-arg-issue2-121424.stderr b/tests/ui/trait-bounds/ice-unsized-struct-arg-issue2-121424.stderr
new file mode 100644
index 00000000000..3738bbfb8de
--- /dev/null
+++ b/tests/ui/trait-bounds/ice-unsized-struct-arg-issue2-121424.stderr
@@ -0,0 +1,30 @@
+error[E0277]: the trait bound `[bool]: Copy` is not satisfied
+  --> $DIR/ice-unsized-struct-arg-issue2-121424.rs:5:22
+   |
+LL | const MYSLICE_GOOD: &MySliceBool = &MySlice(true, [false]);
+   |                      ^^^^^^^^^^^ the trait `Copy` is not implemented for `[bool]`
+   |
+   = help: the trait `Copy` is implemented for `[T; N]`
+note: required by a bound in `MySlice`
+  --> $DIR/ice-unsized-struct-arg-issue2-121424.rs:3:19
+   |
+LL | struct MySlice<T: Copy>(bool, T);
+   |                   ^^^^ required by this bound in `MySlice`
+
+error[E0277]: the trait bound `[bool]: Copy` is not satisfied
+  --> $DIR/ice-unsized-struct-arg-issue2-121424.rs:5:22
+   |
+LL | const MYSLICE_GOOD: &MySliceBool = &MySlice(true, [false]);
+   |                      ^^^^^^^^^^^ the trait `Copy` is not implemented for `[bool]`
+   |
+   = help: the trait `Copy` is implemented for `[T; N]`
+note: required by a bound in `MySlice`
+  --> $DIR/ice-unsized-struct-arg-issue2-121424.rs:3:19
+   |
+LL | struct MySlice<T: Copy>(bool, T);
+   |                   ^^^^ required by this bound in `MySlice`
+   = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0277`.