about summary refs log tree commit diff
path: root/compiler/rustc_const_eval
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2024-02-13 08:33:04 +0000
committerbors <bors@rust-lang.org>2024-02-13 08:33:04 +0000
commit41555ab4a39e18f59387a576bf1c19ef39093a60 (patch)
tree5ed166021ffb0cc6a84667f2801a90486858a747 /compiler/rustc_const_eval
parentd2e446d39e2390093042a7fd8676cc85f2b573d7 (diff)
parent43e9411db839747f650e1125ed06266566c20b65 (diff)
downloadrust-41555ab4a39e18f59387a576bf1c19ef39093a60.tar.gz
rust-41555ab4a39e18f59387a576bf1c19ef39093a60.zip
Auto merge of #3298 - rust-lang:rustup-2024-02-13, r=oli-obk
Automatic Rustup
Diffstat (limited to 'compiler/rustc_const_eval')
-rw-r--r--compiler/rustc_const_eval/src/const_eval/error.rs2
-rw-r--r--compiler/rustc_const_eval/src/const_eval/eval_queries.rs13
-rw-r--r--compiler/rustc_const_eval/src/errors.rs134
-rw-r--r--compiler/rustc_const_eval/src/interpret/eval_context.rs17
-rw-r--r--compiler/rustc_const_eval/src/interpret/operand.rs12
-rw-r--r--compiler/rustc_const_eval/src/interpret/place.rs7
-rw-r--r--compiler/rustc_const_eval/src/interpret/step.rs4
-rw-r--r--compiler/rustc_const_eval/src/interpret/terminator.rs6
-rw-r--r--compiler/rustc_const_eval/src/interpret/util.rs15
-rw-r--r--compiler/rustc_const_eval/src/interpret/validity.rs32
-rw-r--r--compiler/rustc_const_eval/src/transform/check_consts/check.rs8
-rw-r--r--compiler/rustc_const_eval/src/transform/check_consts/mod.rs2
-rw-r--r--compiler/rustc_const_eval/src/transform/check_consts/ops.rs14
-rw-r--r--compiler/rustc_const_eval/src/transform/check_consts/resolver.rs8
14 files changed, 130 insertions, 144 deletions
diff --git a/compiler/rustc_const_eval/src/const_eval/error.rs b/compiler/rustc_const_eval/src/const_eval/error.rs
index 71085c2b2a5..80d02589900 100644
--- a/compiler/rustc_const_eval/src/const_eval/error.rs
+++ b/compiler/rustc_const_eval/src/const_eval/error.rs
@@ -151,7 +151,7 @@ where
             let mut err = tcx.dcx().create_err(err);
 
             let msg = error.diagnostic_message();
-            error.add_args(tcx.dcx(), &mut err);
+            error.add_args(&mut err);
 
             // Use *our* span to label the interp error
             err.span_label(our_span, msg);
diff --git a/compiler/rustc_const_eval/src/const_eval/eval_queries.rs b/compiler/rustc_const_eval/src/const_eval/eval_queries.rs
index 0844cdbe99b..c55d899e4d5 100644
--- a/compiler/rustc_const_eval/src/const_eval/eval_queries.rs
+++ b/compiler/rustc_const_eval/src/const_eval/eval_queries.rs
@@ -356,22 +356,13 @@ pub fn const_validate_mplace<'mir, 'tcx>(
     let mut inner = false;
     while let Some((mplace, path)) = ref_tracking.todo.pop() {
         let mode = match ecx.tcx.static_mutability(cid.instance.def_id()) {
-            Some(_) if cid.promoted.is_some() => {
-                // Promoteds in statics are consts that re allowed to point to statics.
-                CtfeValidationMode::Const {
-                    allow_immutable_unsafe_cell: false,
-                    allow_extern_static_ptrs: true,
-                }
-            }
+            _ if cid.promoted.is_some() => CtfeValidationMode::Promoted,
             Some(mutbl) => CtfeValidationMode::Static { mutbl }, // a `static`
             None => {
                 // In normal `const` (not promoted), the outermost allocation is always only copied,
                 // so having `UnsafeCell` in there is okay despite them being in immutable memory.
                 let allow_immutable_unsafe_cell = cid.promoted.is_none() && !inner;
-                CtfeValidationMode::Const {
-                    allow_immutable_unsafe_cell,
-                    allow_extern_static_ptrs: false,
-                }
+                CtfeValidationMode::Const { allow_immutable_unsafe_cell }
             }
         };
         ecx.const_validate_operand(&mplace.into(), path, &mut ref_tracking, mode)?;
diff --git a/compiler/rustc_const_eval/src/errors.rs b/compiler/rustc_const_eval/src/errors.rs
index a649526c196..11679ab77e3 100644
--- a/compiler/rustc_const_eval/src/errors.rs
+++ b/compiler/rustc_const_eval/src/errors.rs
@@ -426,7 +426,7 @@ pub struct UndefinedBehavior {
 pub trait ReportErrorExt {
     /// Returns the diagnostic message for this error.
     fn diagnostic_message(&self) -> DiagnosticMessage;
-    fn add_args<G: EmissionGuarantee>(self, dcx: &DiagCtxt, builder: &mut DiagnosticBuilder<'_, G>);
+    fn add_args<G: EmissionGuarantee>(self, diag: &mut DiagnosticBuilder<'_, G>);
 
     fn debug(self) -> String
     where
@@ -434,11 +434,11 @@ pub trait ReportErrorExt {
     {
         ty::tls::with(move |tcx| {
             let dcx = tcx.dcx();
-            let mut builder = dcx.struct_allow(DiagnosticMessage::Str(String::new().into()));
+            let mut diag = dcx.struct_allow(DiagnosticMessage::Str(String::new().into()));
             let message = self.diagnostic_message();
-            self.add_args(dcx, &mut builder);
-            let s = dcx.eagerly_translate_to_string(message, builder.args());
-            builder.cancel();
+            self.add_args(&mut diag);
+            let s = dcx.eagerly_translate_to_string(message, diag.args());
+            diag.cancel();
             s
         })
     }
@@ -505,20 +505,17 @@ impl<'a> ReportErrorExt for UndefinedBehaviorInfo<'a> {
         }
     }
 
-    fn add_args<G: EmissionGuarantee>(
-        self,
-        dcx: &DiagCtxt,
-        builder: &mut DiagnosticBuilder<'_, G>,
-    ) {
+    fn add_args<G: EmissionGuarantee>(self, diag: &mut DiagnosticBuilder<'_, G>) {
         use UndefinedBehaviorInfo::*;
+        let dcx = diag.dcx;
         match self {
             Ub(_) => {}
             Custom(custom) => {
                 (custom.add_args)(&mut |name, value| {
-                    builder.arg(name, value);
+                    diag.arg(name, value);
                 });
             }
-            ValidationError(e) => e.add_args(dcx, builder),
+            ValidationError(e) => e.add_args(diag),
 
             Unreachable
             | DivisionByZero
@@ -533,20 +530,18 @@ impl<'a> ReportErrorExt for UndefinedBehaviorInfo<'a> {
             | UninhabitedEnumVariantWritten(_)
             | UninhabitedEnumVariantRead(_) => {}
             BoundsCheckFailed { len, index } => {
-                builder.arg("len", len);
-                builder.arg("index", index);
+                diag.arg("len", len);
+                diag.arg("index", index);
             }
             UnterminatedCString(ptr) | InvalidFunctionPointer(ptr) | InvalidVTablePointer(ptr) => {
-                builder.arg("pointer", ptr);
+                diag.arg("pointer", ptr);
             }
             PointerUseAfterFree(alloc_id, msg) => {
-                builder
-                    .arg("alloc_id", alloc_id)
+                diag.arg("alloc_id", alloc_id)
                     .arg("bad_pointer_message", bad_pointer_message(msg, dcx));
             }
             PointerOutOfBounds { alloc_id, alloc_size, ptr_offset, ptr_size, msg } => {
-                builder
-                    .arg("alloc_id", alloc_id)
+                diag.arg("alloc_id", alloc_id)
                     .arg("alloc_size", alloc_size.bytes())
                     .arg("ptr_offset", ptr_offset)
                     .arg("ptr_size", ptr_size.bytes())
@@ -554,47 +549,47 @@ impl<'a> ReportErrorExt for UndefinedBehaviorInfo<'a> {
             }
             DanglingIntPointer(ptr, msg) => {
                 if ptr != 0 {
-                    builder.arg("pointer", format!("{ptr:#x}[noalloc]"));
+                    diag.arg("pointer", format!("{ptr:#x}[noalloc]"));
                 }
 
-                builder.arg("bad_pointer_message", bad_pointer_message(msg, dcx));
+                diag.arg("bad_pointer_message", bad_pointer_message(msg, dcx));
             }
             AlignmentCheckFailed(Misalignment { required, has }, msg) => {
-                builder.arg("required", required.bytes());
-                builder.arg("has", has.bytes());
-                builder.arg("msg", format!("{msg:?}"));
+                diag.arg("required", required.bytes());
+                diag.arg("has", has.bytes());
+                diag.arg("msg", format!("{msg:?}"));
             }
             WriteToReadOnly(alloc) | DerefFunctionPointer(alloc) | DerefVTablePointer(alloc) => {
-                builder.arg("allocation", alloc);
+                diag.arg("allocation", alloc);
             }
             InvalidBool(b) => {
-                builder.arg("value", format!("{b:02x}"));
+                diag.arg("value", format!("{b:02x}"));
             }
             InvalidChar(c) => {
-                builder.arg("value", format!("{c:08x}"));
+                diag.arg("value", format!("{c:08x}"));
             }
             InvalidTag(tag) => {
-                builder.arg("tag", format!("{tag:x}"));
+                diag.arg("tag", format!("{tag:x}"));
             }
             InvalidStr(err) => {
-                builder.arg("err", format!("{err}"));
+                diag.arg("err", format!("{err}"));
             }
             InvalidUninitBytes(Some((alloc, info))) => {
-                builder.arg("alloc", alloc);
-                builder.arg("access", info.access);
-                builder.arg("uninit", info.bad);
+                diag.arg("alloc", alloc);
+                diag.arg("access", info.access);
+                diag.arg("uninit", info.bad);
             }
             ScalarSizeMismatch(info) => {
-                builder.arg("target_size", info.target_size);
-                builder.arg("data_size", info.data_size);
+                diag.arg("target_size", info.target_size);
+                diag.arg("data_size", info.data_size);
             }
             InvalidNichedEnumVariantWritten { enum_ty } => {
-                builder.arg("ty", enum_ty.to_string());
+                diag.arg("ty", enum_ty.to_string());
             }
             AbiMismatchArgument { caller_ty, callee_ty }
             | AbiMismatchReturn { caller_ty, callee_ty } => {
-                builder.arg("caller_ty", caller_ty.to_string());
-                builder.arg("callee_ty", callee_ty.to_string());
+                diag.arg("caller_ty", caller_ty.to_string());
+                diag.arg("callee_ty", callee_ty.to_string());
             }
         }
     }
@@ -674,7 +669,7 @@ impl<'tcx> ReportErrorExt for ValidationErrorInfo<'tcx> {
         }
     }
 
-    fn add_args<G: EmissionGuarantee>(self, dcx: &DiagCtxt, err: &mut DiagnosticBuilder<'_, G>) {
+    fn add_args<G: EmissionGuarantee>(self, err: &mut DiagnosticBuilder<'_, G>) {
         use crate::fluent_generated as fluent;
         use rustc_middle::mir::interpret::ValidationErrorKind::*;
 
@@ -684,12 +679,12 @@ impl<'tcx> ReportErrorExt for ValidationErrorInfo<'tcx> {
         }
 
         let message = if let Some(path) = self.path {
-            dcx.eagerly_translate_to_string(
+            err.dcx.eagerly_translate_to_string(
                 fluent::const_eval_validation_front_matter_invalid_value_with_path,
                 [("path".into(), DiagnosticArgValue::Str(path.into()))].iter().map(|(a, b)| (a, b)),
             )
         } else {
-            dcx.eagerly_translate_to_string(
+            err.dcx.eagerly_translate_to_string(
                 fluent::const_eval_validation_front_matter_invalid_value,
                 [].into_iter(),
             )
@@ -700,7 +695,6 @@ impl<'tcx> ReportErrorExt for ValidationErrorInfo<'tcx> {
         fn add_range_arg<G: EmissionGuarantee>(
             r: WrappingRange,
             max_hi: u128,
-            dcx: &DiagCtxt,
             err: &mut DiagnosticBuilder<'_, G>,
         ) {
             let WrappingRange { start: lo, end: hi } = r;
@@ -724,7 +718,7 @@ impl<'tcx> ReportErrorExt for ValidationErrorInfo<'tcx> {
                 ("hi".into(), DiagnosticArgValue::Str(hi.to_string().into())),
             ];
             let args = args.iter().map(|(a, b)| (a, b));
-            let message = dcx.eagerly_translate_to_string(msg, args);
+            let message = err.dcx.eagerly_translate_to_string(msg, args);
             err.arg("in_range", message);
         }
 
@@ -746,7 +740,7 @@ impl<'tcx> ReportErrorExt for ValidationErrorInfo<'tcx> {
                     ExpectedKind::EnumTag => fluent::const_eval_validation_expected_enum_tag,
                     ExpectedKind::Str => fluent::const_eval_validation_expected_str,
                 };
-                let msg = dcx.eagerly_translate_to_string(msg, [].into_iter());
+                let msg = err.dcx.eagerly_translate_to_string(msg, [].into_iter());
                 err.arg("expected", msg);
             }
             InvalidEnumTag { value }
@@ -757,11 +751,11 @@ impl<'tcx> ReportErrorExt for ValidationErrorInfo<'tcx> {
                 err.arg("value", value);
             }
             NullablePtrOutOfRange { range, max_value } | PtrOutOfRange { range, max_value } => {
-                add_range_arg(range, max_value, dcx, err)
+                add_range_arg(range, max_value, err)
             }
             OutOfRange { range, max_value, value } => {
                 err.arg("value", value);
-                add_range_arg(range, max_value, dcx, err);
+                add_range_arg(range, max_value, err);
             }
             UnalignedPtr { required_bytes, found_bytes, .. } => {
                 err.arg("required_bytes", required_bytes);
@@ -802,13 +796,13 @@ impl ReportErrorExt for UnsupportedOpInfo {
             UnsupportedOpInfo::ExternStatic(_) => const_eval_extern_static,
         }
     }
-    fn add_args<G: EmissionGuarantee>(self, _: &DiagCtxt, builder: &mut DiagnosticBuilder<'_, G>) {
+    fn add_args<G: EmissionGuarantee>(self, diag: &mut DiagnosticBuilder<'_, G>) {
         use crate::fluent_generated::*;
 
         use UnsupportedOpInfo::*;
         if let ReadPointerAsInt(_) | OverwritePartialPointer(_) | ReadPartialPointer(_) = self {
-            builder.help(const_eval_ptr_as_bytes_1);
-            builder.help(const_eval_ptr_as_bytes_2);
+            diag.help(const_eval_ptr_as_bytes_1);
+            diag.help(const_eval_ptr_as_bytes_2);
         }
         match self {
             // `ReadPointerAsInt(Some(info))` is never printed anyway, it only serves as an error to
@@ -816,10 +810,10 @@ impl ReportErrorExt for UnsupportedOpInfo {
             // print. So it's not worth the effort of having diagnostics that can print the `info`.
             UnsizedLocal | Unsupported(_) | ReadPointerAsInt(_) => {}
             OverwritePartialPointer(ptr) | ReadPartialPointer(ptr) => {
-                builder.arg("ptr", ptr);
+                diag.arg("ptr", ptr);
             }
             ThreadLocalStatic(did) | ExternStatic(did) => {
-                builder.arg("did", format!("{did:?}"));
+                diag.arg("did", format!("{did:?}"));
             }
         }
     }
@@ -835,18 +829,14 @@ impl<'tcx> ReportErrorExt for InterpError<'tcx> {
             InterpError::MachineStop(e) => e.diagnostic_message(),
         }
     }
-    fn add_args<G: EmissionGuarantee>(
-        self,
-        dcx: &DiagCtxt,
-        builder: &mut DiagnosticBuilder<'_, G>,
-    ) {
+    fn add_args<G: EmissionGuarantee>(self, diag: &mut DiagnosticBuilder<'_, G>) {
         match self {
-            InterpError::UndefinedBehavior(ub) => ub.add_args(dcx, builder),
-            InterpError::Unsupported(e) => e.add_args(dcx, builder),
-            InterpError::InvalidProgram(e) => e.add_args(dcx, builder),
-            InterpError::ResourceExhaustion(e) => e.add_args(dcx, builder),
+            InterpError::UndefinedBehavior(ub) => ub.add_args(diag),
+            InterpError::Unsupported(e) => e.add_args(diag),
+            InterpError::InvalidProgram(e) => e.add_args(diag),
+            InterpError::ResourceExhaustion(e) => e.add_args(diag),
             InterpError::MachineStop(e) => e.add_args(&mut |name, value| {
-                builder.arg(name, value);
+                diag.arg(name, value);
             }),
         }
     }
@@ -864,28 +854,24 @@ impl<'tcx> ReportErrorExt for InvalidProgramInfo<'tcx> {
             }
         }
     }
-    fn add_args<G: EmissionGuarantee>(
-        self,
-        dcx: &DiagCtxt,
-        builder: &mut DiagnosticBuilder<'_, G>,
-    ) {
+    fn add_args<G: EmissionGuarantee>(self, diag: &mut DiagnosticBuilder<'_, G>) {
         match self {
             InvalidProgramInfo::TooGeneric | InvalidProgramInfo::AlreadyReported(_) => {}
             InvalidProgramInfo::Layout(e) => {
-                // The level doesn't matter, `diag` is consumed without it being used.
+                // The level doesn't matter, `dummy_diag` is consumed without it being used.
                 let dummy_level = Level::Bug;
-                let diag: DiagnosticBuilder<'_, ()> =
-                    e.into_diagnostic().into_diagnostic(dcx, dummy_level);
-                for (name, val) in diag.args() {
-                    builder.arg(name.clone(), val.clone());
+                let dummy_diag: DiagnosticBuilder<'_, ()> =
+                    e.into_diagnostic().into_diagnostic(diag.dcx, dummy_level);
+                for (name, val) in dummy_diag.args() {
+                    diag.arg(name.clone(), val.clone());
                 }
-                diag.cancel();
+                dummy_diag.cancel();
             }
             InvalidProgramInfo::FnAbiAdjustForForeignAbi(
                 AdjustForForeignAbiError::Unsupported { arch, abi },
             ) => {
-                builder.arg("arch", arch);
-                builder.arg("abi", abi.name());
+                diag.arg("arch", arch);
+                diag.arg("abi", abi.name());
             }
         }
     }
@@ -900,7 +886,7 @@ impl ReportErrorExt for ResourceExhaustionInfo {
             ResourceExhaustionInfo::AddressSpaceFull => const_eval_address_space_full,
         }
     }
-    fn add_args<G: EmissionGuarantee>(self, _: &DiagCtxt, _: &mut DiagnosticBuilder<'_, G>) {}
+    fn add_args<G: EmissionGuarantee>(self, _: &mut DiagnosticBuilder<'_, G>) {}
 }
 
 impl rustc_errors::IntoDiagnosticArg for InternKind {
diff --git a/compiler/rustc_const_eval/src/interpret/eval_context.rs b/compiler/rustc_const_eval/src/interpret/eval_context.rs
index dd9dfe3fe79..33e96e7faa8 100644
--- a/compiler/rustc_const_eval/src/interpret/eval_context.rs
+++ b/compiler/rustc_const_eval/src/interpret/eval_context.rs
@@ -445,7 +445,7 @@ pub fn format_interp_error<'tcx>(dcx: &DiagCtxt, e: InterpErrorInfo<'tcx>) -> St
     #[allow(rustc::untranslatable_diagnostic)]
     let mut diag = dcx.struct_allow("");
     let msg = e.diagnostic_message();
-    e.add_args(dcx, &mut diag);
+    e.add_args(&mut diag);
     let s = dcx.eagerly_translate_to_string(msg, diag.args());
     diag.cancel();
     s
@@ -554,18 +554,20 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
 
     /// Call this on things you got out of the MIR (so it is as generic as the current
     /// stack frame), to bring it into the proper environment for this interpreter.
-    pub(super) fn subst_from_current_frame_and_normalize_erasing_regions<
+    pub(super) fn instantiate_from_current_frame_and_normalize_erasing_regions<
         T: TypeFoldable<TyCtxt<'tcx>>,
     >(
         &self,
         value: T,
     ) -> Result<T, ErrorHandled> {
-        self.subst_from_frame_and_normalize_erasing_regions(self.frame(), value)
+        self.instantiate_from_frame_and_normalize_erasing_regions(self.frame(), value)
     }
 
     /// Call this on things you got out of the MIR (so it is as generic as the provided
     /// stack frame), to bring it into the proper environment for this interpreter.
-    pub(super) fn subst_from_frame_and_normalize_erasing_regions<T: TypeFoldable<TyCtxt<'tcx>>>(
+    pub(super) fn instantiate_from_frame_and_normalize_erasing_regions<
+        T: TypeFoldable<TyCtxt<'tcx>>,
+    >(
         &self,
         frame: &Frame<'mir, 'tcx, M::Provenance, M::FrameExtra>,
         value: T,
@@ -656,7 +658,8 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
 
         let layout = from_known_layout(self.tcx, self.param_env, layout, || {
             let local_ty = frame.body.local_decls[local].ty;
-            let local_ty = self.subst_from_frame_and_normalize_erasing_regions(frame, local_ty)?;
+            let local_ty =
+                self.instantiate_from_frame_and_normalize_erasing_regions(frame, local_ty)?;
             self.layout_of(local_ty)
         })?;
 
@@ -791,8 +794,8 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
         // Make sure all the constants required by this frame evaluate successfully (post-monomorphization check).
         if M::POST_MONO_CHECKS {
             for &const_ in &body.required_consts {
-                let c =
-                    self.subst_from_current_frame_and_normalize_erasing_regions(const_.const_)?;
+                let c = self
+                    .instantiate_from_current_frame_and_normalize_erasing_regions(const_.const_)?;
                 c.eval(*self.tcx, self.param_env, Some(const_.span)).map_err(|err| {
                     err.emit_note(*self.tcx);
                     err
diff --git a/compiler/rustc_const_eval/src/interpret/operand.rs b/compiler/rustc_const_eval/src/interpret/operand.rs
index 4653c9016c6..317e5673b51 100644
--- a/compiler/rustc_const_eval/src/interpret/operand.rs
+++ b/compiler/rustc_const_eval/src/interpret/operand.rs
@@ -696,9 +696,10 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
         trace!("eval_place_to_op: got {:?}", op);
         // Sanity-check the type we ended up with.
         if cfg!(debug_assertions) {
-            let normalized_place_ty = self.subst_from_current_frame_and_normalize_erasing_regions(
-                mir_place.ty(&self.frame().body.local_decls, *self.tcx).ty,
-            )?;
+            let normalized_place_ty = self
+                .instantiate_from_current_frame_and_normalize_erasing_regions(
+                    mir_place.ty(&self.frame().body.local_decls, *self.tcx).ty,
+                )?;
             if !mir_assign_valid_types(
                 *self.tcx,
                 self.param_env,
@@ -731,8 +732,9 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
             &Copy(place) | &Move(place) => self.eval_place_to_op(place, layout)?,
 
             Constant(constant) => {
-                let c =
-                    self.subst_from_current_frame_and_normalize_erasing_regions(constant.const_)?;
+                let c = self.instantiate_from_current_frame_and_normalize_erasing_regions(
+                    constant.const_,
+                )?;
 
                 // This can still fail:
                 // * During ConstProp, with `TooGeneric` or since the `required_consts` were not all
diff --git a/compiler/rustc_const_eval/src/interpret/place.rs b/compiler/rustc_const_eval/src/interpret/place.rs
index 772445f4f62..03d1dc9fd3d 100644
--- a/compiler/rustc_const_eval/src/interpret/place.rs
+++ b/compiler/rustc_const_eval/src/interpret/place.rs
@@ -542,9 +542,10 @@ where
         trace!("{:?}", self.dump_place(&place));
         // Sanity-check the type we ended up with.
         if cfg!(debug_assertions) {
-            let normalized_place_ty = self.subst_from_current_frame_and_normalize_erasing_regions(
-                mir_place.ty(&self.frame().body.local_decls, *self.tcx).ty,
-            )?;
+            let normalized_place_ty = self
+                .instantiate_from_current_frame_and_normalize_erasing_regions(
+                    mir_place.ty(&self.frame().body.local_decls, *self.tcx).ty,
+                )?;
             if !mir_assign_valid_types(
                 *self.tcx,
                 self.param_env,
diff --git a/compiler/rustc_const_eval/src/interpret/step.rs b/compiler/rustc_const_eval/src/interpret/step.rs
index f0f1008aba8..23f3d7eb67d 100644
--- a/compiler/rustc_const_eval/src/interpret/step.rs
+++ b/compiler/rustc_const_eval/src/interpret/step.rs
@@ -235,7 +235,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
             }
 
             NullaryOp(ref null_op, ty) => {
-                let ty = self.subst_from_current_frame_and_normalize_erasing_regions(ty)?;
+                let ty = self.instantiate_from_current_frame_and_normalize_erasing_regions(ty)?;
                 let layout = self.layout_of(ty)?;
                 if let mir::NullOp::SizeOf | mir::NullOp::AlignOf = null_op
                     && layout.is_unsized()
@@ -276,7 +276,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
             Cast(cast_kind, ref operand, cast_ty) => {
                 let src = self.eval_operand(operand, None)?;
                 let cast_ty =
-                    self.subst_from_current_frame_and_normalize_erasing_regions(cast_ty)?;
+                    self.instantiate_from_current_frame_and_normalize_erasing_regions(cast_ty)?;
                 self.cast(&src, cast_kind, cast_ty, &dest)?;
             }
 
diff --git a/compiler/rustc_const_eval/src/interpret/terminator.rs b/compiler/rustc_const_eval/src/interpret/terminator.rs
index ff20fc5092c..4037220e5ed 100644
--- a/compiler/rustc_const_eval/src/interpret/terminator.rs
+++ b/compiler/rustc_const_eval/src/interpret/terminator.rs
@@ -173,7 +173,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
             Drop { place, target, unwind, replace: _ } => {
                 let frame = self.frame();
                 let ty = place.ty(&frame.body.local_decls, *self.tcx).ty;
-                let ty = self.subst_from_frame_and_normalize_erasing_regions(frame, ty)?;
+                let ty = self.instantiate_from_frame_and_normalize_erasing_regions(frame, ty)?;
                 let instance = Instance::resolve_drop_in_place(*self.tcx, ty);
                 if let ty::InstanceDef::DropGlue(_, None) = instance.def {
                     // This is the branch we enter if and only if the dropped type has no drop glue
@@ -672,8 +672,8 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
                         // Construct the destination place for this argument. At this point all
                         // locals are still dead, so we cannot construct a `PlaceTy`.
                         let dest = mir::Place::from(local);
-                        // `layout_of_local` does more than just the substitution we need to get the
-                        // type, but the result gets cached so this avoids calling the substitution
+                        // `layout_of_local` does more than just the instantiation we need to get the
+                        // type, but the result gets cached so this avoids calling the instantiation
                         // query *again* the next time this local is accessed.
                         let ty = self.layout_of_local(self.frame(), local, None)?.ty;
                         if Some(local) == body.spread_arg {
diff --git a/compiler/rustc_const_eval/src/interpret/util.rs b/compiler/rustc_const_eval/src/interpret/util.rs
index 416443f5f4d..3a9ee904734 100644
--- a/compiler/rustc_const_eval/src/interpret/util.rs
+++ b/compiler/rustc_const_eval/src/interpret/util.rs
@@ -19,11 +19,11 @@ where
     }
 
     struct FoundParam;
-    struct UsedParamsNeedSubstVisitor<'tcx> {
+    struct UsedParamsNeedInstantiationVisitor<'tcx> {
         tcx: TyCtxt<'tcx>,
     }
 
-    impl<'tcx> TypeVisitor<TyCtxt<'tcx>> for UsedParamsNeedSubstVisitor<'tcx> {
+    impl<'tcx> TypeVisitor<TyCtxt<'tcx>> for UsedParamsNeedInstantiationVisitor<'tcx> {
         type BreakTy = FoundParam;
 
         fn visit_ty(&mut self, ty: Ty<'tcx>) -> ControlFlow<Self::BreakTy> {
@@ -34,21 +34,22 @@ where
             match *ty.kind() {
                 ty::Param(_) => ControlFlow::Break(FoundParam),
                 ty::Closure(def_id, args)
+                | ty::CoroutineClosure(def_id, args, ..)
                 | ty::Coroutine(def_id, args, ..)
                 | ty::FnDef(def_id, args) => {
                     let instance = ty::InstanceDef::Item(def_id);
                     let unused_params = self.tcx.unused_generic_params(instance);
-                    for (index, subst) in args.into_iter().enumerate() {
+                    for (index, arg) in args.into_iter().enumerate() {
                         let index = index
                             .try_into()
                             .expect("more generic parameters than can fit into a `u32`");
                         // Only recurse when generic parameters in fns, closures and coroutines
                         // are used and have to be instantiated.
                         //
-                        // Just in case there are closures or coroutines within this subst,
+                        // Just in case there are closures or coroutines within this arg,
                         // recurse.
-                        if unused_params.is_used(index) && subst.has_param() {
-                            return subst.visit_with(self);
+                        if unused_params.is_used(index) && arg.has_param() {
+                            return arg.visit_with(self);
                         }
                     }
                     ControlFlow::Continue(())
@@ -65,7 +66,7 @@ where
         }
     }
 
-    let mut vis = UsedParamsNeedSubstVisitor { tcx };
+    let mut vis = UsedParamsNeedInstantiationVisitor { tcx };
     if matches!(ty.visit_with(&mut vis), ControlFlow::Break(FoundParam)) {
         throw_inval!(TooGeneric);
     } else {
diff --git a/compiler/rustc_const_eval/src/interpret/validity.rs b/compiler/rustc_const_eval/src/interpret/validity.rs
index 38aeace02ba..eb9f3fee165 100644
--- a/compiler/rustc_const_eval/src/interpret/validity.rs
+++ b/compiler/rustc_const_eval/src/interpret/validity.rs
@@ -129,17 +129,20 @@ pub enum PathElem {
 pub enum CtfeValidationMode {
     /// Validation of a `static`
     Static { mutbl: Mutability },
-    /// Validation of a `const` (including promoteds).
+    /// Validation of a promoted.
+    Promoted,
+    /// Validation of a `const`.
     /// `allow_immutable_unsafe_cell` says whether we allow `UnsafeCell` in immutable memory (which is the
     /// case for the top-level allocation of a `const`, where this is fine because the allocation will be
     /// copied at each use site).
-    Const { allow_immutable_unsafe_cell: bool, allow_extern_static_ptrs: bool },
+    Const { allow_immutable_unsafe_cell: bool },
 }
 
 impl CtfeValidationMode {
     fn allow_immutable_unsafe_cell(self) -> bool {
         match self {
             CtfeValidationMode::Static { .. } => false,
+            CtfeValidationMode::Promoted { .. } => false,
             CtfeValidationMode::Const { allow_immutable_unsafe_cell, .. } => {
                 allow_immutable_unsafe_cell
             }
@@ -149,6 +152,7 @@ impl CtfeValidationMode {
     fn may_contain_mutable_ref(self) -> bool {
         match self {
             CtfeValidationMode::Static { mutbl } => mutbl == Mutability::Mut,
+            CtfeValidationMode::Promoted { .. } => false,
             CtfeValidationMode::Const { .. } => false,
         }
     }
@@ -236,8 +240,8 @@ impl<'rt, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> ValidityVisitor<'rt, 'mir, '
 
         // Now we know we are projecting to a field, so figure out which one.
         match layout.ty.kind() {
-            // coroutines and closures.
-            ty::Closure(def_id, _) | ty::Coroutine(def_id, _) => {
+            // coroutines, closures, and coroutine-closures all have upvars that may be named.
+            ty::Closure(def_id, _) | ty::Coroutine(def_id, _) | ty::CoroutineClosure(def_id, _) => {
                 let mut name = None;
                 // FIXME this should be more descriptive i.e. CapturePlace instead of CapturedVar
                 // https://github.com/rust-lang/project-rfc-2229/issues/46
@@ -476,34 +480,32 @@ impl<'rt, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> ValidityVisitor<'rt, 'mir, '
                                 throw_validation_failure!(self.path, MutableRefToImmutable);
                             }
                         }
+                        // Mode-specific checks
                         match self.ctfe_mode {
-                            Some(CtfeValidationMode::Static { .. }) => {
+                            Some(
+                                CtfeValidationMode::Static { .. }
+                                | CtfeValidationMode::Promoted { .. },
+                            ) => {
                                 // We skip recursively checking other statics. These statics must be sound by
                                 // themselves, and the only way to get broken statics here is by using
                                 // unsafe code.
                                 // The reasons we don't check other statics is twofold. For one, in all
                                 // sound cases, the static was already validated on its own, and second, we
                                 // trigger cycle errors if we try to compute the value of the other static
-                                // and that static refers back to us.
+                                // and that static refers back to us (potentially through a promoted).
                                 // This could miss some UB, but that's fine.
                                 return Ok(());
                             }
-                            Some(CtfeValidationMode::Const {
-                                allow_extern_static_ptrs, ..
-                            }) => {
+                            Some(CtfeValidationMode::Const { .. }) => {
                                 // For consts on the other hand we have to recursively check;
                                 // pattern matching assumes a valid value. However we better make
                                 // sure this is not mutable.
                                 if is_mut {
                                     throw_validation_failure!(self.path, ConstRefToMutable);
                                 }
+                                // We can't recursively validate `extern static`, so we better reject them.
                                 if self.ecx.tcx.is_foreign_item(did) {
-                                    if !allow_extern_static_ptrs {
-                                        throw_validation_failure!(self.path, ConstRefToExtern);
-                                    } else {
-                                        // We can't validate this...
-                                        return Ok(());
-                                    }
+                                    throw_validation_failure!(self.path, ConstRefToExtern);
                                 }
                             }
                             None => {}
diff --git a/compiler/rustc_const_eval/src/transform/check_consts/check.rs b/compiler/rustc_const_eval/src/transform/check_consts/check.rs
index 28dc69859fd..43048dc41d3 100644
--- a/compiler/rustc_const_eval/src/transform/check_consts/check.rs
+++ b/compiler/rustc_const_eval/src/transform/check_consts/check.rs
@@ -619,9 +619,11 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> {
                 if base_ty.is_unsafe_ptr() {
                     if place_ref.projection.is_empty() {
                         let decl = &self.body.local_decls[place_ref.local];
-                        if let LocalInfo::StaticRef { def_id, .. } = *decl.local_info() {
-                            let span = decl.source_info.span;
-                            self.check_static(def_id, span);
+                        // If this is a static, then this is not really dereferencing a pointer,
+                        // just directly accessing a static. That is not subject to any feature
+                        // gates (except for the one about whether statics can even be used, but
+                        // that is checked already by `visit_operand`).
+                        if let LocalInfo::StaticRef { .. } = *decl.local_info() {
                             return;
                         }
                     }
diff --git a/compiler/rustc_const_eval/src/transform/check_consts/mod.rs b/compiler/rustc_const_eval/src/transform/check_consts/mod.rs
index 1be2a2bc1f3..12e7ec15e32 100644
--- a/compiler/rustc_const_eval/src/transform/check_consts/mod.rs
+++ b/compiler/rustc_const_eval/src/transform/check_consts/mod.rs
@@ -72,7 +72,7 @@ impl<'mir, 'tcx> ConstCx<'mir, 'tcx> {
 
     pub fn fn_sig(&self) -> PolyFnSig<'tcx> {
         let did = self.def_id().to_def_id();
-        if self.tcx.is_closure_or_coroutine(did) {
+        if self.tcx.is_closure_like(did) {
             let ty = self.tcx.type_of(did).instantiate_identity();
             let ty::Closure(_, args) = ty.kind() else { bug!("type_of closure not ty::Closure") };
             args.as_closure().sig()
diff --git a/compiler/rustc_const_eval/src/transform/check_consts/ops.rs b/compiler/rustc_const_eval/src/transform/check_consts/ops.rs
index a9d472d377c..0c93cfaa546 100644
--- a/compiler/rustc_const_eval/src/transform/check_consts/ops.rs
+++ b/compiler/rustc_const_eval/src/transform/check_consts/ops.rs
@@ -409,11 +409,6 @@ impl<'tcx> NonConstOp<'tcx> for TransientCellBorrow {
     fn status_in_item(&self, _: &ConstCx<'_, 'tcx>) -> Status {
         Status::Unstable(sym::const_refs_to_cell)
     }
-    fn importance(&self) -> DiagnosticImportance {
-        // The cases that cannot possibly work will already emit a `CellBorrow`, so we should
-        // not additionally emit a feature gate error if activating the feature gate won't work.
-        DiagnosticImportance::Secondary
-    }
     fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx> {
         ccx.tcx
             .sess
@@ -427,6 +422,11 @@ impl<'tcx> NonConstOp<'tcx> for TransientCellBorrow {
 /// it in the future for static items.
 pub struct CellBorrow;
 impl<'tcx> NonConstOp<'tcx> for CellBorrow {
+    fn importance(&self) -> DiagnosticImportance {
+        // Most likely the code will try to do mutation with these borrows, which
+        // triggers its own errors. Only show this one if that does not happen.
+        DiagnosticImportance::Secondary
+    }
     fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx> {
         // FIXME: Maybe a more elegant solution to this if else case
         if let hir::ConstContext::Static(_) = ccx.const_kind() {
@@ -459,8 +459,8 @@ impl<'tcx> NonConstOp<'tcx> for MutBorrow {
     }
 
     fn importance(&self) -> DiagnosticImportance {
-        // If there were primary errors (like non-const function calls), do not emit further
-        // errors about mutable references.
+        // Most likely the code will try to do mutation with these borrows, which
+        // triggers its own errors. Only show this one if that does not happen.
         DiagnosticImportance::Secondary
     }
 
diff --git a/compiler/rustc_const_eval/src/transform/check_consts/resolver.rs b/compiler/rustc_const_eval/src/transform/check_consts/resolver.rs
index a23922c778f..2c835f6750f 100644
--- a/compiler/rustc_const_eval/src/transform/check_consts/resolver.rs
+++ b/compiler/rustc_const_eval/src/transform/check_consts/resolver.rs
@@ -96,7 +96,7 @@ where
         });
     }
 
-    fn address_of_allows_mutation(&self, _mt: mir::Mutability, _place: mir::Place<'tcx>) -> bool {
+    fn address_of_allows_mutation(&self) -> bool {
         // Exact set of permissions granted by AddressOf is undecided. Conservatively assume that
         // it might allow mutation until resolution of #56604.
         true
@@ -171,10 +171,8 @@ where
         self.super_rvalue(rvalue, location);
 
         match rvalue {
-            mir::Rvalue::AddressOf(mt, borrowed_place) => {
-                if !borrowed_place.is_indirect()
-                    && self.address_of_allows_mutation(*mt, *borrowed_place)
-                {
+            mir::Rvalue::AddressOf(_mt, borrowed_place) => {
+                if !borrowed_place.is_indirect() && self.address_of_allows_mutation() {
                     let place_ty = borrowed_place.ty(self.ccx.body, self.ccx.tcx).ty;
                     if Q::in_any_value_of_ty(self.ccx, place_ty) {
                         self.state.qualif.insert(borrowed_place.local);