about summary refs log tree commit diff
diff options
context:
space:
mode:
authorOli Scherer <git-spam-no-reply9815368754983@oli-obk.de>2022-11-21 16:51:16 +0000
committerOli Scherer <git-spam-no-reply9815368754983@oli-obk.de>2022-12-15 16:07:28 +0000
commitd66824dbc4fb74598251a89d7c3c5fb2df5afeba (patch)
tree14f9cf94e9a62acd51d8dc04d9e4df8f5cccd7d5
parented71e32e1440765d3e133e9892d59ca130477cec (diff)
downloadrust-d66824dbc4fb74598251a89d7c3c5fb2df5afeba.tar.gz
rust-d66824dbc4fb74598251a89d7c3c5fb2df5afeba.zip
Make alignment checks a future incompat lint
-rw-r--r--compiler/rustc_const_eval/src/const_eval/eval_queries.rs15
-rw-r--r--compiler/rustc_const_eval/src/const_eval/machine.rs26
-rw-r--r--compiler/rustc_const_eval/src/interpret/eval_context.rs16
-rw-r--r--compiler/rustc_const_eval/src/interpret/machine.rs4
-rw-r--r--compiler/rustc_const_eval/src/interpret/memory.rs83
-rw-r--r--compiler/rustc_const_eval/src/interpret/place.rs9
-rw-r--r--compiler/rustc_const_eval/src/util/might_permit_raw_init.rs4
-rw-r--r--compiler/rustc_lint_defs/src/builtin.rs36
-rw-r--r--compiler/rustc_mir_transform/src/const_prop.rs5
-rw-r--r--compiler/rustc_mir_transform/src/dataflow_const_prop.rs3
-rw-r--r--src/test/ui/consts/const-eval/ub-ref-ptr.32bit.stderr20
-rw-r--r--src/test/ui/consts/const-eval/ub-ref-ptr.64bit.stderr20
-rw-r--r--src/tools/miri/src/machine.rs9
13 files changed, 180 insertions, 70 deletions
diff --git a/compiler/rustc_const_eval/src/const_eval/eval_queries.rs b/compiler/rustc_const_eval/src/const_eval/eval_queries.rs
index 4dfa42d15e0..18e01567ca3 100644
--- a/compiler/rustc_const_eval/src/const_eval/eval_queries.rs
+++ b/compiler/rustc_const_eval/src/const_eval/eval_queries.rs
@@ -1,3 +1,4 @@
+use crate::const_eval::CheckAlignment;
 use std::borrow::Cow;
 
 use either::{Left, Right};
@@ -76,7 +77,7 @@ fn eval_body_using_ecx<'mir, 'tcx>(
             None => InternKind::Constant,
         }
     };
-    ecx.machine.check_alignment = false; // interning doesn't need to respect alignment
+    ecx.machine.check_alignment = CheckAlignment::No; // interning doesn't need to respect alignment
     intern_const_alloc_recursive(ecx, intern_kind, &ret)?;
     // we leave alignment checks off, since this `ecx` will not be used for further evaluation anyway
 
@@ -102,11 +103,7 @@ pub(super) fn mk_eval_cx<'mir, 'tcx>(
         tcx,
         root_span,
         param_env,
-        CompileTimeInterpreter::new(
-            tcx.const_eval_limit(),
-            can_access_statics,
-            /*check_alignment:*/ false,
-        ),
+        CompileTimeInterpreter::new(tcx.const_eval_limit(), can_access_statics, CheckAlignment::No),
     )
 }
 
@@ -311,7 +308,11 @@ pub fn eval_to_allocation_raw_provider<'tcx>(
         CompileTimeInterpreter::new(
             tcx.const_eval_limit(),
             /*can_access_statics:*/ is_static,
-            /*check_alignment:*/ true,
+            if tcx.sess.opts.unstable_opts.extra_const_ub_checks {
+                CheckAlignment::Error
+            } else {
+                CheckAlignment::FutureIncompat
+            },
         ),
     );
 
diff --git a/compiler/rustc_const_eval/src/const_eval/machine.rs b/compiler/rustc_const_eval/src/const_eval/machine.rs
index 3dfded2d930..355ad669296 100644
--- a/compiler/rustc_const_eval/src/const_eval/machine.rs
+++ b/compiler/rustc_const_eval/src/const_eval/machine.rs
@@ -47,14 +47,34 @@ pub struct CompileTimeInterpreter<'mir, 'tcx> {
     pub(super) can_access_statics: bool,
 
     /// Whether to check alignment during evaluation.
-    pub(super) check_alignment: bool,
+    pub(super) check_alignment: CheckAlignment,
+}
+
+#[derive(Copy, Clone)]
+pub enum CheckAlignment {
+    /// Ignore alignment when following relocations.
+    /// This is mainly used in interning.
+    No,
+    /// Hard error when dereferencing a misaligned pointer.
+    Error,
+    /// Emit a future incompat lint when dereferencing a misaligned pointer.
+    FutureIncompat,
+}
+
+impl CheckAlignment {
+    pub fn should_check(&self) -> bool {
+        match self {
+            CheckAlignment::No => false,
+            CheckAlignment::Error | CheckAlignment::FutureIncompat => true,
+        }
+    }
 }
 
 impl<'mir, 'tcx> CompileTimeInterpreter<'mir, 'tcx> {
     pub(crate) fn new(
         const_eval_limit: Limit,
         can_access_statics: bool,
-        check_alignment: bool,
+        check_alignment: CheckAlignment,
     ) -> Self {
         CompileTimeInterpreter {
             steps_remaining: const_eval_limit.0,
@@ -309,7 +329,7 @@ impl<'mir, 'tcx> interpret::Machine<'mir, 'tcx> for CompileTimeInterpreter<'mir,
     const PANIC_ON_ALLOC_FAIL: bool = false; // will be raised as a proper error
 
     #[inline(always)]
-    fn enforce_alignment(ecx: &InterpCx<'mir, 'tcx, Self>) -> bool {
+    fn enforce_alignment(ecx: &InterpCx<'mir, 'tcx, Self>) -> CheckAlignment {
         ecx.machine.check_alignment
     }
 
diff --git a/compiler/rustc_const_eval/src/interpret/eval_context.rs b/compiler/rustc_const_eval/src/interpret/eval_context.rs
index 0b2809f1d2c..f551b5c2911 100644
--- a/compiler/rustc_const_eval/src/interpret/eval_context.rs
+++ b/compiler/rustc_const_eval/src/interpret/eval_context.rs
@@ -248,6 +248,15 @@ impl<'mir, 'tcx, Prov: Provenance, Extra> Frame<'mir, 'tcx, Prov, Extra> {
             Right(span) => span,
         }
     }
+
+    pub fn lint_root(&self) -> Option<hir::HirId> {
+        self.current_source_info().and_then(|source_info| {
+            match &self.body.source_scopes[source_info.scope].local_data {
+                mir::ClearCrossCrate::Set(data) => Some(data.lint_root),
+                mir::ClearCrossCrate::Clear => None,
+            }
+        })
+    }
 }
 
 impl<'tcx> fmt::Display for FrameInfo<'tcx> {
@@ -954,12 +963,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
         // This deliberately does *not* honor `requires_caller_location` since it is used for much
         // more than just panics.
         for frame in stack.iter().rev() {
-            let lint_root = frame.current_source_info().and_then(|source_info| {
-                match &frame.body.source_scopes[source_info.scope].local_data {
-                    mir::ClearCrossCrate::Set(data) => Some(data.lint_root),
-                    mir::ClearCrossCrate::Clear => None,
-                }
-            });
+            let lint_root = frame.lint_root();
             let span = frame.current_span();
 
             frames.push(FrameInfo { span, instance: frame.instance, lint_root });
diff --git a/compiler/rustc_const_eval/src/interpret/machine.rs b/compiler/rustc_const_eval/src/interpret/machine.rs
index 0604d5ee6fa..f52545317ea 100644
--- a/compiler/rustc_const_eval/src/interpret/machine.rs
+++ b/compiler/rustc_const_eval/src/interpret/machine.rs
@@ -13,6 +13,8 @@ use rustc_span::def_id::DefId;
 use rustc_target::abi::Size;
 use rustc_target::spec::abi::Abi as CallAbi;
 
+use crate::const_eval::CheckAlignment;
+
 use super::{
     AllocId, AllocRange, Allocation, ConstAllocation, Frame, ImmTy, InterpCx, InterpResult,
     MemoryKind, OpTy, Operand, PlaceTy, Pointer, Provenance, Scalar, StackPopUnwind,
@@ -122,7 +124,7 @@ pub trait Machine<'mir, 'tcx>: Sized {
     const PANIC_ON_ALLOC_FAIL: bool;
 
     /// Whether memory accesses should be alignment-checked.
-    fn enforce_alignment(ecx: &InterpCx<'mir, 'tcx, Self>) -> bool;
+    fn enforce_alignment(ecx: &InterpCx<'mir, 'tcx, Self>) -> CheckAlignment;
 
     /// Whether, when checking alignment, we should look at the actual address and thus support
     /// custom alignment logic based on whatever the integer address happens to be.
diff --git a/compiler/rustc_const_eval/src/interpret/memory.rs b/compiler/rustc_const_eval/src/interpret/memory.rs
index b8feb7feda3..ffd5e05bcc4 100644
--- a/compiler/rustc_const_eval/src/interpret/memory.rs
+++ b/compiler/rustc_const_eval/src/interpret/memory.rs
@@ -14,10 +14,15 @@ use std::ptr;
 
 use rustc_ast::Mutability;
 use rustc_data_structures::fx::{FxHashMap, FxHashSet};
+use rustc_hir::CRATE_HIR_ID;
 use rustc_middle::mir::display_allocation;
+use rustc_middle::mir::interpret::UndefinedBehaviorInfo;
 use rustc_middle::ty::{self, Instance, ParamEnv, Ty, TyCtxt};
+use rustc_session::lint::builtin::INVALID_ALIGNMENT;
 use rustc_target::abi::{Align, HasDataLayout, Size};
 
+use crate::const_eval::CheckAlignment;
+
 use super::{
     alloc_range, AllocId, AllocMap, AllocRange, Allocation, CheckInAllocMsg, GlobalAlloc, InterpCx,
     InterpResult, Machine, MayLeak, Pointer, PointerArithmetic, Provenance, Scalar,
@@ -377,7 +382,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
             ptr,
             size,
             align,
-            /* force_alignment_check */ true,
+            CheckAlignment::Error,
             msg,
             |alloc_id, _, _| {
                 let (size, align) = self.get_live_alloc_size_and_align(alloc_id)?;
@@ -396,7 +401,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
         ptr: Pointer<Option<M::Provenance>>,
         size: Size,
         align: Align,
-        force_alignment_check: bool,
+        check: CheckAlignment,
         msg: CheckInAllocMsg,
         alloc_size: impl FnOnce(
             AllocId,
@@ -404,19 +409,6 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
             M::ProvenanceExtra,
         ) -> InterpResult<'tcx, (Size, Align, T)>,
     ) -> InterpResult<'tcx, Option<T>> {
-        fn check_offset_align<'tcx>(offset: u64, align: Align) -> InterpResult<'tcx> {
-            if offset % align.bytes() == 0 {
-                Ok(())
-            } else {
-                // The biggest power of two through which `offset` is divisible.
-                let offset_pow2 = 1 << offset.trailing_zeros();
-                throw_ub!(AlignmentCheckFailed {
-                    has: Align::from_bytes(offset_pow2).unwrap(),
-                    required: align,
-                })
-            }
-        }
-
         Ok(match self.ptr_try_get_alloc_id(ptr) {
             Err(addr) => {
                 // We couldn't get a proper allocation. This is only okay if the access size is 0,
@@ -425,8 +417,8 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
                     throw_ub!(DanglingIntPointer(addr, msg));
                 }
                 // Must be aligned.
-                if force_alignment_check {
-                    check_offset_align(addr, align)?;
+                if check.should_check() {
+                    self.check_offset_align(addr, align, check)?;
                 }
                 None
             }
@@ -449,16 +441,16 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
                 }
                 // Test align. Check this last; if both bounds and alignment are violated
                 // we want the error to be about the bounds.
-                if force_alignment_check {
+                if check.should_check() {
                     if M::use_addr_for_alignment_check(self) {
                         // `use_addr_for_alignment_check` can only be true if `OFFSET_IS_ADDR` is true.
-                        check_offset_align(ptr.addr().bytes(), align)?;
+                        self.check_offset_align(ptr.addr().bytes(), align, check)?;
                     } else {
                         // Check allocation alignment and offset alignment.
                         if alloc_align.bytes() < align.bytes() {
-                            throw_ub!(AlignmentCheckFailed { has: alloc_align, required: align });
+                            self.alignment_check_failed(alloc_align, align, check)?;
                         }
-                        check_offset_align(offset.bytes(), align)?;
+                        self.check_offset_align(offset.bytes(), align, check)?;
                     }
                 }
 
@@ -468,6 +460,55 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
             }
         })
     }
+
+    fn check_offset_align(
+        &self,
+        offset: u64,
+        align: Align,
+        check: CheckAlignment,
+    ) -> InterpResult<'tcx> {
+        if offset % align.bytes() == 0 {
+            Ok(())
+        } else {
+            // The biggest power of two through which `offset` is divisible.
+            let offset_pow2 = 1 << offset.trailing_zeros();
+            self.alignment_check_failed(Align::from_bytes(offset_pow2).unwrap(), align, check)
+        }
+    }
+
+    fn alignment_check_failed(
+        &self,
+        has: Align,
+        required: Align,
+        check: CheckAlignment,
+    ) -> InterpResult<'tcx, ()> {
+        match check {
+            CheckAlignment::Error => {
+                throw_ub!(AlignmentCheckFailed { has, required })
+            }
+            CheckAlignment::No => span_bug!(
+                self.cur_span(),
+                "`alignment_check_failed` called when no alignment check requested"
+            ),
+            CheckAlignment::FutureIncompat => self.tcx.struct_span_lint_hir(
+                INVALID_ALIGNMENT,
+                self.stack().iter().find_map(|frame| frame.lint_root()).unwrap_or(CRATE_HIR_ID),
+                self.cur_span(),
+                UndefinedBehaviorInfo::AlignmentCheckFailed { has, required }.to_string(),
+                |db| {
+                    let mut stacktrace = self.generate_stacktrace();
+                    // Filter out `requires_caller_location` frames.
+                    stacktrace
+                        .retain(|frame| !frame.instance.def.requires_caller_location(*self.tcx));
+                    for frame in stacktrace {
+                        db.span_label(frame.span, format!("inside `{}`", frame.instance));
+                    }
+                    db
+                },
+            ),
+        }
+        Ok(())
+    }
 }
 
 /// Allocation accessors
diff --git a/compiler/rustc_const_eval/src/interpret/place.rs b/compiler/rustc_const_eval/src/interpret/place.rs
index c47cfe8bb69..905eb71bb18 100644
--- a/compiler/rustc_const_eval/src/interpret/place.rs
+++ b/compiler/rustc_const_eval/src/interpret/place.rs
@@ -364,13 +364,8 @@ where
             .size_and_align_of_mplace(&mplace)?
             .unwrap_or((mplace.layout.size, mplace.layout.align.abi));
         assert!(mplace.align <= align, "dynamic alignment less strict than static one?");
-        let align = M::enforce_alignment(self).then_some(align);
-        self.check_ptr_access_align(
-            mplace.ptr,
-            size,
-            align.unwrap_or(Align::ONE),
-            CheckInAllocMsg::DerefTest,
-        )?;
+        let align = if M::enforce_alignment(self).should_check() { align } else { Align::ONE };
+        self.check_ptr_access_align(mplace.ptr, size, align, CheckInAllocMsg::DerefTest)?;
         Ok(())
     }
 
diff --git a/compiler/rustc_const_eval/src/util/might_permit_raw_init.rs b/compiler/rustc_const_eval/src/util/might_permit_raw_init.rs
index 6ca71223391..4ce107ea68d 100644
--- a/compiler/rustc_const_eval/src/util/might_permit_raw_init.rs
+++ b/compiler/rustc_const_eval/src/util/might_permit_raw_init.rs
@@ -3,7 +3,7 @@ use rustc_middle::ty::{ParamEnv, TyCtxt};
 use rustc_session::Limit;
 use rustc_target::abi::{Abi, FieldsShape, InitKind, Scalar, Variants};
 
-use crate::const_eval::CompileTimeInterpreter;
+use crate::const_eval::{CheckAlignment, CompileTimeInterpreter};
 use crate::interpret::{InterpCx, MemoryKind, OpTy};
 
 /// Determines if this type permits "raw" initialization by just transmuting some memory into an
@@ -41,7 +41,7 @@ fn might_permit_raw_init_strict<'tcx>(
     let machine = CompileTimeInterpreter::new(
         Limit::new(0),
         /*can_access_statics:*/ false,
-        /*check_alignment:*/ true,
+        CheckAlignment::Error,
     );
 
     let mut cx = InterpCx::new(tcx, rustc_span::DUMMY_SP, ParamEnv::reveal_all(), machine);
diff --git a/compiler/rustc_lint_defs/src/builtin.rs b/compiler/rustc_lint_defs/src/builtin.rs
index a3008e9e321..dddc200b2fb 100644
--- a/compiler/rustc_lint_defs/src/builtin.rs
+++ b/compiler/rustc_lint_defs/src/builtin.rs
@@ -1020,6 +1020,42 @@ declare_lint! {
 }
 
 declare_lint! {
+    /// The `invalid_alignment` lint detects dereferences of misaligned pointers during
+    /// constant evluation.
+    ///
+    /// ### Example
+    ///
+    /// ```rust,compile_fail
+    /// const FOO: () = unsafe {
+    ///     let x = [0_u8; 10];
+    ///     let y = x.as_ptr() as *const u32;
+    ///     *y; // the address of a `u8` array is unknown and thus we don't know if
+    ///     // it is aligned enough for reading a `u32`.
+    /// }
+    /// ```
+    ///
+    /// {{produces}}
+    ///
+    /// ### Explanation
+    ///
+    /// The compiler allowed dereferencing raw pointers irrespective of alignment
+    /// during const eval due to the const evaluator at the time not making it easy
+    /// or cheap to check. Now that it is both, this is not accepted anymore.
+    ///
+    /// Since it was undefined behaviour to begin with, this breakage does not violate
+    /// Rust's stability guarantees. Using undefined behaviour can cause arbitrary
+    /// behaviour, including failure to build.
+    ///
+    /// [future-incompatible]: ../index.md#future-incompatible-lints
+    pub INVALID_ALIGNMENT,
+    Deny,
+    "raw pointers must be aligned before dereferencing",
+    @future_incompatible = FutureIncompatibleInfo {
+        reference: "issue #68585 <https://github.com/rust-lang/rust/issues/104616>",
+    };
+}
+
+declare_lint! {
     /// The `exported_private_dependencies` lint detects private dependencies
     /// that are exposed in a public interface.
     ///
diff --git a/compiler/rustc_mir_transform/src/const_prop.rs b/compiler/rustc_mir_transform/src/const_prop.rs
index b0514e03356..c8ba6310d59 100644
--- a/compiler/rustc_mir_transform/src/const_prop.rs
+++ b/compiler/rustc_mir_transform/src/const_prop.rs
@@ -6,6 +6,7 @@ use std::cell::Cell;
 use either::Right;
 
 use rustc_ast::Mutability;
+use rustc_const_eval::const_eval::CheckAlignment;
 use rustc_data_structures::fx::FxHashSet;
 use rustc_hir::def::DefKind;
 use rustc_index::bit_set::BitSet;
@@ -186,10 +187,10 @@ impl<'mir, 'tcx> interpret::Machine<'mir, 'tcx> for ConstPropMachine<'mir, 'tcx>
     type MemoryKind = !;
 
     #[inline(always)]
-    fn enforce_alignment(_ecx: &InterpCx<'mir, 'tcx, Self>) -> bool {
+    fn enforce_alignment(_ecx: &InterpCx<'mir, 'tcx, Self>) -> CheckAlignment {
         // We do not check for alignment to avoid having to carry an `Align`
         // in `ConstValue::ByRef`.
-        false
+        CheckAlignment::No
     }
 
     #[inline(always)]
diff --git a/compiler/rustc_mir_transform/src/dataflow_const_prop.rs b/compiler/rustc_mir_transform/src/dataflow_const_prop.rs
index e9027387413..37675426f19 100644
--- a/compiler/rustc_mir_transform/src/dataflow_const_prop.rs
+++ b/compiler/rustc_mir_transform/src/dataflow_const_prop.rs
@@ -2,6 +2,7 @@
 //!
 //! Currently, this pass only propagates scalar values.
 
+use rustc_const_eval::const_eval::CheckAlignment;
 use rustc_const_eval::interpret::{ConstValue, ImmTy, Immediate, InterpCx, Scalar};
 use rustc_data_structures::fx::FxHashMap;
 use rustc_middle::mir::visit::{MutVisitor, Visitor};
@@ -448,7 +449,7 @@ impl<'mir, 'tcx> rustc_const_eval::interpret::Machine<'mir, 'tcx> for DummyMachi
     type MemoryKind = !;
     const PANIC_ON_ALLOC_FAIL: bool = true;
 
-    fn enforce_alignment(_ecx: &InterpCx<'mir, 'tcx, Self>) -> bool {
+    fn enforce_alignment(_ecx: &InterpCx<'mir, 'tcx, Self>) -> CheckAlignment {
         unimplemented!()
     }
 
diff --git a/src/test/ui/consts/const-eval/ub-ref-ptr.32bit.stderr b/src/test/ui/consts/const-eval/ub-ref-ptr.32bit.stderr
index b4c343e64d5..8cd3918c0b4 100644
--- a/src/test/ui/consts/const-eval/ub-ref-ptr.32bit.stderr
+++ b/src/test/ui/consts/const-eval/ub-ref-ptr.32bit.stderr
@@ -148,20 +148,22 @@ LL | const DATA_FN_PTR: fn() = unsafe { mem::transmute(&13) };
                ╾─alloc41─╼                                     │ ╾──╼
            }
 
-error[E0080]: evaluation of constant value failed
+error: accessing memory with alignment 1, but alignment 4 is required
   --> $SRC_DIR/core/src/ptr/mod.rs:LL:COL
    |
-   = note: accessing memory with alignment 1, but alignment 4 is required
-   |
-note: inside `std::ptr::read::<u32>`
-  --> $SRC_DIR/core/src/ptr/mod.rs:LL:COL
-note: inside `ptr::const_ptr::<impl *const u32>::read`
+   = note: inside `std::ptr::read::<u32>`
   --> $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL
-note: inside `UNALIGNED_READ`
-  --> $DIR/ub-ref-ptr.rs:65:5
+   |
+   = note: inside `ptr::const_ptr::<impl *const u32>::read`
+   |
+  ::: $DIR/ub-ref-ptr.rs:65:5
    |
 LL |     ptr.read();
-   |     ^^^^^^^^^^
+   |     ---------- inside `UNALIGNED_READ`
+   |
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+   = note: for more information, see issue #68585 <https://github.com/rust-lang/rust/issues/104616>
+   = note: `#[deny(invalid_alignment)]` on by default
 
 error: aborting due to 15 previous errors
 
diff --git a/src/test/ui/consts/const-eval/ub-ref-ptr.64bit.stderr b/src/test/ui/consts/const-eval/ub-ref-ptr.64bit.stderr
index 012e050de84..77c52788a9c 100644
--- a/src/test/ui/consts/const-eval/ub-ref-ptr.64bit.stderr
+++ b/src/test/ui/consts/const-eval/ub-ref-ptr.64bit.stderr
@@ -148,20 +148,22 @@ LL | const DATA_FN_PTR: fn() = unsafe { mem::transmute(&13) };
                ╾───────alloc41───────╼                         │ ╾──────╼
            }
 
-error[E0080]: evaluation of constant value failed
+error: accessing memory with alignment 1, but alignment 4 is required
   --> $SRC_DIR/core/src/ptr/mod.rs:LL:COL
    |
-   = note: accessing memory with alignment 1, but alignment 4 is required
-   |
-note: inside `std::ptr::read::<u32>`
-  --> $SRC_DIR/core/src/ptr/mod.rs:LL:COL
-note: inside `ptr::const_ptr::<impl *const u32>::read`
+   = note: inside `std::ptr::read::<u32>`
   --> $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL
-note: inside `UNALIGNED_READ`
-  --> $DIR/ub-ref-ptr.rs:65:5
+   |
+   = note: inside `ptr::const_ptr::<impl *const u32>::read`
+   |
+  ::: $DIR/ub-ref-ptr.rs:65:5
    |
 LL |     ptr.read();
-   |     ^^^^^^^^^^
+   |     ---------- inside `UNALIGNED_READ`
+   |
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+   = note: for more information, see issue #68585 <https://github.com/rust-lang/rust/issues/104616>
+   = note: `#[deny(invalid_alignment)]` on by default
 
 error: aborting due to 15 previous errors
 
diff --git a/src/tools/miri/src/machine.rs b/src/tools/miri/src/machine.rs
index e5b1eb2e487..8f3c979f5eb 100644
--- a/src/tools/miri/src/machine.rs
+++ b/src/tools/miri/src/machine.rs
@@ -24,6 +24,7 @@ use rustc_span::def_id::{CrateNum, DefId};
 use rustc_span::Symbol;
 use rustc_target::abi::Size;
 use rustc_target::spec::abi::Abi;
+use rustc_const_eval::const_eval::CheckAlignment;
 
 use crate::{
     concurrency::{data_race, weak_memory},
@@ -752,8 +753,12 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for MiriMachine<'mir, 'tcx> {
     const PANIC_ON_ALLOC_FAIL: bool = false;
 
     #[inline(always)]
-    fn enforce_alignment(ecx: &MiriInterpCx<'mir, 'tcx>) -> bool {
-        ecx.machine.check_alignment != AlignmentCheck::None
+    fn enforce_alignment(ecx: &MiriInterpCx<'mir, 'tcx>) -> CheckAlignment {
+        if ecx.machine.check_alignment == AlignmentCheck::None {
+            CheckAlignment::No
+        } else {
+            CheckAlignment::Error
+        }
     }
 
     #[inline(always)]