remove scalar size mismatch interpreter error, make it an ICE instead
Project: rust-lang/rust | Language: Rust | Concepts: error-handling, compiler-internals | Difficulty: senior
Link: https://github.com/rust-lang/rust/pull/161238
The problem
The Rust compiler's interpreter (used for constant evaluation and Miri) had an error variant for "scalar size mismatch"—a case where a scalar value's size didn't match its expected layout. This error was only a partial fix for earlier internal compiler errors (ICEs) related to Miri shims, but it didn't handle all cases. The codebase was left with a special error for this scenario, even though the proper fix is being tracked elsewhere and the check was incomplete.
Why it's non-trivial
A naive fix would simply remove the error, but this could hide real bugs or result in confusing panics. The challenge is to ensure that such mismatches are still caught—preferably as ICEs (which are always bugs in the compiler), not as user-facing errors—while removing the now-redundant, incomplete error-handling code. Care must be taken to update all code paths that previously returned or handled this error.
The approach
Remove the ScalarSizeMismatch error and related code
Delete the error variant and its plumbing:
-/// Information about a size mismatch.
-#[derive(Debug)]
-pub struct ScalarSizeMismatch {
- pub target_size: u64,
- pub data_size: u64,
-}
This removes the ScalarSizeMismatch struct, which represented the error.
-pub enum AllocError {
- /// A scalar had the wrong size.
- ScalarSizeMismatch(ScalarSizeMismatch),
...
-}
The AllocError enum no longer includes the ScalarSizeMismatch variant.
-impl From<ScalarSizeMismatch> for AllocError {
- fn from(s: ScalarSizeMismatch) -> Self {
- AllocError::ScalarSizeMismatch(s)
- }
-}
The conversion from ScalarSizeMismatch to AllocError is deleted.
- ScalarSizeMismatch(s) => {
- InterpErrorKind::UndefinedBehavior(UndefinedBehaviorInfo::ScalarSizeMismatch(s))
- }
The mapping from AllocError::ScalarSizeMismatch to an interpreter error is removed.
Replace error with assertion (ICE on bug)
In ImmTy::to_scalar_int, replace the error with an assertion:
- if s.size() != self.layout.size {
- throw_ub!(ScalarSizeMismatch(ScalarSizeMismatch {
- target_size: self.layout.size.bytes(),
- data_size: s.size().bytes(),
- }));
- }
+ assert_eq!(s.size(), self.layout.size, "scalar immediate size does not match layout");
Now, if a scalar's size mismatches its layout, the compiler will panic (ICE), making it clear that this is a bug.
Remove unneeded error handling at call sites
Change all .to_pointer(self)? to .to_pointer(self) where the error is no longer possible or meaningful:
Example:
- let vptr = receiver_place.meta().unwrap_meta().to_pointer(self)?;
+ let vptr = receiver_place.meta().unwrap_meta().to_pointer(self);
This pattern is repeated across many files, as to_pointer is no longer fallible in the same way.
Update memory writing to not expect an error:
- let (bytes, provenance) = match val.to_bits_or_ptr_internal(range.size)? {
+ let (bytes, provenance) = match val.to_bits_or_ptr_internal(range.size) {
No error is expected from a size mismatch anymore.
From the review thread
No notable review discussion on this PR.
Takeaways
- Remove partial or incomplete error handling when the proper solution is to treat such cases as internal bugs (ICEs), not user-facing errors.
- Use assertions to catch invariants that should never be violated in correct code, surfacing them as ICEs for maintainers.
- When removing an error variant, ensure all code paths and conversions that referenced it are updated or deleted, to avoid dead code and confusion.