summary refs log tree commit diff
path: root/compiler/rustc_const_eval/src
diff options
context:
space:
mode:
authorRalf Jung <post@ralfj.de>2023-08-02 16:14:36 +0200
committerRalf Jung <post@ralfj.de>2023-08-02 18:51:50 +0200
commit7767cbb3b0b332fd0a46e347ea7f68f20109d768 (patch)
tree4e748496f86ac3de86d85a83f65bafc6f85eb0f1 /compiler/rustc_const_eval/src
parent7637653b9fdd2b2f2dc3b378891eb5cf6aea9f5d (diff)
downloadrust-7767cbb3b0b332fd0a46e347ea7f68f20109d768.tar.gz
rust-7767cbb3b0b332fd0a46e347ea7f68f20109d768.zip
const validation: point at where we found a pointer but expected an integer
Diffstat (limited to 'compiler/rustc_const_eval/src')
-rw-r--r--compiler/rustc_const_eval/src/errors.rs154
-rw-r--r--compiler/rustc_const_eval/src/interpret/validity.rs102
2 files changed, 145 insertions, 111 deletions
diff --git a/compiler/rustc_const_eval/src/errors.rs b/compiler/rustc_const_eval/src/errors.rs
index 8cbc68d9061..3a4e2648b80 100644
--- a/compiler/rustc_const_eval/src/errors.rs
+++ b/compiler/rustc_const_eval/src/errors.rs
@@ -513,7 +513,7 @@ impl<'a> ReportErrorExt for UndefinedBehaviorInfo<'a> {
             ScalarSizeMismatch(_) => const_eval_scalar_size_mismatch,
             UninhabitedEnumVariantWritten(_) => const_eval_uninhabited_enum_variant_written,
             UninhabitedEnumVariantRead(_) => const_eval_uninhabited_enum_variant_read,
-            Validation(e) => e.diagnostic_message(),
+            ValidationError(e) => e.diagnostic_message(),
             Custom(x) => (x.msg)(),
         }
     }
@@ -587,13 +587,13 @@ impl<'a> ReportErrorExt for UndefinedBehaviorInfo<'a> {
             InvalidUninitBytes(Some((alloc, info))) => {
                 builder.set_arg("alloc", alloc);
                 builder.set_arg("access", info.access);
-                builder.set_arg("uninit", info.uninit);
+                builder.set_arg("uninit", info.bad);
             }
             ScalarSizeMismatch(info) => {
                 builder.set_arg("target_size", info.target_size);
                 builder.set_arg("data_size", info.data_size);
             }
-            Validation(e) => e.add_args(handler, builder),
+            ValidationError(e) => e.add_args(handler, builder),
             Custom(custom) => {
                 (custom.add_args)(&mut |name, value| {
                     builder.set_arg(name, value);
@@ -608,74 +608,72 @@ impl<'tcx> ReportErrorExt for ValidationErrorInfo<'tcx> {
         use crate::fluent_generated::*;
         use rustc_middle::mir::interpret::ValidationErrorKind::*;
         match self.kind {
-            PtrToUninhabited { ptr_kind: PointerKind::Box, .. } => const_eval_box_to_uninhabited,
-            PtrToUninhabited { ptr_kind: PointerKind::Ref, .. } => const_eval_ref_to_uninhabited,
-
-            PtrToStatic { ptr_kind: PointerKind::Box } => const_eval_box_to_static,
-            PtrToStatic { ptr_kind: PointerKind::Ref } => const_eval_ref_to_static,
-
-            PtrToMut { ptr_kind: PointerKind::Box } => const_eval_box_to_mut,
-            PtrToMut { ptr_kind: PointerKind::Ref } => const_eval_ref_to_mut,
-
-            ExpectedNonPtr { .. } => const_eval_expected_non_ptr,
-            MutableRefInConst => const_eval_mutable_ref_in_const,
-            NullFnPtr => const_eval_null_fn_ptr,
-            NeverVal => const_eval_never_val,
-            NullablePtrOutOfRange { .. } => const_eval_nullable_ptr_out_of_range,
-            PtrOutOfRange { .. } => const_eval_ptr_out_of_range,
-            OutOfRange { .. } => const_eval_out_of_range,
-            UnsafeCell => const_eval_unsafe_cell,
-            UninhabitedVal { .. } => const_eval_uninhabited_val,
-            InvalidEnumTag { .. } => const_eval_invalid_enum_tag,
-            UninhabitedEnumTag => const_eval_uninhabited_enum_tag,
-            UninitEnumTag => const_eval_uninit_enum_tag,
-            UninitStr => const_eval_uninit_str,
-            Uninit { expected: ExpectedKind::Bool } => const_eval_uninit_bool,
-            Uninit { expected: ExpectedKind::Reference } => const_eval_uninit_ref,
-            Uninit { expected: ExpectedKind::Box } => const_eval_uninit_box,
-            Uninit { expected: ExpectedKind::RawPtr } => const_eval_uninit_raw_ptr,
-            Uninit { expected: ExpectedKind::InitScalar } => const_eval_uninit_init_scalar,
-            Uninit { expected: ExpectedKind::Char } => const_eval_uninit_char,
-            Uninit { expected: ExpectedKind::Float } => const_eval_uninit_float,
-            Uninit { expected: ExpectedKind::Int } => const_eval_uninit_int,
-            Uninit { expected: ExpectedKind::FnPtr } => const_eval_uninit_fn_ptr,
-            UninitVal => const_eval_uninit,
-            InvalidVTablePtr { .. } => const_eval_invalid_vtable_ptr,
+            PtrToUninhabited { ptr_kind: PointerKind::Box, .. } => {
+                const_eval_validation_box_to_uninhabited
+            }
+            PtrToUninhabited { ptr_kind: PointerKind::Ref, .. } => {
+                const_eval_validation_ref_to_uninhabited
+            }
+
+            PtrToStatic { ptr_kind: PointerKind::Box } => const_eval_validation_box_to_static,
+            PtrToStatic { ptr_kind: PointerKind::Ref } => const_eval_validation_ref_to_static,
+
+            PtrToMut { ptr_kind: PointerKind::Box } => const_eval_validation_box_to_mut,
+            PtrToMut { ptr_kind: PointerKind::Ref } => const_eval_validation_ref_to_mut,
+
+            PointerAsInt { .. } => const_eval_validation_pointer_as_int,
+            PartialPointer => const_eval_validation_partial_pointer,
+            MutableRefInConst => const_eval_validation_mutable_ref_in_const,
+            NullFnPtr => const_eval_validation_null_fn_ptr,
+            NeverVal => const_eval_validation_never_val,
+            NullablePtrOutOfRange { .. } => const_eval_validation_nullable_ptr_out_of_range,
+            PtrOutOfRange { .. } => const_eval_validation_ptr_out_of_range,
+            OutOfRange { .. } => const_eval_validation_out_of_range,
+            UnsafeCell => const_eval_validation_unsafe_cell,
+            UninhabitedVal { .. } => const_eval_validation_uninhabited_val,
+            InvalidEnumTag { .. } => const_eval_validation_invalid_enum_tag,
+            UninhabitedEnumVariant => const_eval_validation_uninhabited_enum_variant,
+            Uninit { .. } => const_eval_validation_uninit,
+            InvalidVTablePtr { .. } => const_eval_validation_invalid_vtable_ptr,
             InvalidMetaSliceTooLarge { ptr_kind: PointerKind::Box } => {
-                const_eval_invalid_box_slice_meta
+                const_eval_validation_invalid_box_slice_meta
             }
             InvalidMetaSliceTooLarge { ptr_kind: PointerKind::Ref } => {
-                const_eval_invalid_ref_slice_meta
+                const_eval_validation_invalid_ref_slice_meta
             }
 
-            InvalidMetaTooLarge { ptr_kind: PointerKind::Box } => const_eval_invalid_box_meta,
-            InvalidMetaTooLarge { ptr_kind: PointerKind::Ref } => const_eval_invalid_ref_meta,
-            UnalignedPtr { ptr_kind: PointerKind::Ref, .. } => const_eval_unaligned_ref,
-            UnalignedPtr { ptr_kind: PointerKind::Box, .. } => const_eval_unaligned_box,
+            InvalidMetaTooLarge { ptr_kind: PointerKind::Box } => {
+                const_eval_validation_invalid_box_meta
+            }
+            InvalidMetaTooLarge { ptr_kind: PointerKind::Ref } => {
+                const_eval_validation_invalid_ref_meta
+            }
+            UnalignedPtr { ptr_kind: PointerKind::Ref, .. } => const_eval_validation_unaligned_ref,
+            UnalignedPtr { ptr_kind: PointerKind::Box, .. } => const_eval_validation_unaligned_box,
 
-            NullPtr { ptr_kind: PointerKind::Box } => const_eval_null_box,
-            NullPtr { ptr_kind: PointerKind::Ref } => const_eval_null_ref,
+            NullPtr { ptr_kind: PointerKind::Box } => const_eval_validation_null_box,
+            NullPtr { ptr_kind: PointerKind::Ref } => const_eval_validation_null_ref,
             DanglingPtrNoProvenance { ptr_kind: PointerKind::Box, .. } => {
-                const_eval_dangling_box_no_provenance
+                const_eval_validation_dangling_box_no_provenance
             }
             DanglingPtrNoProvenance { ptr_kind: PointerKind::Ref, .. } => {
-                const_eval_dangling_ref_no_provenance
+                const_eval_validation_dangling_ref_no_provenance
             }
             DanglingPtrOutOfBounds { ptr_kind: PointerKind::Box } => {
-                const_eval_dangling_box_out_of_bounds
+                const_eval_validation_dangling_box_out_of_bounds
             }
             DanglingPtrOutOfBounds { ptr_kind: PointerKind::Ref } => {
-                const_eval_dangling_ref_out_of_bounds
+                const_eval_validation_dangling_ref_out_of_bounds
             }
             DanglingPtrUseAfterFree { ptr_kind: PointerKind::Box } => {
-                const_eval_dangling_box_use_after_free
+                const_eval_validation_dangling_box_use_after_free
             }
             DanglingPtrUseAfterFree { ptr_kind: PointerKind::Ref } => {
-                const_eval_dangling_ref_use_after_free
+                const_eval_validation_dangling_ref_use_after_free
             }
             InvalidBool { .. } => const_eval_validation_invalid_bool,
             InvalidChar { .. } => const_eval_validation_invalid_char,
-            InvalidFnPtr { .. } => const_eval_invalid_fn_ptr,
+            InvalidFnPtr { .. } => const_eval_validation_invalid_fn_ptr,
         }
     }
 
@@ -683,13 +681,21 @@ impl<'tcx> ReportErrorExt for ValidationErrorInfo<'tcx> {
         use crate::fluent_generated as fluent;
         use rustc_middle::mir::interpret::ValidationErrorKind::*;
 
+        if let PointerAsInt { .. } | PartialPointer = self.kind {
+            err.help(fluent::const_eval_ptr_as_bytes_1);
+            err.help(fluent::const_eval_ptr_as_bytes_2);
+        }
+
         let message = if let Some(path) = self.path {
             handler.eagerly_translate_to_string(
-                fluent::const_eval_invalid_value_with_path,
+                fluent::const_eval_validation_front_matter_invalid_value_with_path,
                 [("path".into(), DiagnosticArgValue::Str(path.into()))].iter().map(|(a, b)| (a, b)),
             )
         } else {
-            handler.eagerly_translate_to_string(fluent::const_eval_invalid_value, [].into_iter())
+            handler.eagerly_translate_to_string(
+                fluent::const_eval_validation_front_matter_invalid_value,
+                [].into_iter(),
+            )
         };
 
         err.set_arg("front_matter", message);
@@ -729,8 +735,24 @@ impl<'tcx> ReportErrorExt for ValidationErrorInfo<'tcx> {
             PtrToUninhabited { ty, .. } | UninhabitedVal { ty } => {
                 err.set_arg("ty", ty);
             }
-            ExpectedNonPtr { value }
-            | InvalidEnumTag { value }
+            PointerAsInt { expected } | Uninit { expected } => {
+                let msg = match expected {
+                    ExpectedKind::Reference => fluent::const_eval_validation_expected_ref,
+                    ExpectedKind::Box => fluent::const_eval_validation_expected_box,
+                    ExpectedKind::RawPtr => fluent::const_eval_validation_expected_raw_ptr,
+                    ExpectedKind::InitScalar => fluent::const_eval_validation_expected_init_scalar,
+                    ExpectedKind::Bool => fluent::const_eval_validation_expected_bool,
+                    ExpectedKind::Char => fluent::const_eval_validation_expected_char,
+                    ExpectedKind::Float => fluent::const_eval_validation_expected_float,
+                    ExpectedKind::Int => fluent::const_eval_validation_expected_int,
+                    ExpectedKind::FnPtr => fluent::const_eval_validation_expected_fn_ptr,
+                    ExpectedKind::EnumTag => fluent::const_eval_validation_expected_enum_tag,
+                    ExpectedKind::Str => fluent::const_eval_validation_expected_str,
+                };
+                let msg = handler.eagerly_translate_to_string(msg, [].into_iter());
+                err.set_arg("expected", msg);
+            }
+            InvalidEnumTag { value }
             | InvalidVTablePtr { value }
             | InvalidBool { value }
             | InvalidChar { value }
@@ -758,15 +780,12 @@ impl<'tcx> ReportErrorExt for ValidationErrorInfo<'tcx> {
             | NullFnPtr
             | NeverVal
             | UnsafeCell
-            | UninitEnumTag
-            | UninitStr
-            | Uninit { .. }
-            | UninitVal
             | InvalidMetaSliceTooLarge { .. }
             | InvalidMetaTooLarge { .. }
             | DanglingPtrUseAfterFree { .. }
             | DanglingPtrOutOfBounds { .. }
-            | UninhabitedEnumTag => {}
+            | UninhabitedEnumVariant
+            | PartialPointer => {}
         }
     }
 }
@@ -776,9 +795,9 @@ impl ReportErrorExt for UnsupportedOpInfo {
         use crate::fluent_generated::*;
         match self {
             UnsupportedOpInfo::Unsupported(s) => s.clone().into(),
-            UnsupportedOpInfo::PartialPointerOverwrite(_) => const_eval_partial_pointer_overwrite,
-            UnsupportedOpInfo::PartialPointerCopy(_) => const_eval_partial_pointer_copy,
-            UnsupportedOpInfo::ReadPointerAsBytes => const_eval_read_pointer_as_bytes,
+            UnsupportedOpInfo::OverwritePartialPointer(_) => const_eval_partial_pointer_overwrite,
+            UnsupportedOpInfo::ReadPartialPointer(_) => const_eval_partial_pointer_copy,
+            UnsupportedOpInfo::ReadPointerAsInt(_) => const_eval_read_pointer_as_int,
             UnsupportedOpInfo::ThreadLocalStatic(_) => const_eval_thread_local_static,
             UnsupportedOpInfo::ReadExternStatic(_) => const_eval_read_extern_static,
         }
@@ -787,13 +806,16 @@ impl ReportErrorExt for UnsupportedOpInfo {
         use crate::fluent_generated::*;
 
         use UnsupportedOpInfo::*;
-        if let ReadPointerAsBytes | PartialPointerOverwrite(_) | PartialPointerCopy(_) = self {
+        if let ReadPointerAsInt(_) | OverwritePartialPointer(_) | ReadPartialPointer(_) = self {
             builder.help(const_eval_ptr_as_bytes_1);
             builder.help(const_eval_ptr_as_bytes_2);
         }
         match self {
-            Unsupported(_) | ReadPointerAsBytes => {}
-            PartialPointerOverwrite(ptr) | PartialPointerCopy(ptr) => {
+            // `ReadPointerAsInt(Some(info))` is never printed anyway, it only serves as an error to
+            // be further processed by validity checking which then turns it into something nice to
+            // print. So it's not worth the effort of having diagnostics that can print the `info`.
+            Unsupported(_) | ReadPointerAsInt(_) => {}
+            OverwritePartialPointer(ptr) | ReadPartialPointer(ptr) => {
                 builder.set_arg("ptr", ptr);
             }
             ThreadLocalStatic(did) | ReadExternStatic(did) => {
diff --git a/compiler/rustc_const_eval/src/interpret/validity.rs b/compiler/rustc_const_eval/src/interpret/validity.rs
index ff22d3d2d5a..d3f05af1c72 100644
--- a/compiler/rustc_const_eval/src/interpret/validity.rs
+++ b/compiler/rustc_const_eval/src/interpret/validity.rs
@@ -25,13 +25,17 @@ use rustc_target::abi::{
 
 use std::hash::Hash;
 
-// for the validation errors
-use super::UndefinedBehaviorInfo::*;
 use super::{
     AllocId, CheckInAllocMsg, GlobalAlloc, ImmTy, Immediate, InterpCx, InterpResult, MPlaceTy,
     Machine, MemPlaceMeta, OpTy, Pointer, Projectable, Scalar, ValueVisitor,
 };
 
+// for the validation errors
+use super::InterpError::UndefinedBehavior as Ub;
+use super::InterpError::Unsupported as Unsup;
+use super::UndefinedBehaviorInfo::*;
+use super::UnsupportedOpInfo::*;
+
 macro_rules! throw_validation_failure {
     ($where:expr, $kind: expr) => {{
         let where_ = &$where;
@@ -43,7 +47,7 @@ macro_rules! throw_validation_failure {
             None
         };
 
-        throw_ub!(Validation(ValidationErrorInfo { path, kind: $kind }))
+        throw_ub!(ValidationError(ValidationErrorInfo { path, kind: $kind }))
     }};
 }
 
@@ -85,16 +89,16 @@ macro_rules! try_validation {
             Ok(x) => x,
             // We catch the error and turn it into a validation failure. We are okay with
             // allocation here as this can only slow down builds that fail anyway.
-            Err(e) => match e.into_parts() {
+            Err(e) => match e.kind() {
                 $(
-                    (InterpError::UndefinedBehavior($($p)|+), _) =>
+                    $($p)|+ =>
                        throw_validation_failure!(
                             $where,
                             $kind
                         )
                 ),+,
                 #[allow(unreachable_patterns)]
-                (e, rest) => Err::<!, _>($crate::interpret::InterpErrorInfo::from_parts(e, rest))?,
+                _ => Err::<!, _>(e)?,
             }
         }
     }};
@@ -294,7 +298,13 @@ impl<'rt, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> ValidityVisitor<'rt, 'mir, '
         Ok(try_validation!(
             self.ecx.read_immediate(op),
             self.path,
-            InvalidUninitBytes(None) => Uninit { expected }
+            Ub(InvalidUninitBytes(None)) =>
+                Uninit { expected },
+            // The `Unsup` cases can only occur during CTFE
+            Unsup(ReadPointerAsInt(_)) =>
+                PointerAsInt { expected },
+            Unsup(ReadPartialPointer(_)) =>
+                PartialPointer,
         ))
     }
 
@@ -319,8 +329,8 @@ impl<'rt, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> ValidityVisitor<'rt, 'mir, '
                 let (_ty, _trait) = try_validation!(
                     self.ecx.get_ptr_vtable(vtable),
                     self.path,
-                    DanglingIntPointer(..) |
-                    InvalidVTablePointer(..) => InvalidVTablePtr { value: format!("{vtable}") }
+                    Ub(DanglingIntPointer(..) | InvalidVTablePointer(..)) =>
+                        InvalidVTablePtr { value: format!("{vtable}") }
                 );
                 // FIXME: check if the type/trait match what ty::Dynamic says?
             }
@@ -356,7 +366,7 @@ impl<'rt, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> ValidityVisitor<'rt, 'mir, '
         let size_and_align = try_validation!(
             self.ecx.size_and_align_of_mplace(&place),
             self.path,
-            InvalidMeta(msg) => match msg {
+            Ub(InvalidMeta(msg)) => match msg {
                 InvalidMetaKind::SliceTooBig => InvalidMetaSliceTooLarge { ptr_kind },
                 InvalidMetaKind::TooBig => InvalidMetaTooLarge { ptr_kind },
             }
@@ -375,23 +385,23 @@ impl<'rt, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> ValidityVisitor<'rt, 'mir, '
                 CheckInAllocMsg::InboundsTest, // will anyway be replaced by validity message
             ),
             self.path,
-            AlignmentCheckFailed { required, has } => UnalignedPtr {
+            Ub(AlignmentCheckFailed { required, has }) => UnalignedPtr {
                 ptr_kind,
                 required_bytes: required.bytes(),
                 found_bytes: has.bytes()
             },
-            DanglingIntPointer(0, _) => NullPtr { ptr_kind },
-            DanglingIntPointer(i, _) => DanglingPtrNoProvenance {
+            Ub(DanglingIntPointer(0, _)) => NullPtr { ptr_kind },
+            Ub(DanglingIntPointer(i, _)) => DanglingPtrNoProvenance {
                 ptr_kind,
                 // FIXME this says "null pointer" when null but we need translate
-                pointer: format!("{}", Pointer::<Option<AllocId>>::from_addr_invalid(i))
+                pointer: format!("{}", Pointer::<Option<AllocId>>::from_addr_invalid(*i))
             },
-            PointerOutOfBounds { .. } => DanglingPtrOutOfBounds {
+            Ub(PointerOutOfBounds { .. }) => DanglingPtrOutOfBounds {
                 ptr_kind
             },
             // This cannot happen during const-eval (because interning already detects
             // dangling pointers), but it can happen in Miri.
-            PointerUseAfterFree(..) => DanglingPtrUseAfterFree {
+            Ub(PointerUseAfterFree(..)) => DanglingPtrUseAfterFree {
                 ptr_kind,
             },
         );
@@ -477,7 +487,7 @@ impl<'rt, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> ValidityVisitor<'rt, 'mir, '
                 try_validation!(
                     value.to_bool(),
                     self.path,
-                    InvalidBool(..) => ValidationErrorKind::InvalidBool {
+                    Ub(InvalidBool(..)) => ValidationErrorKind::InvalidBool {
                         value: format!("{value:x}"),
                     }
                 );
@@ -488,7 +498,7 @@ impl<'rt, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> ValidityVisitor<'rt, 'mir, '
                 try_validation!(
                     value.to_char(),
                     self.path,
-                    InvalidChar(..) => ValidationErrorKind::InvalidChar {
+                    Ub(InvalidChar(..)) => ValidationErrorKind::InvalidChar {
                         value: format!("{value:x}"),
                     }
                 );
@@ -497,7 +507,7 @@ impl<'rt, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> ValidityVisitor<'rt, 'mir, '
             ty::Float(_) | ty::Int(_) | ty::Uint(_) => {
                 // NOTE: Keep this in sync with the array optimization for int/float
                 // types below!
-                let value = self.read_scalar(
+                self.read_scalar(
                     value,
                     if matches!(ty.kind(), ty::Float(..)) {
                         ExpectedKind::Float
@@ -505,14 +515,6 @@ impl<'rt, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> ValidityVisitor<'rt, 'mir, '
                         ExpectedKind::Int
                     },
                 )?;
-                // As a special exception we *do* match on a `Scalar` here, since we truly want
-                // to know its underlying representation (and *not* cast it to an integer).
-                if matches!(value, Scalar::Ptr(..)) {
-                    throw_validation_failure!(
-                        self.path,
-                        ExpectedNonPtr { value: format!("{value:x}") }
-                    )
-                }
                 Ok(true)
             }
             ty::RawPtr(..) => {
@@ -546,10 +548,8 @@ impl<'rt, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> ValidityVisitor<'rt, 'mir, '
                     let _fn = try_validation!(
                         self.ecx.get_ptr_fn(ptr),
                         self.path,
-                        DanglingIntPointer(..) |
-                        InvalidFunctionPointer(..) => InvalidFnPtr {
-                            value: format!("{ptr}"),
-                        },
+                        Ub(DanglingIntPointer(..) | InvalidFunctionPointer(..)) =>
+                            InvalidFnPtr { value: format!("{ptr}") },
                     );
                     // FIXME: Check if the signature matches
                 } else {
@@ -657,11 +657,12 @@ impl<'rt, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> ValueVisitor<'mir, 'tcx, M>
             Ok(try_validation!(
                 this.ecx.read_discriminant(op),
                 this.path,
-                InvalidTag(val) => InvalidEnumTag {
+                Ub(InvalidTag(val)) => InvalidEnumTag {
                     value: format!("{val:x}"),
                 },
-                UninhabitedEnumVariantRead(_) => UninhabitedEnumTag,
-                InvalidUninitBytes(None) => UninitEnumTag,
+                Ub(UninhabitedEnumVariantRead(_)) => UninhabitedEnumVariant,
+                // Uninit / bad provenance are not possible since the field was already previously
+                // checked at its integer type.
             ))
         })
     }
@@ -740,7 +741,8 @@ impl<'rt, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> ValueVisitor<'mir, 'tcx, M>
                 try_validation!(
                     self.ecx.read_bytes_ptr_strip_provenance(mplace.ptr, Size::from_bytes(len)),
                     self.path,
-                    InvalidUninitBytes(..) => { UninitStr },
+                    Ub(InvalidUninitBytes(..)) => Uninit { expected: ExpectedKind::Str },
+                    Unsup(ReadPointerAsInt(_)) => PointerAsInt { expected: ExpectedKind::Str }
                 );
             }
             ty::Array(tys, ..) | ty::Slice(tys)
@@ -752,6 +754,7 @@ impl<'rt, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> ValueVisitor<'mir, 'tcx, M>
                 if matches!(tys.kind(), ty::Int(..) | ty::Uint(..) | ty::Float(..))
                 =>
             {
+                let expected = if tys.is_integral() { ExpectedKind::Int } else { ExpectedKind::Float };
                 // Optimized handling for arrays of integer/float type.
 
                 // This is the length of the array/slice.
@@ -770,7 +773,7 @@ impl<'rt, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> ValueVisitor<'mir, 'tcx, M>
                     Left(mplace) => mplace,
                     Right(imm) => match *imm {
                         Immediate::Uninit =>
-                            throw_validation_failure!(self.path, UninitVal),
+                            throw_validation_failure!(self.path, Uninit { expected }),
                         Immediate::Scalar(..) | Immediate::ScalarPair(..) =>
                             bug!("arrays/slices can never have Scalar/ScalarPair layout"),
                     }
@@ -796,17 +799,21 @@ impl<'rt, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> ValueVisitor<'mir, 'tcx, M>
                         // For some errors we might be able to provide extra information.
                         // (This custom logic does not fit the `try_validation!` macro.)
                         match err.kind() {
-                            err_ub!(InvalidUninitBytes(Some((_alloc_id, access)))) => {
+                            Ub(InvalidUninitBytes(Some((_alloc_id, access)))) | Unsup(ReadPointerAsInt(Some((_alloc_id, access)))) => {
                                 // Some byte was uninitialized, determine which
                                 // element that byte belongs to so we can
                                 // provide an index.
                                 let i = usize::try_from(
-                                    access.uninit.start.bytes() / layout.size.bytes(),
+                                    access.bad.start.bytes() / layout.size.bytes(),
                                 )
                                 .unwrap();
                                 self.path.push(PathElem::ArrayElem(i));
 
-                                throw_validation_failure!(self.path, UninitVal)
+                                if matches!(err.kind(), Ub(InvalidUninitBytes(_))) {
+                                    throw_validation_failure!(self.path, Uninit { expected })
+                                } else {
+                                    throw_validation_failure!(self.path, PointerAsInt { expected })
+                                }
                             }
 
                             // Propagate upwards (that will also check for unexpected errors).
@@ -892,17 +899,22 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
         // Run it.
         match visitor.visit_value(&op) {
             Ok(()) => Ok(()),
-            // Pass through validation failures.
-            Err(err) if matches!(err.kind(), err_ub!(Validation { .. })) => Err(err),
-            // Complain about any other kind of UB error -- those are bad because we'd like to
+            // Pass through validation failures and "invalid program" issues.
+            Err(err)
+                if matches!(
+                    err.kind(),
+                    err_ub!(ValidationError { .. }) | InterpError::InvalidProgram(_)
+                ) =>
+            {
+                Err(err)
+            }
+            // Complain about any other kind of error -- those are bad because we'd like to
             // report them in a way that shows *where* in the value the issue lies.
-            Err(err) if matches!(err.kind(), InterpError::UndefinedBehavior(_)) => {
+            Err(err) => {
                 let (err, backtrace) = err.into_parts();
                 backtrace.print_backtrace();
                 bug!("Unexpected Undefined Behavior error during validation: {err:?}");
             }
-            // Pass through everything else.
-            Err(err) => Err(err),
         }
     }