about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--Cargo.lock1
-rw-r--r--compiler/rustc_const_eval/src/interpret/memory.rs8
-rw-r--r--compiler/rustc_lint/messages.ftl6
-rw-r--r--compiler/rustc_lint/src/dangling.rs150
-rw-r--r--compiler/rustc_lint/src/lints.rs16
-rw-r--r--compiler/rustc_resolve/Cargo.toml1
-rw-r--r--compiler/rustc_resolve/src/build_reduced_graph.rs42
-rw-r--r--compiler/rustc_resolve/src/diagnostics.rs4
-rw-r--r--compiler/rustc_resolve/src/late/diagnostics.rs17
-rw-r--r--compiler/rustc_resolve/src/lib.rs72
-rw-r--r--library/core/src/ptr/alignment.rs8
-rw-r--r--library/core/src/slice/mod.rs3
-rw-r--r--library/std/src/panicking.rs12
-rw-r--r--library/std/src/thread/mod.rs3
-rw-r--r--src/bootstrap/src/core/build_steps/test.rs8
-rw-r--r--src/doc/rustc/src/platform-support/lynxos178.md2
-rw-r--r--src/tools/compiletest/src/common.rs35
-rw-r--r--src/tools/compiletest/src/lib.rs7
-rw-r--r--src/tools/miri/tests/fail/function_calls/exported_symbol_bad_unwind2.both.stderr2
-rw-r--r--src/tools/miri/tests/fail/function_calls/exported_symbol_bad_unwind2.definition.stderr2
-rw-r--r--src/tools/miri/tests/fail/panic/abort_unwind.stderr2
-rw-r--r--src/tools/miri/tests/fail/panic/double_panic.stderr2
-rw-r--r--src/tools/miri/tests/fail/panic/panic_abort1.stderr2
-rw-r--r--src/tools/miri/tests/fail/panic/panic_abort2.stderr2
-rw-r--r--src/tools/miri/tests/fail/panic/panic_abort3.stderr2
-rw-r--r--src/tools/miri/tests/fail/panic/panic_abort4.stderr2
-rw-r--r--src/tools/miri/tests/fail/ptr_swap_nonoverlapping.stderr2
-rw-r--r--src/tools/miri/tests/fail/terminate-terminator.stderr2
-rw-r--r--src/tools/miri/tests/fail/unwind-action-terminate.stderr2
-rw-r--r--src/tools/miri/tests/fail/validity/dangling_ref3.rs3
-rw-r--r--src/tools/miri/tests/pass/fn_align.rs25
-rw-r--r--tests/codegen-llvm/simd/extract-insert-dyn.rs27
-rw-r--r--tests/debuginfo/basic-stepping.rs47
-rw-r--r--tests/mir-opt/pre-codegen/drop_boxed_slice.generic_in_place.PreCodegen.after.32bit.panic-abort.mir12
-rw-r--r--tests/mir-opt/pre-codegen/drop_boxed_slice.generic_in_place.PreCodegen.after.32bit.panic-unwind.mir12
-rw-r--r--tests/mir-opt/pre-codegen/drop_boxed_slice.generic_in_place.PreCodegen.after.64bit.panic-abort.mir12
-rw-r--r--tests/mir-opt/pre-codegen/drop_boxed_slice.generic_in_place.PreCodegen.after.64bit.panic-unwind.mir12
-rw-r--r--tests/mir-opt/pre-codegen/drop_boxed_slice.rs3
-rw-r--r--tests/ui/codegen/unsupported-static-initializer-in-const-array.rs18
-rw-r--r--tests/ui/lint/dangling-pointers-from-locals.rs188
-rw-r--r--tests/ui/lint/dangling-pointers-from-locals.stderr247
41 files changed, 850 insertions, 173 deletions
diff --git a/Cargo.lock b/Cargo.lock
index a966493f139..5a3906c470f 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -4519,6 +4519,7 @@ name = "rustc_resolve"
 version = "0.0.0"
 dependencies = [
  "bitflags",
+ "indexmap",
  "itertools",
  "pulldown-cmark",
  "rustc_arena",
diff --git a/compiler/rustc_const_eval/src/interpret/memory.rs b/compiler/rustc_const_eval/src/interpret/memory.rs
index 47bebf5371a..23b40894f16 100644
--- a/compiler/rustc_const_eval/src/interpret/memory.rs
+++ b/compiler/rustc_const_eval/src/interpret/memory.rs
@@ -937,8 +937,12 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
         // (both global from `alloc_map` and local from `extra_fn_ptr_map`)
         if let Some(fn_val) = self.get_fn_alloc(id) {
             let align = match fn_val {
-                FnVal::Instance(instance) => {
-                    self.tcx.codegen_instance_attrs(instance.def).alignment.unwrap_or(Align::ONE)
+                FnVal::Instance(_instance) => {
+                    // FIXME: Until we have a clear design for the effects of align(N) functions
+                    // on the address of function pointers, we don't consider the align(N)
+                    // attribute on functions in the interpreter.
+                    // See <https://github.com/rust-lang/rust/issues/144661> for more context.
+                    Align::ONE
                 }
                 // Machine-specific extra functions currently do not support alignment restrictions.
                 FnVal::Other(_) => Align::ONE,
diff --git a/compiler/rustc_lint/messages.ftl b/compiler/rustc_lint/messages.ftl
index 69fe7fe83ff..4d0c0c94a81 100644
--- a/compiler/rustc_lint/messages.ftl
+++ b/compiler/rustc_lint/messages.ftl
@@ -207,6 +207,12 @@ lint_confusable_identifier_pair = found both `{$existing_sym}` and `{$sym}` as i
 
 lint_custom_inner_attribute_unstable = custom inner attributes are unstable
 
+lint_dangling_pointers_from_locals = a dangling pointer will be produced because the local variable `{$local_var_name}` will be dropped
+    .ret_ty = return type of the {$fn_kind} is `{$ret_ty}`
+    .local_var = `{$local_var_name}` is part the {$fn_kind} and will be dropped at the end of the {$fn_kind}
+    .created_at = dangling pointer created here
+    .note = pointers do not have a lifetime; after returning, the `{$local_var_ty}` will be deallocated at the end of the {$fn_kind} because nothing is referencing it as far as the type system is concerned
+
 lint_dangling_pointers_from_temporaries = a dangling pointer will be produced because the temporary `{$ty}` will be dropped
     .label_ptr = this pointer will immediately be invalid
     .label_temporary = this `{$ty}` is deallocated at the end of the statement, bind it to a variable to extend its lifetime
diff --git a/compiler/rustc_lint/src/dangling.rs b/compiler/rustc_lint/src/dangling.rs
index 9e19949c3b6..af4457f4314 100644
--- a/compiler/rustc_lint/src/dangling.rs
+++ b/compiler/rustc_lint/src/dangling.rs
@@ -1,13 +1,14 @@
 use rustc_ast::visit::{visit_opt, walk_list};
 use rustc_hir::attrs::AttributeKind;
+use rustc_hir::def::Res;
 use rustc_hir::def_id::LocalDefId;
 use rustc_hir::intravisit::{FnKind, Visitor, walk_expr};
-use rustc_hir::{Block, Body, Expr, ExprKind, FnDecl, LangItem, find_attr};
-use rustc_middle::ty::{Ty, TyCtxt};
+use rustc_hir::{Block, Body, Expr, ExprKind, FnDecl, FnRetTy, LangItem, TyKind, find_attr};
+use rustc_middle::ty::{self, Ty, TyCtxt};
 use rustc_session::{declare_lint, impl_lint_pass};
 use rustc_span::{Span, sym};
 
-use crate::lints::DanglingPointersFromTemporaries;
+use crate::lints::{DanglingPointersFromLocals, DanglingPointersFromTemporaries};
 use crate::{LateContext, LateLintPass};
 
 declare_lint! {
@@ -42,6 +43,36 @@ declare_lint! {
     "detects getting a pointer from a temporary"
 }
 
+declare_lint! {
+    /// The `dangling_pointers_from_locals` lint detects getting a pointer to data
+    /// of a local that will be dropped at the end of the function.
+    ///
+    /// ### Example
+    ///
+    /// ```rust
+    /// fn f() -> *const u8 {
+    ///     let x = 0;
+    ///     &x // returns a dangling ptr to `x`
+    /// }
+    /// ```
+    ///
+    /// {{produces}}
+    ///
+    /// ### Explanation
+    ///
+    /// Returning a pointer from a local value will not prolong its lifetime,
+    /// which means that the value can be dropped and the allocation freed
+    /// while the pointer still exists, making the pointer dangling.
+    /// This is not an error (as far as the type system is concerned)
+    /// but probably is not what the user intended either.
+    ///
+    /// If you need stronger guarantees, consider using references instead,
+    /// as they are statically verified by the borrow-checker to never dangle.
+    pub DANGLING_POINTERS_FROM_LOCALS,
+    Warn,
+    "detects returning a pointer from a local variable"
+}
+
 /// FIXME: false negatives (i.e. the lint is not emitted when it should be)
 /// 1. Ways to get a temporary that are not recognized:
 ///    - `owning_temporary.field`
@@ -53,20 +84,123 @@ declare_lint! {
 #[derive(Clone, Copy, Default)]
 pub(crate) struct DanglingPointers;
 
-impl_lint_pass!(DanglingPointers => [DANGLING_POINTERS_FROM_TEMPORARIES]);
+impl_lint_pass!(DanglingPointers => [DANGLING_POINTERS_FROM_TEMPORARIES, DANGLING_POINTERS_FROM_LOCALS]);
 
 // This skips over const blocks, but they cannot use or return a dangling pointer anyways.
 impl<'tcx> LateLintPass<'tcx> for DanglingPointers {
     fn check_fn(
         &mut self,
         cx: &LateContext<'tcx>,
-        _: FnKind<'tcx>,
-        _: &'tcx FnDecl<'tcx>,
+        fn_kind: FnKind<'tcx>,
+        fn_decl: &'tcx FnDecl<'tcx>,
         body: &'tcx Body<'tcx>,
         _: Span,
-        _: LocalDefId,
+        def_id: LocalDefId,
     ) {
-        DanglingPointerSearcher { cx, inside_call_args: false }.visit_body(body)
+        DanglingPointerSearcher { cx, inside_call_args: false }.visit_body(body);
+
+        if let FnRetTy::Return(ret_ty) = &fn_decl.output
+            && let TyKind::Ptr(_) = ret_ty.kind
+        {
+            // get the return type of the function or closure
+            let ty = match cx.tcx.type_of(def_id).instantiate_identity().kind() {
+                ty::FnDef(..) => cx.tcx.fn_sig(def_id).instantiate_identity(),
+                ty::Closure(_, args) => args.as_closure().sig(),
+                _ => return,
+            };
+            let ty = ty.output();
+
+            // this type is only used for layout computation and pretty-printing, neither of them rely on regions
+            let ty = cx.tcx.instantiate_bound_regions_with_erased(ty);
+
+            // verify that we have a pointer type
+            let inner_ty = match ty.kind() {
+                ty::RawPtr(inner_ty, _) => *inner_ty,
+                _ => return,
+            };
+
+            if cx
+                .tcx
+                .layout_of(cx.typing_env().as_query_input(inner_ty))
+                .is_ok_and(|layout| !layout.is_1zst())
+            {
+                let dcx = &DanglingPointerLocalContext {
+                    body: def_id,
+                    fn_ret: ty,
+                    fn_ret_span: ret_ty.span,
+                    fn_ret_inner: inner_ty,
+                    fn_kind: match fn_kind {
+                        FnKind::ItemFn(..) => "function",
+                        FnKind::Method(..) => "method",
+                        FnKind::Closure => "closure",
+                    },
+                };
+
+                // look for `return`s
+                DanglingPointerReturnSearcher { cx, dcx }.visit_body(body);
+
+                // analyze implicit return expression
+                if let ExprKind::Block(block, None) = &body.value.kind
+                    && let innermost_block = block.innermost_block()
+                    && let Some(expr) = innermost_block.expr
+                {
+                    lint_addr_of_local(cx, dcx, expr);
+                }
+            }
+        }
+    }
+}
+
+struct DanglingPointerLocalContext<'tcx> {
+    body: LocalDefId,
+    fn_ret: Ty<'tcx>,
+    fn_ret_span: Span,
+    fn_ret_inner: Ty<'tcx>,
+    fn_kind: &'static str,
+}
+
+struct DanglingPointerReturnSearcher<'lcx, 'tcx> {
+    cx: &'lcx LateContext<'tcx>,
+    dcx: &'lcx DanglingPointerLocalContext<'tcx>,
+}
+
+impl<'tcx> Visitor<'tcx> for DanglingPointerReturnSearcher<'_, 'tcx> {
+    fn visit_expr(&mut self, expr: &'tcx Expr<'tcx>) -> Self::Result {
+        if let ExprKind::Ret(Some(expr)) = expr.kind {
+            lint_addr_of_local(self.cx, self.dcx, expr);
+        }
+        walk_expr(self, expr)
+    }
+}
+
+/// Look for `&<path_to_local_in_same_body>` pattern and emit lint for it
+fn lint_addr_of_local<'a>(
+    cx: &LateContext<'a>,
+    dcx: &DanglingPointerLocalContext<'a>,
+    expr: &'a Expr<'a>,
+) {
+    // peel casts as they do not interest us here, we want the inner expression.
+    let (inner, _) = super::utils::peel_casts(cx, expr);
+
+    if let ExprKind::AddrOf(_, _, inner_of) = inner.kind
+        && let ExprKind::Path(ref qpath) = inner_of.peel_blocks().kind
+        && let Res::Local(from) = cx.qpath_res(qpath, inner_of.hir_id)
+        && cx.tcx.hir_enclosing_body_owner(from) == dcx.body
+    {
+        cx.tcx.emit_node_span_lint(
+            DANGLING_POINTERS_FROM_LOCALS,
+            expr.hir_id,
+            expr.span,
+            DanglingPointersFromLocals {
+                ret_ty: dcx.fn_ret,
+                ret_ty_span: dcx.fn_ret_span,
+                fn_kind: dcx.fn_kind,
+                local_var: cx.tcx.hir_span(from),
+                local_var_name: cx.tcx.hir_ident(from),
+                local_var_ty: dcx.fn_ret_inner,
+                created_at: (expr.hir_id != inner.hir_id).then_some(inner.span),
+            },
+        );
     }
 }
 
diff --git a/compiler/rustc_lint/src/lints.rs b/compiler/rustc_lint/src/lints.rs
index fd8d0f832aa..ef63c0dee8c 100644
--- a/compiler/rustc_lint/src/lints.rs
+++ b/compiler/rustc_lint/src/lints.rs
@@ -1188,6 +1188,22 @@ pub(crate) struct DanglingPointersFromTemporaries<'tcx> {
     pub temporary_span: Span,
 }
 
+#[derive(LintDiagnostic)]
+#[diag(lint_dangling_pointers_from_locals)]
+#[note]
+pub(crate) struct DanglingPointersFromLocals<'tcx> {
+    pub ret_ty: Ty<'tcx>,
+    #[label(lint_ret_ty)]
+    pub ret_ty_span: Span,
+    pub fn_kind: &'static str,
+    #[label(lint_local_var)]
+    pub local_var: Span,
+    pub local_var_name: Ident,
+    pub local_var_ty: Ty<'tcx>,
+    #[label(lint_created_at)]
+    pub created_at: Option<Span>,
+}
+
 // multiple_supertrait_upcastable.rs
 #[derive(LintDiagnostic)]
 #[diag(lint_multiple_supertrait_upcastable)]
diff --git a/compiler/rustc_resolve/Cargo.toml b/compiler/rustc_resolve/Cargo.toml
index 9ea9c58cfd1..eb98a6e85c0 100644
--- a/compiler/rustc_resolve/Cargo.toml
+++ b/compiler/rustc_resolve/Cargo.toml
@@ -6,6 +6,7 @@ edition = "2024"
 [dependencies]
 # tidy-alphabetical-start
 bitflags = "2.4.1"
+indexmap = "2.4.0"
 itertools = "0.12"
 pulldown-cmark = { version = "0.11", features = ["html"], default-features = false }
 rustc_arena = { path = "../rustc_arena" }
diff --git a/compiler/rustc_resolve/src/build_reduced_graph.rs b/compiler/rustc_resolve/src/build_reduced_graph.rs
index 82eae088803..d9671c43b3d 100644
--- a/compiler/rustc_resolve/src/build_reduced_graph.rs
+++ b/compiler/rustc_resolve/src/build_reduced_graph.rs
@@ -968,7 +968,7 @@ impl<'a, 'ra, 'tcx> BuildReducedGraphVisitor<'a, 'ra, 'tcx> {
         }
         self.r.potentially_unused_imports.push(import);
         let imported_binding = self.r.import(binding, import);
-        if parent == self.r.graph_root {
+        if ident.name != kw::Underscore && parent == self.r.graph_root {
             let ident = ident.normalize_to_macros_2_0();
             if let Some(entry) = self.r.extern_prelude.get(&ident)
                 && expansion != LocalExpnId::ROOT
@@ -984,23 +984,29 @@ impl<'a, 'ra, 'tcx> BuildReducedGraphVisitor<'a, 'ra, 'tcx> {
                 // more details: https://github.com/rust-lang/rust/pull/111761
                 return;
             }
-            let entry = self.r.extern_prelude.entry(ident).or_insert(ExternPreludeEntry {
-                binding: Cell::new(None),
-                introduced_by_item: true,
-            });
-            if orig_name.is_some() {
-                entry.introduced_by_item = true;
-            }
-            // Binding from `extern crate` item in source code can replace
-            // a binding from `--extern` on command line here.
-            if !entry.is_import() {
-                entry.binding.set(Some(imported_binding));
-            } else if ident.name != kw::Underscore {
-                self.r.dcx().span_delayed_bug(
-                    item.span,
-                    format!("it had been define the external module '{ident}' multiple times"),
-                );
-            }
+
+            use indexmap::map::Entry;
+            match self.r.extern_prelude.entry(ident) {
+                Entry::Occupied(mut occupied) => {
+                    let entry = occupied.get_mut();
+                    if let Some(old_binding) = entry.binding.get()
+                        && old_binding.is_import()
+                    {
+                        let msg = format!("extern crate `{ident}` already in extern prelude");
+                        self.r.tcx.dcx().span_delayed_bug(item.span, msg);
+                    } else {
+                        // Binding from `extern crate` item in source code can replace
+                        // a binding from `--extern` on command line here.
+                        entry.binding.set(Some(imported_binding));
+                        entry.introduced_by_item = orig_name.is_some();
+                    }
+                    entry
+                }
+                Entry::Vacant(vacant) => vacant.insert(ExternPreludeEntry {
+                    binding: Cell::new(Some(imported_binding)),
+                    introduced_by_item: true,
+                }),
+            };
         }
         self.r.define_binding_local(parent, ident, TypeNS, imported_binding);
     }
diff --git a/compiler/rustc_resolve/src/diagnostics.rs b/compiler/rustc_resolve/src/diagnostics.rs
index 3b57f6e883a..d18554bba1b 100644
--- a/compiler/rustc_resolve/src/diagnostics.rs
+++ b/compiler/rustc_resolve/src/diagnostics.rs
@@ -1098,7 +1098,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
                     }
                 }
                 Scope::ExternPrelude => {
-                    suggestions.extend(this.extern_prelude.iter().filter_map(|(ident, _)| {
+                    suggestions.extend(this.extern_prelude.keys().filter_map(|ident| {
                         let res = Res::Def(DefKind::Mod, CRATE_DEF_ID.to_def_id());
                         filter_fn(res).then_some(TypoSuggestion::typo_from_ident(*ident, res))
                     }));
@@ -1409,7 +1409,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
         );
 
         if lookup_ident.span.at_least_rust_2018() {
-            for ident in self.extern_prelude.clone().into_keys() {
+            for &ident in self.extern_prelude.keys() {
                 if ident.span.from_expansion() {
                     // Idents are adjusted to the root context before being
                     // resolved in the extern prelude, so reporting this to the
diff --git a/compiler/rustc_resolve/src/late/diagnostics.rs b/compiler/rustc_resolve/src/late/diagnostics.rs
index 236b1404eeb..c8ca57a380f 100644
--- a/compiler/rustc_resolve/src/late/diagnostics.rs
+++ b/compiler/rustc_resolve/src/late/diagnostics.rs
@@ -2476,19 +2476,10 @@ impl<'ast, 'ra, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> {
                     } else {
                         // Items from the prelude
                         if !module.no_implicit_prelude {
-                            let extern_prelude = self.r.extern_prelude.clone();
-                            names.extend(extern_prelude.iter().flat_map(|(ident, _)| {
-                                self.r
-                                    .cstore_mut()
-                                    .maybe_process_path_extern(self.r.tcx, ident.name)
-                                    .and_then(|crate_id| {
-                                        let crate_mod =
-                                            Res::Def(DefKind::Mod, crate_id.as_def_id());
-
-                                        filter_fn(crate_mod).then(|| {
-                                            TypoSuggestion::typo_from_ident(*ident, crate_mod)
-                                        })
-                                    })
+                            names.extend(self.r.extern_prelude.keys().flat_map(|ident| {
+                                let res = Res::Def(DefKind::Mod, CRATE_DEF_ID.to_def_id());
+                                filter_fn(res)
+                                    .then_some(TypoSuggestion::typo_from_ident(*ident, res))
                             }));
 
                             if let Some(prelude) = self.r.prelude {
diff --git a/compiler/rustc_resolve/src/lib.rs b/compiler/rustc_resolve/src/lib.rs
index dbde6f7cfd7..6b034c5129f 100644
--- a/compiler/rustc_resolve/src/lib.rs
+++ b/compiler/rustc_resolve/src/lib.rs
@@ -1487,13 +1487,23 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
         let mut invocation_parents = FxHashMap::default();
         invocation_parents.insert(LocalExpnId::ROOT, InvocationParent::ROOT);
 
-        let mut extern_prelude: FxIndexMap<Ident, ExternPreludeEntry<'_>> = tcx
+        let mut extern_prelude: FxIndexMap<_, _> = tcx
             .sess
             .opts
             .externs
             .iter()
-            .filter(|(_, entry)| entry.add_prelude)
-            .map(|(name, _)| (Ident::from_str(name), Default::default()))
+            .filter_map(|(name, entry)| {
+                // Make sure `self`, `super`, `_` etc do not get into extern prelude.
+                // FIXME: reject `--extern self` and similar in option parsing instead.
+                if entry.add_prelude
+                    && let name = Symbol::intern(name)
+                    && name.can_be_raw()
+                {
+                    Some((Ident::with_dummy_span(name), Default::default()))
+                } else {
+                    None
+                }
+            })
             .collect();
 
         if !attr::contains_name(attrs, sym::no_core) {
@@ -2168,40 +2178,42 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
     }
 
     fn extern_prelude_get(&mut self, ident: Ident, finalize: bool) -> Option<NameBinding<'ra>> {
-        if ident.is_path_segment_keyword() {
-            // Make sure `self`, `super` etc produce an error when passed to here.
-            return None;
-        }
-
-        let norm_ident = ident.normalize_to_macros_2_0();
-        let binding = self.extern_prelude.get(&norm_ident).cloned().and_then(|entry| {
-            Some(if let Some(binding) = entry.binding.get() {
+        let mut record_use = None;
+        let entry = self.extern_prelude.get(&ident.normalize_to_macros_2_0());
+        let binding = entry.and_then(|entry| match entry.binding.get() {
+            Some(binding) if binding.is_import() => {
                 if finalize {
-                    if !entry.is_import() {
-                        self.cstore_mut().process_path_extern(self.tcx, ident.name, ident.span);
-                    } else if entry.introduced_by_item {
-                        self.record_use(ident, binding, Used::Other);
-                    }
+                    record_use = Some(binding);
                 }
-                binding
-            } else {
+                Some(binding)
+            }
+            Some(binding) => {
+                if finalize {
+                    self.cstore_mut().process_path_extern(self.tcx, ident.name, ident.span);
+                }
+                Some(binding)
+            }
+            None => {
                 let crate_id = if finalize {
-                    let Some(crate_id) =
-                        self.cstore_mut().process_path_extern(self.tcx, ident.name, ident.span)
-                    else {
-                        return Some(self.dummy_binding);
-                    };
-                    crate_id
+                    self.cstore_mut().process_path_extern(self.tcx, ident.name, ident.span)
                 } else {
-                    self.cstore_mut().maybe_process_path_extern(self.tcx, ident.name)?
+                    self.cstore_mut().maybe_process_path_extern(self.tcx, ident.name)
                 };
-                let res = Res::Def(DefKind::Mod, crate_id.as_def_id());
-                self.arenas.new_pub_res_binding(res, DUMMY_SP, LocalExpnId::ROOT)
-            })
+                match crate_id {
+                    Some(crate_id) => {
+                        let res = Res::Def(DefKind::Mod, crate_id.as_def_id());
+                        let binding =
+                            self.arenas.new_pub_res_binding(res, DUMMY_SP, LocalExpnId::ROOT);
+                        entry.binding.set(Some(binding));
+                        Some(binding)
+                    }
+                    None => finalize.then_some(self.dummy_binding),
+                }
+            }
         });
 
-        if let Some(entry) = self.extern_prelude.get(&norm_ident) {
-            entry.binding.set(binding);
+        if let Some(binding) = record_use {
+            self.record_use(ident, binding, Used::Scope);
         }
 
         binding
diff --git a/library/core/src/ptr/alignment.rs b/library/core/src/ptr/alignment.rs
index bd5b4e21baa..402634e49b3 100644
--- a/library/core/src/ptr/alignment.rs
+++ b/library/core/src/ptr/alignment.rs
@@ -1,3 +1,5 @@
+#![allow(clippy::enum_clike_unportable_variant)]
+
 use crate::num::NonZero;
 use crate::ub_checks::assert_unsafe_precondition;
 use crate::{cmp, fmt, hash, mem, num};
@@ -241,7 +243,7 @@ impl const Default for Alignment {
 
 #[cfg(target_pointer_width = "16")]
 #[derive(Copy, Clone, PartialEq, Eq)]
-#[repr(u16)]
+#[repr(usize)]
 enum AlignmentEnum {
     _Align1Shl0 = 1 << 0,
     _Align1Shl1 = 1 << 1,
@@ -263,7 +265,7 @@ enum AlignmentEnum {
 
 #[cfg(target_pointer_width = "32")]
 #[derive(Copy, Clone, PartialEq, Eq)]
-#[repr(u32)]
+#[repr(usize)]
 enum AlignmentEnum {
     _Align1Shl0 = 1 << 0,
     _Align1Shl1 = 1 << 1,
@@ -301,7 +303,7 @@ enum AlignmentEnum {
 
 #[cfg(target_pointer_width = "64")]
 #[derive(Copy, Clone, PartialEq, Eq)]
-#[repr(u64)]
+#[repr(usize)]
 enum AlignmentEnum {
     _Align1Shl0 = 1 << 0,
     _Align1Shl1 = 1 << 1,
diff --git a/library/core/src/slice/mod.rs b/library/core/src/slice/mod.rs
index 14042997bc2..1dddc48e68e 100644
--- a/library/core/src/slice/mod.rs
+++ b/library/core/src/slice/mod.rs
@@ -3974,8 +3974,9 @@ impl<T> [T] {
     ///
     /// [`split_at_mut`]: slice::split_at_mut
     #[stable(feature = "swap_with_slice", since = "1.27.0")]
+    #[rustc_const_unstable(feature = "const_swap_with_slice", issue = "142204")]
     #[track_caller]
-    pub fn swap_with_slice(&mut self, other: &mut [T]) {
+    pub const fn swap_with_slice(&mut self, other: &mut [T]) {
         assert!(self.len() == other.len(), "destination and source slices have different lengths");
         // SAFETY: `self` is valid for `self.len()` elements by definition, and `src` was
         // checked to have the same length. The slices cannot overlap because
diff --git a/library/std/src/panicking.rs b/library/std/src/panicking.rs
index 7873049d20b..c2b0e43a324 100644
--- a/library/std/src/panicking.rs
+++ b/library/std/src/panicking.rs
@@ -696,14 +696,14 @@ pub fn begin_panic_handler(info: &core::panic::PanicInfo<'_>) -> ! {
     let msg = info.message();
     crate::sys::backtrace::__rust_end_short_backtrace(move || {
         if let Some(s) = msg.as_str() {
-            rust_panic_with_hook(
+            panic_with_hook(
                 &mut StaticStrPayload(s),
                 loc,
                 info.can_unwind(),
                 info.force_no_backtrace(),
             );
         } else {
-            rust_panic_with_hook(
+            panic_with_hook(
                 &mut FormatStringPayload { inner: &msg, string: None },
                 loc,
                 info.can_unwind(),
@@ -767,7 +767,7 @@ pub const fn begin_panic<M: Any + Send>(msg: M) -> ! {
 
     let loc = Location::caller();
     crate::sys::backtrace::__rust_end_short_backtrace(move || {
-        rust_panic_with_hook(
+        panic_with_hook(
             &mut Payload { inner: Some(msg) },
             loc,
             /* can_unwind */ true,
@@ -792,7 +792,7 @@ fn payload_as_str(payload: &dyn Any) -> &str {
 /// panics, panic hooks, and finally dispatching to the panic runtime to either
 /// abort or unwind.
 #[optimize(size)]
-fn rust_panic_with_hook(
+fn panic_with_hook(
     payload: &mut dyn PanicPayload,
     location: &Location<'_>,
     can_unwind: bool,
@@ -885,8 +885,8 @@ pub fn rust_panic_without_hook(payload: Box<dyn Any + Send>) -> ! {
     rust_panic(&mut RewrapBox(payload))
 }
 
-/// An unmangled function (through `rustc_std_internal_symbol`) on which to slap
-/// yer breakpoints.
+/// A function with a fixed suffix (through `rustc_std_internal_symbol`)
+/// on which to slap yer breakpoints.
 #[inline(never)]
 #[cfg_attr(not(test), rustc_std_internal_symbol)]
 #[cfg(not(feature = "panic_immediate_abort"))]
diff --git a/library/std/src/thread/mod.rs b/library/std/src/thread/mod.rs
index dff981c900c..8d3ab82ace1 100644
--- a/library/std/src/thread/mod.rs
+++ b/library/std/src/thread/mod.rs
@@ -2018,6 +2018,9 @@ fn _assert_sync_and_send() {
 ///   which may take time on systems with large numbers of mountpoints.
 ///   (This does not apply to cgroup v2, or to processes not in a
 ///   cgroup.)
+/// - It does not attempt to take `ulimit` into account. If there is a limit set on the number of
+///   threads, `available_parallelism` cannot know how much of that limit a Rust program should
+///   take, or know in a reliable and race-free way how much of that limit is already taken.
 ///
 /// On all targets:
 /// - It may overcount the amount of parallelism available when running in a VM
diff --git a/src/bootstrap/src/core/build_steps/test.rs b/src/bootstrap/src/core/build_steps/test.rs
index ffc5dfad459..8bee00a9c13 100644
--- a/src/bootstrap/src/core/build_steps/test.rs
+++ b/src/bootstrap/src/core/build_steps/test.rs
@@ -1663,7 +1663,11 @@ NOTE: if you're sure you want to do this, please open an issue as to why. In the
         // bootstrap compiler.
         // NOTE: Only stage 1 is special cased because we need the rustc_private artifacts to match the
         // running compiler in stage 2 when plugins run.
+        let query_compiler;
         let (stage, stage_id) = if suite == "ui-fulldeps" && compiler.stage == 1 {
+            // Even when using the stage 0 compiler, we also need to provide the stage 1 compiler
+            // so that compiletest can query it for target information.
+            query_compiler = Some(compiler);
             // At stage 0 (stage - 1) we are using the stage0 compiler. Using `self.target` can lead
             // finding an incorrect compiler path on cross-targets, as the stage 0 is always equal to
             // `build.build` in the configuration.
@@ -1672,6 +1676,7 @@ NOTE: if you're sure you want to do this, please open an issue as to why. In the
             let test_stage = compiler.stage + 1;
             (test_stage, format!("stage{test_stage}-{build}"))
         } else {
+            query_compiler = None;
             let stage = compiler.stage;
             (stage, format!("stage{stage}-{target}"))
         };
@@ -1716,6 +1721,9 @@ NOTE: if you're sure you want to do this, please open an issue as to why. In the
         cmd.arg("--compile-lib-path").arg(builder.rustc_libdir(compiler));
         cmd.arg("--run-lib-path").arg(builder.sysroot_target_libdir(compiler, target));
         cmd.arg("--rustc-path").arg(builder.rustc(compiler));
+        if let Some(query_compiler) = query_compiler {
+            cmd.arg("--query-rustc-path").arg(builder.rustc(query_compiler));
+        }
 
         // Minicore auxiliary lib for `no_core` tests that need `core` stubs in cross-compilation
         // scenarios.
diff --git a/src/doc/rustc/src/platform-support/lynxos178.md b/src/doc/rustc/src/platform-support/lynxos178.md
index 6463f95a0b8..121e11fb653 100644
--- a/src/doc/rustc/src/platform-support/lynxos178.md
+++ b/src/doc/rustc/src/platform-support/lynxos178.md
@@ -15,7 +15,7 @@ Target triples available:
 
 ## Target maintainers
 
-- Renat Fatykhov, https://github.com/rfatykhov-lynx
+[@rfatykhov-lynx](https://github.com/rfatykhov-lynx)
 
 ## Requirements
 
diff --git a/src/tools/compiletest/src/common.rs b/src/tools/compiletest/src/common.rs
index aceae3e3a3b..2d49b1a7097 100644
--- a/src/tools/compiletest/src/common.rs
+++ b/src/tools/compiletest/src/common.rs
@@ -279,6 +279,15 @@ pub struct Config {
     /// [`Self::rustc_path`].
     pub stage0_rustc_path: Option<Utf8PathBuf>,
 
+    /// Path to the stage 1 or higher `rustc` used to obtain target information via
+    /// `--print=all-target-specs-json` and similar queries.
+    ///
+    /// Normally this is unset, because [`Self::rustc_path`] can be used instead.
+    /// But when running "stage 1" ui-fulldeps tests, `rustc_path` is a stage 0
+    /// compiler, whereas target specs must be obtained from a stage 1+ compiler
+    /// (in case the JSON format has changed since the last bootstrap bump).
+    pub query_rustc_path: Option<Utf8PathBuf>,
+
     /// Path to the `rustdoc`-under-test. Like [`Self::rustc_path`], this `rustdoc` is *staged*.
     pub rustdoc_path: Option<Utf8PathBuf>,
 
@@ -712,6 +721,7 @@ impl Config {
             rustc_path: Utf8PathBuf::default(),
             cargo_path: Default::default(),
             stage0_rustc_path: Default::default(),
+            query_rustc_path: Default::default(),
             rustdoc_path: Default::default(),
             coverage_dump_path: Default::default(),
             python: Default::default(),
@@ -917,7 +927,7 @@ pub struct TargetCfgs {
 
 impl TargetCfgs {
     fn new(config: &Config) -> TargetCfgs {
-        let mut targets: HashMap<String, TargetCfg> = serde_json::from_str(&rustc_output(
+        let mut targets: HashMap<String, TargetCfg> = serde_json::from_str(&query_rustc_output(
             config,
             &["--print=all-target-specs-json", "-Zunstable-options"],
             Default::default(),
@@ -950,7 +960,7 @@ impl TargetCfgs {
             if config.target.ends_with(".json") || !envs.is_empty() {
                 targets.insert(
                     config.target.clone(),
-                    serde_json::from_str(&rustc_output(
+                    serde_json::from_str(&query_rustc_output(
                         config,
                         &[
                             "--print=target-spec-json",
@@ -1009,10 +1019,13 @@ impl TargetCfgs {
         // which are respected for `--print=cfg` but not for `--print=all-target-specs-json`. The
         // code below extracts them from `--print=cfg`: make sure to only override fields that can
         // actually be changed with `-C` flags.
-        for config in
-            rustc_output(config, &["--print=cfg", "--target", &config.target], Default::default())
-                .trim()
-                .lines()
+        for config in query_rustc_output(
+            config,
+            &["--print=cfg", "--target", &config.target],
+            Default::default(),
+        )
+        .trim()
+        .lines()
         {
             let (name, value) = config
                 .split_once("=\"")
@@ -1113,7 +1126,7 @@ pub enum Endian {
 }
 
 fn builtin_cfg_names(config: &Config) -> HashSet<String> {
-    rustc_output(
+    query_rustc_output(
         config,
         &["--print=check-cfg", "-Zunstable-options", "--check-cfg=cfg()"],
         Default::default(),
@@ -1128,7 +1141,7 @@ pub const KNOWN_CRATE_TYPES: &[&str] =
     &["bin", "cdylib", "dylib", "lib", "proc-macro", "rlib", "staticlib"];
 
 fn supported_crate_types(config: &Config) -> HashSet<String> {
-    let crate_types: HashSet<_> = rustc_output(
+    let crate_types: HashSet<_> = query_rustc_output(
         config,
         &["--target", &config.target, "--print=supported-crate-types", "-Zunstable-options"],
         Default::default(),
@@ -1149,8 +1162,10 @@ fn supported_crate_types(config: &Config) -> HashSet<String> {
     crate_types
 }
 
-fn rustc_output(config: &Config, args: &[&str], envs: HashMap<String, String>) -> String {
-    let mut command = Command::new(&config.rustc_path);
+fn query_rustc_output(config: &Config, args: &[&str], envs: HashMap<String, String>) -> String {
+    let query_rustc_path = config.query_rustc_path.as_deref().unwrap_or(&config.rustc_path);
+
+    let mut command = Command::new(query_rustc_path);
     add_dylib_path(&mut command, iter::once(&config.compile_lib_path));
     command.args(&config.target_rustcflags).args(args);
     command.env("RUSTC_BOOTSTRAP", "1");
diff --git a/src/tools/compiletest/src/lib.rs b/src/tools/compiletest/src/lib.rs
index c712185733c..f5409e78341 100644
--- a/src/tools/compiletest/src/lib.rs
+++ b/src/tools/compiletest/src/lib.rs
@@ -63,6 +63,12 @@ pub fn parse_config(args: Vec<String>) -> Config {
             "path to rustc to use for compiling run-make recipes",
             "PATH",
         )
+        .optopt(
+            "",
+            "query-rustc-path",
+            "path to rustc to use for querying target information (defaults to `--rustc-path`)",
+            "PATH",
+        )
         .optopt("", "rustdoc-path", "path to rustdoc to use for compiling", "PATH")
         .optopt("", "coverage-dump-path", "path to coverage-dump to use in tests", "PATH")
         .reqopt("", "python", "path to python to use for doc tests", "PATH")
@@ -354,6 +360,7 @@ pub fn parse_config(args: Vec<String>) -> Config {
         rustc_path: opt_path(matches, "rustc-path"),
         cargo_path: matches.opt_str("cargo-path").map(Utf8PathBuf::from),
         stage0_rustc_path: matches.opt_str("stage0-rustc-path").map(Utf8PathBuf::from),
+        query_rustc_path: matches.opt_str("query-rustc-path").map(Utf8PathBuf::from),
         rustdoc_path: matches.opt_str("rustdoc-path").map(Utf8PathBuf::from),
         coverage_dump_path: matches.opt_str("coverage-dump-path").map(Utf8PathBuf::from),
         python: matches.opt_str("python").unwrap(),
diff --git a/src/tools/miri/tests/fail/function_calls/exported_symbol_bad_unwind2.both.stderr b/src/tools/miri/tests/fail/function_calls/exported_symbol_bad_unwind2.both.stderr
index deec81f7e51..14b3be02a79 100644
--- a/src/tools/miri/tests/fail/function_calls/exported_symbol_bad_unwind2.both.stderr
+++ b/src/tools/miri/tests/fail/function_calls/exported_symbol_bad_unwind2.both.stderr
@@ -16,7 +16,7 @@ LL | ABORT()
    |
    = note: BACKTRACE:
    = note: inside `std::sys::pal::PLATFORM::abort_internal` at RUSTLIB/std/src/sys/pal/PLATFORM/mod.rs:LL:CC
-   = note: inside `std::panicking::rust_panic_with_hook` at RUSTLIB/std/src/panicking.rs:LL:CC
+   = note: inside `std::panicking::panic_with_hook` at RUSTLIB/std/src/panicking.rs:LL:CC
    = note: inside closure at RUSTLIB/std/src/panicking.rs:LL:CC
    = note: inside `std::sys::backtrace::__rust_end_short_backtrace::<{closure@std::panicking::begin_panic_handler::{closure#0}}, !>` at RUSTLIB/std/src/sys/backtrace.rs:LL:CC
    = note: inside `std::panicking::begin_panic_handler` at RUSTLIB/std/src/panicking.rs:LL:CC
diff --git a/src/tools/miri/tests/fail/function_calls/exported_symbol_bad_unwind2.definition.stderr b/src/tools/miri/tests/fail/function_calls/exported_symbol_bad_unwind2.definition.stderr
index deec81f7e51..14b3be02a79 100644
--- a/src/tools/miri/tests/fail/function_calls/exported_symbol_bad_unwind2.definition.stderr
+++ b/src/tools/miri/tests/fail/function_calls/exported_symbol_bad_unwind2.definition.stderr
@@ -16,7 +16,7 @@ LL | ABORT()
    |
    = note: BACKTRACE:
    = note: inside `std::sys::pal::PLATFORM::abort_internal` at RUSTLIB/std/src/sys/pal/PLATFORM/mod.rs:LL:CC
-   = note: inside `std::panicking::rust_panic_with_hook` at RUSTLIB/std/src/panicking.rs:LL:CC
+   = note: inside `std::panicking::panic_with_hook` at RUSTLIB/std/src/panicking.rs:LL:CC
    = note: inside closure at RUSTLIB/std/src/panicking.rs:LL:CC
    = note: inside `std::sys::backtrace::__rust_end_short_backtrace::<{closure@std::panicking::begin_panic_handler::{closure#0}}, !>` at RUSTLIB/std/src/sys/backtrace.rs:LL:CC
    = note: inside `std::panicking::begin_panic_handler` at RUSTLIB/std/src/panicking.rs:LL:CC
diff --git a/src/tools/miri/tests/fail/panic/abort_unwind.stderr b/src/tools/miri/tests/fail/panic/abort_unwind.stderr
index 81d560c27ec..35052f37dfc 100644
--- a/src/tools/miri/tests/fail/panic/abort_unwind.stderr
+++ b/src/tools/miri/tests/fail/panic/abort_unwind.stderr
@@ -16,7 +16,7 @@ LL | ABORT()
    |
    = note: BACKTRACE:
    = note: inside `std::sys::pal::PLATFORM::abort_internal` at RUSTLIB/std/src/sys/pal/PLATFORM/mod.rs:LL:CC
-   = note: inside `std::panicking::rust_panic_with_hook` at RUSTLIB/std/src/panicking.rs:LL:CC
+   = note: inside `std::panicking::panic_with_hook` at RUSTLIB/std/src/panicking.rs:LL:CC
    = note: inside closure at RUSTLIB/std/src/panicking.rs:LL:CC
    = note: inside `std::sys::backtrace::__rust_end_short_backtrace::<{closure@std::panicking::begin_panic_handler::{closure#0}}, !>` at RUSTLIB/std/src/sys/backtrace.rs:LL:CC
    = note: inside `std::panicking::begin_panic_handler` at RUSTLIB/std/src/panicking.rs:LL:CC
diff --git a/src/tools/miri/tests/fail/panic/double_panic.stderr b/src/tools/miri/tests/fail/panic/double_panic.stderr
index bc6cce93d41..3f1fbfef721 100644
--- a/src/tools/miri/tests/fail/panic/double_panic.stderr
+++ b/src/tools/miri/tests/fail/panic/double_panic.stderr
@@ -19,7 +19,7 @@ LL | ABORT()
    |
    = note: BACKTRACE:
    = note: inside `std::sys::pal::PLATFORM::abort_internal` at RUSTLIB/std/src/sys/pal/PLATFORM/mod.rs:LL:CC
-   = note: inside `std::panicking::rust_panic_with_hook` at RUSTLIB/std/src/panicking.rs:LL:CC
+   = note: inside `std::panicking::panic_with_hook` at RUSTLIB/std/src/panicking.rs:LL:CC
    = note: inside closure at RUSTLIB/std/src/panicking.rs:LL:CC
    = note: inside `std::sys::backtrace::__rust_end_short_backtrace::<{closure@std::panicking::begin_panic_handler::{closure#0}}, !>` at RUSTLIB/std/src/sys/backtrace.rs:LL:CC
    = note: inside `std::panicking::begin_panic_handler` at RUSTLIB/std/src/panicking.rs:LL:CC
diff --git a/src/tools/miri/tests/fail/panic/panic_abort1.stderr b/src/tools/miri/tests/fail/panic/panic_abort1.stderr
index 61bc9a7a495..9aca2ed654f 100644
--- a/src/tools/miri/tests/fail/panic/panic_abort1.stderr
+++ b/src/tools/miri/tests/fail/panic/panic_abort1.stderr
@@ -15,7 +15,7 @@ LL | ABORT()
    = note: inside `std::rt::__rust_abort` at RUSTLIB/std/src/rt.rs:LL:CC
    = note: inside `panic_abort::__rust_start_panic` at RUSTLIB/panic_abort/src/lib.rs:LL:CC
    = note: inside `std::panicking::rust_panic` at RUSTLIB/std/src/panicking.rs:LL:CC
-   = note: inside `std::panicking::rust_panic_with_hook` at RUSTLIB/std/src/panicking.rs:LL:CC
+   = note: inside `std::panicking::panic_with_hook` at RUSTLIB/std/src/panicking.rs:LL:CC
    = note: inside closure at RUSTLIB/std/src/panicking.rs:LL:CC
    = note: inside `std::sys::backtrace::__rust_end_short_backtrace::<{closure@std::panicking::begin_panic_handler::{closure#0}}, !>` at RUSTLIB/std/src/sys/backtrace.rs:LL:CC
    = note: inside `std::panicking::begin_panic_handler` at RUSTLIB/std/src/panicking.rs:LL:CC
diff --git a/src/tools/miri/tests/fail/panic/panic_abort2.stderr b/src/tools/miri/tests/fail/panic/panic_abort2.stderr
index a7a42f8174e..425817d5f86 100644
--- a/src/tools/miri/tests/fail/panic/panic_abort2.stderr
+++ b/src/tools/miri/tests/fail/panic/panic_abort2.stderr
@@ -15,7 +15,7 @@ LL | ABORT()
    = note: inside `std::rt::__rust_abort` at RUSTLIB/std/src/rt.rs:LL:CC
    = note: inside `panic_abort::__rust_start_panic` at RUSTLIB/panic_abort/src/lib.rs:LL:CC
    = note: inside `std::panicking::rust_panic` at RUSTLIB/std/src/panicking.rs:LL:CC
-   = note: inside `std::panicking::rust_panic_with_hook` at RUSTLIB/std/src/panicking.rs:LL:CC
+   = note: inside `std::panicking::panic_with_hook` at RUSTLIB/std/src/panicking.rs:LL:CC
    = note: inside closure at RUSTLIB/std/src/panicking.rs:LL:CC
    = note: inside `std::sys::backtrace::__rust_end_short_backtrace::<{closure@std::panicking::begin_panic_handler::{closure#0}}, !>` at RUSTLIB/std/src/sys/backtrace.rs:LL:CC
    = note: inside `std::panicking::begin_panic_handler` at RUSTLIB/std/src/panicking.rs:LL:CC
diff --git a/src/tools/miri/tests/fail/panic/panic_abort3.stderr b/src/tools/miri/tests/fail/panic/panic_abort3.stderr
index ba1f11065ea..a21e185219e 100644
--- a/src/tools/miri/tests/fail/panic/panic_abort3.stderr
+++ b/src/tools/miri/tests/fail/panic/panic_abort3.stderr
@@ -15,7 +15,7 @@ LL | ABORT()
    = note: inside `std::rt::__rust_abort` at RUSTLIB/std/src/rt.rs:LL:CC
    = note: inside `panic_abort::__rust_start_panic` at RUSTLIB/panic_abort/src/lib.rs:LL:CC
    = note: inside `std::panicking::rust_panic` at RUSTLIB/std/src/panicking.rs:LL:CC
-   = note: inside `std::panicking::rust_panic_with_hook` at RUSTLIB/std/src/panicking.rs:LL:CC
+   = note: inside `std::panicking::panic_with_hook` at RUSTLIB/std/src/panicking.rs:LL:CC
    = note: inside closure at RUSTLIB/std/src/panicking.rs:LL:CC
    = note: inside `std::sys::backtrace::__rust_end_short_backtrace::<{closure@std::panicking::begin_panic_handler::{closure#0}}, !>` at RUSTLIB/std/src/sys/backtrace.rs:LL:CC
    = note: inside `std::panicking::begin_panic_handler` at RUSTLIB/std/src/panicking.rs:LL:CC
diff --git a/src/tools/miri/tests/fail/panic/panic_abort4.stderr b/src/tools/miri/tests/fail/panic/panic_abort4.stderr
index 1464c1fcc7c..a3cf5d72198 100644
--- a/src/tools/miri/tests/fail/panic/panic_abort4.stderr
+++ b/src/tools/miri/tests/fail/panic/panic_abort4.stderr
@@ -15,7 +15,7 @@ LL | ABORT()
    = note: inside `std::rt::__rust_abort` at RUSTLIB/std/src/rt.rs:LL:CC
    = note: inside `panic_abort::__rust_start_panic` at RUSTLIB/panic_abort/src/lib.rs:LL:CC
    = note: inside `std::panicking::rust_panic` at RUSTLIB/std/src/panicking.rs:LL:CC
-   = note: inside `std::panicking::rust_panic_with_hook` at RUSTLIB/std/src/panicking.rs:LL:CC
+   = note: inside `std::panicking::panic_with_hook` at RUSTLIB/std/src/panicking.rs:LL:CC
    = note: inside closure at RUSTLIB/std/src/panicking.rs:LL:CC
    = note: inside `std::sys::backtrace::__rust_end_short_backtrace::<{closure@std::panicking::begin_panic_handler::{closure#0}}, !>` at RUSTLIB/std/src/sys/backtrace.rs:LL:CC
    = note: inside `std::panicking::begin_panic_handler` at RUSTLIB/std/src/panicking.rs:LL:CC
diff --git a/src/tools/miri/tests/fail/ptr_swap_nonoverlapping.stderr b/src/tools/miri/tests/fail/ptr_swap_nonoverlapping.stderr
index b893220426c..8295a581060 100644
--- a/src/tools/miri/tests/fail/ptr_swap_nonoverlapping.stderr
+++ b/src/tools/miri/tests/fail/ptr_swap_nonoverlapping.stderr
@@ -14,7 +14,7 @@ LL | ABORT()
    |
    = note: BACKTRACE:
    = note: inside `std::sys::pal::PLATFORM::abort_internal` at RUSTLIB/std/src/sys/pal/PLATFORM/mod.rs:LL:CC
-   = note: inside `std::panicking::rust_panic_with_hook` at RUSTLIB/std/src/panicking.rs:LL:CC
+   = note: inside `std::panicking::panic_with_hook` at RUSTLIB/std/src/panicking.rs:LL:CC
    = note: inside closure at RUSTLIB/std/src/panicking.rs:LL:CC
    = note: inside `std::sys::backtrace::__rust_end_short_backtrace::<{closure@std::panicking::begin_panic_handler::{closure#0}}, !>` at RUSTLIB/std/src/sys/backtrace.rs:LL:CC
    = note: inside `std::panicking::begin_panic_handler` at RUSTLIB/std/src/panicking.rs:LL:CC
diff --git a/src/tools/miri/tests/fail/terminate-terminator.stderr b/src/tools/miri/tests/fail/terminate-terminator.stderr
index a0ee75e5dd2..f0f305d76bc 100644
--- a/src/tools/miri/tests/fail/terminate-terminator.stderr
+++ b/src/tools/miri/tests/fail/terminate-terminator.stderr
@@ -18,7 +18,7 @@ LL | ABORT()
    |
    = note: BACKTRACE:
    = note: inside `std::sys::pal::PLATFORM::abort_internal` at RUSTLIB/std/src/sys/pal/PLATFORM/mod.rs:LL:CC
-   = note: inside `std::panicking::rust_panic_with_hook` at RUSTLIB/std/src/panicking.rs:LL:CC
+   = note: inside `std::panicking::panic_with_hook` at RUSTLIB/std/src/panicking.rs:LL:CC
    = note: inside closure at RUSTLIB/std/src/panicking.rs:LL:CC
    = note: inside `std::sys::backtrace::__rust_end_short_backtrace::<{closure@std::panicking::begin_panic_handler::{closure#0}}, !>` at RUSTLIB/std/src/sys/backtrace.rs:LL:CC
    = note: inside `std::panicking::begin_panic_handler` at RUSTLIB/std/src/panicking.rs:LL:CC
diff --git a/src/tools/miri/tests/fail/unwind-action-terminate.stderr b/src/tools/miri/tests/fail/unwind-action-terminate.stderr
index 5fa485752a4..216ae84512a 100644
--- a/src/tools/miri/tests/fail/unwind-action-terminate.stderr
+++ b/src/tools/miri/tests/fail/unwind-action-terminate.stderr
@@ -16,7 +16,7 @@ LL | ABORT()
    |
    = note: BACKTRACE:
    = note: inside `std::sys::pal::PLATFORM::abort_internal` at RUSTLIB/std/src/sys/pal/PLATFORM/mod.rs:LL:CC
-   = note: inside `std::panicking::rust_panic_with_hook` at RUSTLIB/std/src/panicking.rs:LL:CC
+   = note: inside `std::panicking::panic_with_hook` at RUSTLIB/std/src/panicking.rs:LL:CC
    = note: inside closure at RUSTLIB/std/src/panicking.rs:LL:CC
    = note: inside `std::sys::backtrace::__rust_end_short_backtrace::<{closure@std::panicking::begin_panic_handler::{closure#0}}, !>` at RUSTLIB/std/src/sys/backtrace.rs:LL:CC
    = note: inside `std::panicking::begin_panic_handler` at RUSTLIB/std/src/panicking.rs:LL:CC
diff --git a/src/tools/miri/tests/fail/validity/dangling_ref3.rs b/src/tools/miri/tests/fail/validity/dangling_ref3.rs
index 8e8a75bd7ec..0fecd8f1c28 100644
--- a/src/tools/miri/tests/fail/validity/dangling_ref3.rs
+++ b/src/tools/miri/tests/fail/validity/dangling_ref3.rs
@@ -1,5 +1,8 @@
 // Make sure we catch this even without Stacked Borrows
 //@compile-flags: -Zmiri-disable-stacked-borrows
+
+#![allow(dangling_pointers_from_locals)]
+
 use std::mem;
 
 fn dangling() -> *const u8 {
diff --git a/src/tools/miri/tests/pass/fn_align.rs b/src/tools/miri/tests/pass/fn_align.rs
deleted file mode 100644
index 9752d033458..00000000000
--- a/src/tools/miri/tests/pass/fn_align.rs
+++ /dev/null
@@ -1,25 +0,0 @@
-//@compile-flags: -Zmin-function-alignment=8
-
-// FIXME(rust-lang/rust#82232, rust-lang/rust#143834): temporarily renamed to mitigate `#[align]`
-// nameres ambiguity
-#![feature(rustc_attrs)]
-#![feature(fn_align)]
-
-// When a function uses `align(N)`, the function address should be a multiple of `N`.
-
-#[rustc_align(256)]
-fn foo() {}
-
-#[rustc_align(16)]
-fn bar() {}
-
-#[rustc_align(4)]
-fn baz() {}
-
-fn main() {
-    assert!((foo as usize).is_multiple_of(256));
-    assert!((bar as usize).is_multiple_of(16));
-
-    // The maximum of `align(N)` and `-Zmin-function-alignment=N` is used.
-    assert!((baz as usize).is_multiple_of(8));
-}
diff --git a/tests/codegen-llvm/simd/extract-insert-dyn.rs b/tests/codegen-llvm/simd/extract-insert-dyn.rs
index 729f0145314..9c17b82e553 100644
--- a/tests/codegen-llvm/simd/extract-insert-dyn.rs
+++ b/tests/codegen-llvm/simd/extract-insert-dyn.rs
@@ -5,7 +5,8 @@
     repr_simd,
     arm_target_feature,
     mips_target_feature,
-    s390x_target_feature
+    s390x_target_feature,
+    riscv_target_feature
 )]
 #![no_std]
 #![crate_type = "lib"]
@@ -25,97 +26,105 @@ pub struct u32x16([u32; 16]);
 pub struct i8x16([i8; 16]);
 
 // CHECK-LABEL: dyn_simd_extract
-// CHECK: extractelement <16 x i8> %x, i32 %idx
+// CHECK: extractelement <16 x i8> %[[TEMP:.+]], i32 %idx
 #[no_mangle]
 #[cfg_attr(target_family = "wasm", target_feature(enable = "simd128"))]
 #[cfg_attr(target_arch = "arm", target_feature(enable = "neon"))]
 #[cfg_attr(target_arch = "x86", target_feature(enable = "sse"))]
 #[cfg_attr(target_arch = "mips", target_feature(enable = "msa"))]
 #[cfg_attr(target_arch = "s390x", target_feature(enable = "vector"))]
+#[cfg_attr(target_arch = "riscv64", target_feature(enable = "v"))]
 unsafe extern "C" fn dyn_simd_extract(x: i8x16, idx: u32) -> i8 {
     simd_extract_dyn(x, idx)
 }
 
 // CHECK-LABEL: literal_dyn_simd_extract
-// CHECK: extractelement <16 x i8> %x, i32 7
+// CHECK: extractelement <16 x i8> %[[TEMP:.+]], i32 7
 #[no_mangle]
 #[cfg_attr(target_family = "wasm", target_feature(enable = "simd128"))]
 #[cfg_attr(target_arch = "arm", target_feature(enable = "neon"))]
 #[cfg_attr(target_arch = "x86", target_feature(enable = "sse"))]
 #[cfg_attr(target_arch = "mips", target_feature(enable = "msa"))]
 #[cfg_attr(target_arch = "s390x", target_feature(enable = "vector"))]
+#[cfg_attr(target_arch = "riscv64", target_feature(enable = "v"))]
 unsafe extern "C" fn literal_dyn_simd_extract(x: i8x16) -> i8 {
     simd_extract_dyn(x, 7)
 }
 
 // CHECK-LABEL: const_dyn_simd_extract
-// CHECK: extractelement <16 x i8> %x, i32 7
+// CHECK: extractelement <16 x i8> %[[TEMP:.+]], i32 7
 #[no_mangle]
 #[cfg_attr(target_family = "wasm", target_feature(enable = "simd128"))]
 #[cfg_attr(target_arch = "arm", target_feature(enable = "neon"))]
 #[cfg_attr(target_arch = "x86", target_feature(enable = "sse"))]
 #[cfg_attr(target_arch = "mips", target_feature(enable = "msa"))]
 #[cfg_attr(target_arch = "s390x", target_feature(enable = "vector"))]
+#[cfg_attr(target_arch = "riscv64", target_feature(enable = "v"))]
 unsafe extern "C" fn const_dyn_simd_extract(x: i8x16) -> i8 {
     simd_extract_dyn(x, const { 3 + 4 })
 }
 
 // CHECK-LABEL: const_simd_extract
-// CHECK: extractelement <16 x i8> %x, i32 7
+// CHECK: extractelement <16 x i8> %[[TEMP:.+]], i32 7
 #[no_mangle]
 #[cfg_attr(target_family = "wasm", target_feature(enable = "simd128"))]
 #[cfg_attr(target_arch = "arm", target_feature(enable = "neon"))]
 #[cfg_attr(target_arch = "x86", target_feature(enable = "sse"))]
 #[cfg_attr(target_arch = "mips", target_feature(enable = "msa"))]
 #[cfg_attr(target_arch = "s390x", target_feature(enable = "vector"))]
+#[cfg_attr(target_arch = "riscv64", target_feature(enable = "v"))]
 unsafe extern "C" fn const_simd_extract(x: i8x16) -> i8 {
     simd_extract(x, const { 3 + 4 })
 }
 
 // CHECK-LABEL: dyn_simd_insert
-// CHECK: insertelement <16 x i8> %x, i8 %e, i32 %idx
+// CHECK: insertelement <16 x i8> %[[TEMP:.+]], i8 %e, i32 %idx
 #[no_mangle]
 #[cfg_attr(target_family = "wasm", target_feature(enable = "simd128"))]
 #[cfg_attr(target_arch = "arm", target_feature(enable = "neon"))]
 #[cfg_attr(target_arch = "x86", target_feature(enable = "sse"))]
 #[cfg_attr(target_arch = "mips", target_feature(enable = "msa"))]
 #[cfg_attr(target_arch = "s390x", target_feature(enable = "vector"))]
+#[cfg_attr(target_arch = "riscv64", target_feature(enable = "v"))]
 unsafe extern "C" fn dyn_simd_insert(x: i8x16, e: i8, idx: u32) -> i8x16 {
     simd_insert_dyn(x, idx, e)
 }
 
 // CHECK-LABEL: literal_dyn_simd_insert
-// CHECK: insertelement <16 x i8> %x, i8 %e, i32 7
+// CHECK: insertelement <16 x i8> %[[TEMP:.+]], i8 %e, i32 7
 #[no_mangle]
 #[cfg_attr(target_family = "wasm", target_feature(enable = "simd128"))]
 #[cfg_attr(target_arch = "arm", target_feature(enable = "neon"))]
 #[cfg_attr(target_arch = "x86", target_feature(enable = "sse"))]
 #[cfg_attr(target_arch = "mips", target_feature(enable = "msa"))]
 #[cfg_attr(target_arch = "s390x", target_feature(enable = "vector"))]
+#[cfg_attr(target_arch = "riscv64", target_feature(enable = "v"))]
 unsafe extern "C" fn literal_dyn_simd_insert(x: i8x16, e: i8) -> i8x16 {
     simd_insert_dyn(x, 7, e)
 }
 
 // CHECK-LABEL: const_dyn_simd_insert
-// CHECK: insertelement <16 x i8> %x, i8 %e, i32 7
+// CHECK: insertelement <16 x i8> %[[TEMP:.+]], i8 %e, i32 7
 #[no_mangle]
 #[cfg_attr(target_family = "wasm", target_feature(enable = "simd128"))]
 #[cfg_attr(target_arch = "arm", target_feature(enable = "neon"))]
 #[cfg_attr(target_arch = "x86", target_feature(enable = "sse"))]
 #[cfg_attr(target_arch = "mips", target_feature(enable = "msa"))]
 #[cfg_attr(target_arch = "s390x", target_feature(enable = "vector"))]
+#[cfg_attr(target_arch = "riscv64", target_feature(enable = "v"))]
 unsafe extern "C" fn const_dyn_simd_insert(x: i8x16, e: i8) -> i8x16 {
     simd_insert_dyn(x, const { 3 + 4 }, e)
 }
 
 // CHECK-LABEL: const_simd_insert
-// CHECK: insertelement <16 x i8> %x, i8 %e, i32 7
+// CHECK: insertelement <16 x i8> %[[TEMP:.+]], i8 %e, i32 7
 #[no_mangle]
 #[cfg_attr(target_family = "wasm", target_feature(enable = "simd128"))]
 #[cfg_attr(target_arch = "arm", target_feature(enable = "neon"))]
 #[cfg_attr(target_arch = "x86", target_feature(enable = "sse"))]
 #[cfg_attr(target_arch = "mips", target_feature(enable = "msa"))]
 #[cfg_attr(target_arch = "s390x", target_feature(enable = "vector"))]
+#[cfg_attr(target_arch = "riscv64", target_feature(enable = "v"))]
 unsafe extern "C" fn const_simd_insert(x: i8x16, e: i8) -> i8x16 {
     simd_insert(x, const { 3 + 4 }, e)
 }
diff --git a/tests/debuginfo/basic-stepping.rs b/tests/debuginfo/basic-stepping.rs
new file mode 100644
index 00000000000..6e1344d22a5
--- /dev/null
+++ b/tests/debuginfo/basic-stepping.rs
@@ -0,0 +1,47 @@
+//! Test that stepping through a simple program with a debugger one line at a
+//! time works intuitively, e.g. that `next` takes you to the next source line.
+//! Regression test for <https://github.com/rust-lang/rust/issues/33013>.
+
+//@ ignore-aarch64: Doesn't work yet.
+//@ compile-flags: -g
+
+// gdb-command: run
+// FIXME(#97083): Should we be able to break on initialization of zero-sized types?
+// FIXME(#97083): Right now the first breakable line is:
+// gdb-check:   let mut c = 27;
+// gdb-command: next
+// gdb-check:   let d = c = 99;
+// gdb-command: next
+// FIXME(#33013): gdb-check:   let e = "hi bob";
+// FIXME(#33013): gdb-command: next
+// FIXME(#33013): gdb-check:   let f = b"hi bob";
+// FIXME(#33013): gdb-command: next
+// FIXME(#33013): gdb-check:   let g = b'9';
+// FIXME(#33013): gdb-command: next
+// FIXME(#33013): gdb-check:   let h = ["whatever"; 8];
+// FIXME(#33013): gdb-command: next
+// gdb-check:   let i = [1,2,3,4];
+// gdb-command: next
+// gdb-check:   let j = (23, "hi");
+// gdb-command: next
+// gdb-check:   let k = 2..3;
+// gdb-command: next
+// gdb-check:   let l = &i[k];
+// gdb-command: next
+// gdb-check:   let m: *const() = &a;
+
+fn main () {
+    let a = (); // #break
+    let b : [i32; 0] = [];
+    let mut c = 27;
+    let d = c = 99;
+    let e = "hi bob";
+    let f = b"hi bob";
+    let g = b'9';
+    let h = ["whatever"; 8];
+    let i = [1,2,3,4];
+    let j = (23, "hi");
+    let k = 2..3;
+    let l = &i[k];
+    let m: *const() = &a;
+}
diff --git a/tests/mir-opt/pre-codegen/drop_boxed_slice.generic_in_place.PreCodegen.after.32bit.panic-abort.mir b/tests/mir-opt/pre-codegen/drop_boxed_slice.generic_in_place.PreCodegen.after.32bit.panic-abort.mir
index 2777bba893b..ba6ce0ee528 100644
--- a/tests/mir-opt/pre-codegen/drop_boxed_slice.generic_in_place.PreCodegen.after.32bit.panic-abort.mir
+++ b/tests/mir-opt/pre-codegen/drop_boxed_slice.generic_in_place.PreCodegen.after.32bit.panic-abort.mir
@@ -8,7 +8,7 @@ fn generic_in_place(_1: *mut Box<[T]>) -> () {
             let _2: std::ptr::NonNull<[T]>;
             let mut _3: *mut [T];
             let mut _4: *const [T];
-            let _12: ();
+            let _11: ();
             scope 3 {
                 let _8: std::ptr::alignment::AlignmentEnum;
                 scope 4 {
@@ -31,12 +31,11 @@ fn generic_in_place(_1: *mut Box<[T]>) -> () {
                         scope 20 (inlined NonNull::<u8>::as_ptr) {
                         }
                         scope 21 (inlined std::alloc::dealloc) {
-                            let mut _11: usize;
+                            let mut _10: usize;
                             scope 22 (inlined Layout::size) {
                             }
                             scope 23 (inlined Layout::align) {
                                 scope 24 (inlined std::ptr::Alignment::as_usize) {
-                                    let mut _10: u32;
                                 }
                             }
                         }
@@ -87,16 +86,13 @@ fn generic_in_place(_1: *mut Box<[T]>) -> () {
     bb2: {
         StorageLive(_9);
         _9 = copy _3 as *mut u8 (PtrToPtr);
-        StorageLive(_11);
         StorageLive(_10);
         _10 = discriminant(_8);
-        _11 = move _10 as usize (IntToInt);
-        StorageDead(_10);
-        _12 = alloc::alloc::__rust_dealloc(move _9, move _5, move _11) -> [return: bb3, unwind unreachable];
+        _11 = alloc::alloc::__rust_dealloc(move _9, move _5, move _10) -> [return: bb3, unwind unreachable];
     }
 
     bb3: {
-        StorageDead(_11);
+        StorageDead(_10);
         StorageDead(_9);
         goto -> bb4;
     }
diff --git a/tests/mir-opt/pre-codegen/drop_boxed_slice.generic_in_place.PreCodegen.after.32bit.panic-unwind.mir b/tests/mir-opt/pre-codegen/drop_boxed_slice.generic_in_place.PreCodegen.after.32bit.panic-unwind.mir
index 2777bba893b..ba6ce0ee528 100644
--- a/tests/mir-opt/pre-codegen/drop_boxed_slice.generic_in_place.PreCodegen.after.32bit.panic-unwind.mir
+++ b/tests/mir-opt/pre-codegen/drop_boxed_slice.generic_in_place.PreCodegen.after.32bit.panic-unwind.mir
@@ -8,7 +8,7 @@ fn generic_in_place(_1: *mut Box<[T]>) -> () {
             let _2: std::ptr::NonNull<[T]>;
             let mut _3: *mut [T];
             let mut _4: *const [T];
-            let _12: ();
+            let _11: ();
             scope 3 {
                 let _8: std::ptr::alignment::AlignmentEnum;
                 scope 4 {
@@ -31,12 +31,11 @@ fn generic_in_place(_1: *mut Box<[T]>) -> () {
                         scope 20 (inlined NonNull::<u8>::as_ptr) {
                         }
                         scope 21 (inlined std::alloc::dealloc) {
-                            let mut _11: usize;
+                            let mut _10: usize;
                             scope 22 (inlined Layout::size) {
                             }
                             scope 23 (inlined Layout::align) {
                                 scope 24 (inlined std::ptr::Alignment::as_usize) {
-                                    let mut _10: u32;
                                 }
                             }
                         }
@@ -87,16 +86,13 @@ fn generic_in_place(_1: *mut Box<[T]>) -> () {
     bb2: {
         StorageLive(_9);
         _9 = copy _3 as *mut u8 (PtrToPtr);
-        StorageLive(_11);
         StorageLive(_10);
         _10 = discriminant(_8);
-        _11 = move _10 as usize (IntToInt);
-        StorageDead(_10);
-        _12 = alloc::alloc::__rust_dealloc(move _9, move _5, move _11) -> [return: bb3, unwind unreachable];
+        _11 = alloc::alloc::__rust_dealloc(move _9, move _5, move _10) -> [return: bb3, unwind unreachable];
     }
 
     bb3: {
-        StorageDead(_11);
+        StorageDead(_10);
         StorageDead(_9);
         goto -> bb4;
     }
diff --git a/tests/mir-opt/pre-codegen/drop_boxed_slice.generic_in_place.PreCodegen.after.64bit.panic-abort.mir b/tests/mir-opt/pre-codegen/drop_boxed_slice.generic_in_place.PreCodegen.after.64bit.panic-abort.mir
index 2be0a478c85..ba6ce0ee528 100644
--- a/tests/mir-opt/pre-codegen/drop_boxed_slice.generic_in_place.PreCodegen.after.64bit.panic-abort.mir
+++ b/tests/mir-opt/pre-codegen/drop_boxed_slice.generic_in_place.PreCodegen.after.64bit.panic-abort.mir
@@ -8,7 +8,7 @@ fn generic_in_place(_1: *mut Box<[T]>) -> () {
             let _2: std::ptr::NonNull<[T]>;
             let mut _3: *mut [T];
             let mut _4: *const [T];
-            let _12: ();
+            let _11: ();
             scope 3 {
                 let _8: std::ptr::alignment::AlignmentEnum;
                 scope 4 {
@@ -31,12 +31,11 @@ fn generic_in_place(_1: *mut Box<[T]>) -> () {
                         scope 20 (inlined NonNull::<u8>::as_ptr) {
                         }
                         scope 21 (inlined std::alloc::dealloc) {
-                            let mut _11: usize;
+                            let mut _10: usize;
                             scope 22 (inlined Layout::size) {
                             }
                             scope 23 (inlined Layout::align) {
                                 scope 24 (inlined std::ptr::Alignment::as_usize) {
-                                    let mut _10: u64;
                                 }
                             }
                         }
@@ -87,16 +86,13 @@ fn generic_in_place(_1: *mut Box<[T]>) -> () {
     bb2: {
         StorageLive(_9);
         _9 = copy _3 as *mut u8 (PtrToPtr);
-        StorageLive(_11);
         StorageLive(_10);
         _10 = discriminant(_8);
-        _11 = move _10 as usize (IntToInt);
-        StorageDead(_10);
-        _12 = alloc::alloc::__rust_dealloc(move _9, move _5, move _11) -> [return: bb3, unwind unreachable];
+        _11 = alloc::alloc::__rust_dealloc(move _9, move _5, move _10) -> [return: bb3, unwind unreachable];
     }
 
     bb3: {
-        StorageDead(_11);
+        StorageDead(_10);
         StorageDead(_9);
         goto -> bb4;
     }
diff --git a/tests/mir-opt/pre-codegen/drop_boxed_slice.generic_in_place.PreCodegen.after.64bit.panic-unwind.mir b/tests/mir-opt/pre-codegen/drop_boxed_slice.generic_in_place.PreCodegen.after.64bit.panic-unwind.mir
index 2be0a478c85..ba6ce0ee528 100644
--- a/tests/mir-opt/pre-codegen/drop_boxed_slice.generic_in_place.PreCodegen.after.64bit.panic-unwind.mir
+++ b/tests/mir-opt/pre-codegen/drop_boxed_slice.generic_in_place.PreCodegen.after.64bit.panic-unwind.mir
@@ -8,7 +8,7 @@ fn generic_in_place(_1: *mut Box<[T]>) -> () {
             let _2: std::ptr::NonNull<[T]>;
             let mut _3: *mut [T];
             let mut _4: *const [T];
-            let _12: ();
+            let _11: ();
             scope 3 {
                 let _8: std::ptr::alignment::AlignmentEnum;
                 scope 4 {
@@ -31,12 +31,11 @@ fn generic_in_place(_1: *mut Box<[T]>) -> () {
                         scope 20 (inlined NonNull::<u8>::as_ptr) {
                         }
                         scope 21 (inlined std::alloc::dealloc) {
-                            let mut _11: usize;
+                            let mut _10: usize;
                             scope 22 (inlined Layout::size) {
                             }
                             scope 23 (inlined Layout::align) {
                                 scope 24 (inlined std::ptr::Alignment::as_usize) {
-                                    let mut _10: u64;
                                 }
                             }
                         }
@@ -87,16 +86,13 @@ fn generic_in_place(_1: *mut Box<[T]>) -> () {
     bb2: {
         StorageLive(_9);
         _9 = copy _3 as *mut u8 (PtrToPtr);
-        StorageLive(_11);
         StorageLive(_10);
         _10 = discriminant(_8);
-        _11 = move _10 as usize (IntToInt);
-        StorageDead(_10);
-        _12 = alloc::alloc::__rust_dealloc(move _9, move _5, move _11) -> [return: bb3, unwind unreachable];
+        _11 = alloc::alloc::__rust_dealloc(move _9, move _5, move _10) -> [return: bb3, unwind unreachable];
     }
 
     bb3: {
-        StorageDead(_11);
+        StorageDead(_10);
         StorageDead(_9);
         goto -> bb4;
     }
diff --git a/tests/mir-opt/pre-codegen/drop_boxed_slice.rs b/tests/mir-opt/pre-codegen/drop_boxed_slice.rs
index 11fb7afef0f..9ceba9444b8 100644
--- a/tests/mir-opt/pre-codegen/drop_boxed_slice.rs
+++ b/tests/mir-opt/pre-codegen/drop_boxed_slice.rs
@@ -13,7 +13,6 @@ pub unsafe fn generic_in_place<T: Copy>(ptr: *mut Box<[T]>) {
     // CHECK: [[B:_.+]] = copy [[ALIGN]] as std::ptr::Alignment (Transmute);
     // CHECK: [[C:_.+]] = move ([[B]].0: std::ptr::alignment::AlignmentEnum);
     // CHECK: [[D:_.+]] = discriminant([[C]]);
-    // CHECK: [[E:_.+]] = move [[D]] as usize (IntToInt);
-    // CHECK: = alloc::alloc::__rust_dealloc({{.+}}, move [[SIZE]], move [[E]]) ->
+    // CHECK: = alloc::alloc::__rust_dealloc({{.+}}, move [[SIZE]], move [[D]]) ->
     std::ptr::drop_in_place(ptr)
 }
diff --git a/tests/ui/codegen/unsupported-static-initializer-in-const-array.rs b/tests/ui/codegen/unsupported-static-initializer-in-const-array.rs
new file mode 100644
index 00000000000..bc94130ee19
--- /dev/null
+++ b/tests/ui/codegen/unsupported-static-initializer-in-const-array.rs
@@ -0,0 +1,18 @@
+//! LLVM error with unsupported expression in static
+//! initializer for const pointer in array on macOS.
+//!
+//! Regression test for <https://github.com/rust-lang/rust/issues/89225>.
+
+//@ build-pass
+//@ compile-flags: -C opt-level=3
+
+const fn make() -> (i32, i32, *const i32) {
+    const V: i32 = 123;
+    &V as *const i32;
+    (0, 0, &V)
+}
+
+fn main() {
+    let arr = [make(); 32];
+    println!("{}", arr[0].0);
+}
diff --git a/tests/ui/lint/dangling-pointers-from-locals.rs b/tests/ui/lint/dangling-pointers-from-locals.rs
new file mode 100644
index 00000000000..e321df2f427
--- /dev/null
+++ b/tests/ui/lint/dangling-pointers-from-locals.rs
@@ -0,0 +1,188 @@
+//@ check-pass
+
+struct Zst((), ());
+struct Adt(u8);
+
+const X: u8 = 5;
+
+fn simple() -> *const u8 {
+    let x = 0;
+    &x
+    //~^ WARN a dangling pointer will be produced
+}
+
+fn bindings() -> *const u8 {
+    let x = 0;
+    let x = &x;
+    x
+    //~^ WARN a dangling pointer will be produced
+}
+
+fn bindings_with_return() -> *const u8 {
+    let x = 42;
+    let y = &x;
+    return y;
+    //~^ WARN a dangling pointer will be produced
+}
+
+fn with_simple_cast() -> *const u8 {
+    let x = 0u8;
+    &x as *const u8
+    //~^ WARN a dangling pointer will be produced
+}
+
+fn bindings_and_casts() -> *const u8 {
+    let x = 0u8;
+    let x = &x as *const u8;
+    x as *const u8
+    //~^ WARN a dangling pointer will be produced
+}
+
+fn return_with_complex_cast() -> *mut u8 {
+    let mut x = 0u8;
+    return &mut x as *mut u8 as *const u8 as *mut u8;
+    //~^ WARN a dangling pointer will be produced
+}
+
+fn with_block() -> *const u8 {
+    let x = 0;
+    &{ x }
+    //~^ WARN a dangling pointer will be produced
+}
+
+fn with_many_blocks() -> *const u8 {
+    let x = 0;
+    {
+        {
+            &{
+                //~^ WARN a dangling pointer will be produced
+                { x }
+            }
+        }
+    }
+}
+
+fn simple_return() -> *const u8 {
+    let x = 0;
+    return &x;
+    //~^ WARN a dangling pointer will be produced
+}
+
+fn return_mut() -> *mut u8 {
+    let mut x = 0;
+    return &mut x;
+    //~^ WARN a dangling pointer will be produced
+}
+
+fn const_and_flow() -> *const u8 {
+    if false {
+        let x = 8;
+        return &x;
+        //~^ WARN a dangling pointer will be produced
+    }
+    &X // not dangling
+}
+
+fn vector<T: Default>() -> *const Vec<T> {
+    let x = vec![T::default()];
+    &x
+    //~^ WARN a dangling pointer will be produced
+}
+
+fn local_adt() -> *const Adt {
+    let x = Adt(5);
+    return &x;
+    //~^ WARN a dangling pointer will be produced
+}
+
+fn closure() -> *const u8 {
+    let _x = || -> *const u8 {
+        let x = 8;
+        return &x;
+        //~^ WARN a dangling pointer will be produced
+    };
+    &X // not dangling
+}
+
+fn fn_ptr() -> *const fn() -> u8 {
+    fn ret_u8() -> u8 {
+        0
+    }
+
+    let x = ret_u8 as fn() -> u8;
+    &x
+    //~^ WARN a dangling pointer will be produced
+}
+
+fn as_arg(a: Adt) -> *const Adt {
+    &a
+    //~^ WARN a dangling pointer will be produced
+}
+
+fn fn_ptr_as_arg(a: fn() -> u8) -> *const fn() -> u8 {
+    &a
+    //~^ WARN a dangling pointer will be produced
+}
+
+fn ptr_as_arg(a: *const Adt) -> *const *const Adt {
+    &a
+    //~^ WARN a dangling pointer will be produced
+}
+
+fn adt_as_arg(a: &Adt) -> *const &Adt {
+    &a
+    //~^ WARN a dangling pointer will be produced
+}
+
+fn unit() -> *const () {
+    let x = ();
+    &x // not dangling
+}
+
+fn zst() -> *const Zst {
+    let x = Zst((), ());
+    &x // not dangling
+}
+
+fn ref_implicit(a: &Adt) -> *const Adt {
+    a // not dangling
+}
+
+fn ref_explicit(a: &Adt) -> *const Adt {
+    &*a // not dangling
+}
+
+fn identity(a: *const Adt) -> *const Adt {
+    a // not dangling
+}
+
+fn from_ref(a: &Adt) -> *const Adt {
+    std::ptr::from_ref(a) // not dangling
+}
+
+fn inner_static() -> *const u8 {
+    static U: u8 = 5;
+    if false {
+        return &U as *const u8; // not dangling
+    }
+    &U // not dangling
+}
+
+fn return_in_closure() {
+    let x = 0;
+    let c = || -> *const u8 {
+        &x // not dangling by it-self
+    };
+}
+
+fn option<T: Default>() -> *const Option<T> {
+    let x = Some(T::default());
+    &x // can't compute layout of `Option<T>`, so cnat' be sure it won't be a ZST
+}
+
+fn generic<T: Default>() -> *const T {
+    let x = T::default();
+    &x // can't compute layout of `T`, so can't be sure it won't be a ZST
+}
+
+fn main() {}
diff --git a/tests/ui/lint/dangling-pointers-from-locals.stderr b/tests/ui/lint/dangling-pointers-from-locals.stderr
new file mode 100644
index 00000000000..e1d28bf22a0
--- /dev/null
+++ b/tests/ui/lint/dangling-pointers-from-locals.stderr
@@ -0,0 +1,247 @@
+warning: a dangling pointer will be produced because the local variable `x` will be dropped
+  --> $DIR/dangling-pointers-from-locals.rs:10:5
+   |
+LL | fn simple() -> *const u8 {
+   |                --------- return type of the function is `*const u8`
+LL |     let x = 0;
+   |         - `x` is part the function and will be dropped at the end of the function
+LL |     &x
+   |     ^^
+   |
+   = note: pointers do not have a lifetime; after returning, the `u8` will be deallocated at the end of the function because nothing is referencing it as far as the type system is concerned
+   = note: `#[warn(dangling_pointers_from_locals)]` on by default
+
+warning: a dangling pointer will be produced because the local variable `x` will be dropped
+  --> $DIR/dangling-pointers-from-locals.rs:17:5
+   |
+LL | fn bindings() -> *const u8 {
+   |                  --------- return type of the function is `*const u8`
+LL |     let x = 0;
+   |         - `x` is part the function and will be dropped at the end of the function
+LL |     let x = &x;
+   |             -- dangling pointer created here
+LL |     x
+   |     ^
+   |
+   = note: pointers do not have a lifetime; after returning, the `u8` will be deallocated at the end of the function because nothing is referencing it as far as the type system is concerned
+
+warning: a dangling pointer will be produced because the local variable `x` will be dropped
+  --> $DIR/dangling-pointers-from-locals.rs:24:12
+   |
+LL | fn bindings_with_return() -> *const u8 {
+   |                              --------- return type of the function is `*const u8`
+LL |     let x = 42;
+   |         - `x` is part the function and will be dropped at the end of the function
+LL |     let y = &x;
+   |             -- dangling pointer created here
+LL |     return y;
+   |            ^
+   |
+   = note: pointers do not have a lifetime; after returning, the `u8` will be deallocated at the end of the function because nothing is referencing it as far as the type system is concerned
+
+warning: a dangling pointer will be produced because the local variable `x` will be dropped
+  --> $DIR/dangling-pointers-from-locals.rs:30:5
+   |
+LL | fn with_simple_cast() -> *const u8 {
+   |                          --------- return type of the function is `*const u8`
+LL |     let x = 0u8;
+   |         - `x` is part the function and will be dropped at the end of the function
+LL |     &x as *const u8
+   |     --^^^^^^^^^^^^^
+   |     |
+   |     dangling pointer created here
+   |
+   = note: pointers do not have a lifetime; after returning, the `u8` will be deallocated at the end of the function because nothing is referencing it as far as the type system is concerned
+
+warning: a dangling pointer will be produced because the local variable `x` will be dropped
+  --> $DIR/dangling-pointers-from-locals.rs:37:5
+   |
+LL | fn bindings_and_casts() -> *const u8 {
+   |                            --------- return type of the function is `*const u8`
+LL |     let x = 0u8;
+   |         - `x` is part the function and will be dropped at the end of the function
+LL |     let x = &x as *const u8;
+   |             -- dangling pointer created here
+LL |     x as *const u8
+   |     ^^^^^^^^^^^^^^
+   |
+   = note: pointers do not have a lifetime; after returning, the `u8` will be deallocated at the end of the function because nothing is referencing it as far as the type system is concerned
+
+warning: a dangling pointer will be produced because the local variable `x` will be dropped
+  --> $DIR/dangling-pointers-from-locals.rs:43:12
+   |
+LL | fn return_with_complex_cast() -> *mut u8 {
+   |                                  ------- return type of the function is `*mut u8`
+LL |     let mut x = 0u8;
+   |         ----- `x` is part the function and will be dropped at the end of the function
+LL |     return &mut x as *mut u8 as *const u8 as *mut u8;
+   |            ------^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |            |
+   |            dangling pointer created here
+   |
+   = note: pointers do not have a lifetime; after returning, the `u8` will be deallocated at the end of the function because nothing is referencing it as far as the type system is concerned
+
+warning: a dangling pointer will be produced because the local variable `x` will be dropped
+  --> $DIR/dangling-pointers-from-locals.rs:49:5
+   |
+LL | fn with_block() -> *const u8 {
+   |                    --------- return type of the function is `*const u8`
+LL |     let x = 0;
+   |         - `x` is part the function and will be dropped at the end of the function
+LL |     &{ x }
+   |     ^^^^^^
+   |
+   = note: pointers do not have a lifetime; after returning, the `u8` will be deallocated at the end of the function because nothing is referencing it as far as the type system is concerned
+
+warning: a dangling pointer will be produced because the local variable `x` will be dropped
+  --> $DIR/dangling-pointers-from-locals.rs:57:13
+   |
+LL |   fn with_many_blocks() -> *const u8 {
+   |                            --------- return type of the function is `*const u8`
+LL |       let x = 0;
+   |           - `x` is part the function and will be dropped at the end of the function
+...
+LL | /             &{
+LL | |
+LL | |                 { x }
+LL | |             }
+   | |_____________^
+   |
+   = note: pointers do not have a lifetime; after returning, the `u8` will be deallocated at the end of the function because nothing is referencing it as far as the type system is concerned
+
+warning: a dangling pointer will be produced because the local variable `x` will be dropped
+  --> $DIR/dangling-pointers-from-locals.rs:67:12
+   |
+LL | fn simple_return() -> *const u8 {
+   |                       --------- return type of the function is `*const u8`
+LL |     let x = 0;
+   |         - `x` is part the function and will be dropped at the end of the function
+LL |     return &x;
+   |            ^^
+   |
+   = note: pointers do not have a lifetime; after returning, the `u8` will be deallocated at the end of the function because nothing is referencing it as far as the type system is concerned
+
+warning: a dangling pointer will be produced because the local variable `x` will be dropped
+  --> $DIR/dangling-pointers-from-locals.rs:73:12
+   |
+LL | fn return_mut() -> *mut u8 {
+   |                    ------- return type of the function is `*mut u8`
+LL |     let mut x = 0;
+   |         ----- `x` is part the function and will be dropped at the end of the function
+LL |     return &mut x;
+   |            ^^^^^^
+   |
+   = note: pointers do not have a lifetime; after returning, the `u8` will be deallocated at the end of the function because nothing is referencing it as far as the type system is concerned
+
+warning: a dangling pointer will be produced because the local variable `x` will be dropped
+  --> $DIR/dangling-pointers-from-locals.rs:80:16
+   |
+LL | fn const_and_flow() -> *const u8 {
+   |                        --------- return type of the function is `*const u8`
+LL |     if false {
+LL |         let x = 8;
+   |             - `x` is part the function and will be dropped at the end of the function
+LL |         return &x;
+   |                ^^
+   |
+   = note: pointers do not have a lifetime; after returning, the `u8` will be deallocated at the end of the function because nothing is referencing it as far as the type system is concerned
+
+warning: a dangling pointer will be produced because the local variable `x` will be dropped
+  --> $DIR/dangling-pointers-from-locals.rs:88:5
+   |
+LL | fn vector<T: Default>() -> *const Vec<T> {
+   |                            ------------- return type of the function is `*const Vec<T>`
+LL |     let x = vec![T::default()];
+   |         - `x` is part the function and will be dropped at the end of the function
+LL |     &x
+   |     ^^
+   |
+   = note: pointers do not have a lifetime; after returning, the `Vec<T>` will be deallocated at the end of the function because nothing is referencing it as far as the type system is concerned
+
+warning: a dangling pointer will be produced because the local variable `x` will be dropped
+  --> $DIR/dangling-pointers-from-locals.rs:94:12
+   |
+LL | fn local_adt() -> *const Adt {
+   |                   ---------- return type of the function is `*const Adt`
+LL |     let x = Adt(5);
+   |         - `x` is part the function and will be dropped at the end of the function
+LL |     return &x;
+   |            ^^
+   |
+   = note: pointers do not have a lifetime; after returning, the `Adt` will be deallocated at the end of the function because nothing is referencing it as far as the type system is concerned
+
+warning: a dangling pointer will be produced because the local variable `x` will be dropped
+  --> $DIR/dangling-pointers-from-locals.rs:101:16
+   |
+LL |     let _x = || -> *const u8 {
+   |                    --------- return type of the closure is `*const u8`
+LL |         let x = 8;
+   |             - `x` is part the closure and will be dropped at the end of the closure
+LL |         return &x;
+   |                ^^
+   |
+   = note: pointers do not have a lifetime; after returning, the `u8` will be deallocated at the end of the closure because nothing is referencing it as far as the type system is concerned
+
+warning: a dangling pointer will be produced because the local variable `x` will be dropped
+  --> $DIR/dangling-pointers-from-locals.rs:113:5
+   |
+LL | fn fn_ptr() -> *const fn() -> u8 {
+   |                ----------------- return type of the function is `*const fn() -> u8`
+...
+LL |     let x = ret_u8 as fn() -> u8;
+   |         - `x` is part the function and will be dropped at the end of the function
+LL |     &x
+   |     ^^
+   |
+   = note: pointers do not have a lifetime; after returning, the `fn() -> u8` will be deallocated at the end of the function because nothing is referencing it as far as the type system is concerned
+
+warning: a dangling pointer will be produced because the local variable `a` will be dropped
+  --> $DIR/dangling-pointers-from-locals.rs:118:5
+   |
+LL | fn as_arg(a: Adt) -> *const Adt {
+   |           -          ---------- return type of the function is `*const Adt`
+   |           |
+   |           `a` is part the function and will be dropped at the end of the function
+LL |     &a
+   |     ^^
+   |
+   = note: pointers do not have a lifetime; after returning, the `Adt` will be deallocated at the end of the function because nothing is referencing it as far as the type system is concerned
+
+warning: a dangling pointer will be produced because the local variable `a` will be dropped
+  --> $DIR/dangling-pointers-from-locals.rs:123:5
+   |
+LL | fn fn_ptr_as_arg(a: fn() -> u8) -> *const fn() -> u8 {
+   |                  -                 ----------------- return type of the function is `*const fn() -> u8`
+   |                  |
+   |                  `a` is part the function and will be dropped at the end of the function
+LL |     &a
+   |     ^^
+   |
+   = note: pointers do not have a lifetime; after returning, the `fn() -> u8` will be deallocated at the end of the function because nothing is referencing it as far as the type system is concerned
+
+warning: a dangling pointer will be produced because the local variable `a` will be dropped
+  --> $DIR/dangling-pointers-from-locals.rs:128:5
+   |
+LL | fn ptr_as_arg(a: *const Adt) -> *const *const Adt {
+   |               -                 ----------------- return type of the function is `*const *const Adt`
+   |               |
+   |               `a` is part the function and will be dropped at the end of the function
+LL |     &a
+   |     ^^
+   |
+   = note: pointers do not have a lifetime; after returning, the `*const Adt` will be deallocated at the end of the function because nothing is referencing it as far as the type system is concerned
+
+warning: a dangling pointer will be produced because the local variable `a` will be dropped
+  --> $DIR/dangling-pointers-from-locals.rs:133:5
+   |
+LL | fn adt_as_arg(a: &Adt) -> *const &Adt {
+   |               -           ----------- return type of the function is `*const &Adt`
+   |               |
+   |               `a` is part the function and will be dropped at the end of the function
+LL |     &a
+   |     ^^
+   |
+   = note: pointers do not have a lifetime; after returning, the `&Adt` will be deallocated at the end of the function because nothing is referencing it as far as the type system is concerned
+
+warning: 19 warnings emitted
+