rust-lang/rust · critical
Invalid scalar type {val:?}
Error message
Invalid scalar type {val:?} What it means
Inside the same `debug_assert!` block in `Operand::const_from_scalar`, the code matches on `val: Scalar` and panics if it is anything other than `Scalar::Int`. rustc_middle enforces this because `const_from_scalar` is meant to synthesize integer-like literal constants; passing a `Scalar::Ptr` (an allocation pointer) is a misuse of the API and would produce an invalid constant operand.
Source
Thrown at compiler/rustc_middle/src/mir/statement.rs:670
}
/// Convenience helper to make a literal-like constant from a given scalar value.
/// Since this is used to synthesize MIR, assumes `user_ty` is None.
pub fn const_from_scalar(
tcx: TyCtxt<'tcx>,
ty: Ty<'tcx>,
val: Scalar,
span: Span,
) -> Operand<'tcx> {
debug_assert!({
let typing_env = ty::TypingEnv::fully_monomorphized();
let type_size = tcx
.layout_of(typing_env.as_query_input(ty))
.unwrap_or_else(|e| panic!("could not compute layout for {ty:?}: {e:?}"))
.size;
let scalar_size = match val {
Scalar::Int(int) => int.size(),
_ => panic!("Invalid scalar type {val:?}"),
};
scalar_size == type_size
});
Operand::Constant(Box::new(ConstOperand {
span,
user_ty: None,
const_: Const::Val(ConstValue::Scalar(val), ty),
}))
}
pub fn to_copy(&self) -> Self {
match *self {
Operand::Copy(_) | Operand::Constant(_) | Operand::RuntimeChecks(_) => self.clone(),
Operand::Move(place) => Operand::Copy(place),
}
}
/// Returns the `Place` that is the target of this `Operand`, or `None` if this `Operand` is aView on GitHub (pinned to 22057b88b0)
Solutions
- Pass only `Scalar::Int(...)` to `const_from_scalar`; for pointer constants use the allocation-based constant API (e.g. `ConstValue::ByRef`/`Slice` via the proper constructor).
- If your scalar originated from a pointer read, materialize an allocation and build the constant operand from that allocation instead of the raw `Scalar::Ptr`.
- Verify in release rustc that the surrounding code is not silently producing ill-formed MIR (the debug assert exists precisely because release builds would hide this).
- File an ICE if a stock rustc path passes a pointer scalar here — include the call site and the offending `Scalar` value.
Example fix
// before
let op = Operand::const_from_scalar(tcx, ty, Scalar::Ptr(ptr, sz), span);
// debug rustc panic: Invalid scalar type Ptr(...)
// after: build a pointer-typed constant from the allocation
let const_ = Const::Val(
ConstValue::Scalar(Scalar::Ptr(ptr, sz)), // built via the alloc API
ty,
);
let op = Operand::Constant(Box::new(ConstOperand { span, user_ty: None, const_ })); Defensive patterns
Strategy: type-guard
Validate before calling
// const_from_scalar() additionally requires the Scalar to be a Scalar::Int
// (it then reads .size() to compare against the type's layout size).
// Validate the variant before calling.
use rustc_middle::mir::interpret::Scalar;
fn is_int_scalar(val: &Scalar) -> bool {
matches!(val, Scalar::Int(_))
}
// Usage:
// if is_int_scalar(&scalar) {
// Operand::const_from_scalar(tcx, ty, scalar, span)
// } else {
// // Scalar::Ptr (pointer/alloc) cannot become a plain int constant here;
// // build the Operand via ConstValue::Scalar + Const::Val instead.
// } Type guard
// Narrow a Scalar to its integer form, extracting the size in one step.
use rustc_middle::mir::interpret::{Scalar, ScalarInt};
fn as_scalar_int(val: &Scalar) -> Option<ScalarInt> {
match val {
Scalar::Int(int) => Some(*int),
_ => None, // Scalar::Ptr -> not valid for const_from_scalar
}
} Prevention
- `const_from_scalar` only accepts `Scalar::Int`; a `Scalar::Ptr` (an allocation-backed pointer) is not a plain integer and must be wrapped through `ConstValue::Scalar` + `Const::Val`.
- When you deserialize or transmute raw bytes into a Scalar, explicitly construct `Scalar::Int(ScalarInt::try_from_raw(...))` rather than relying on a `From` impl that could yield a Ptr.
- Pair this guard with the layout guard from [258]: a Scalar::Int whose `.size()` differs from the type's layout size is the other half of the same debug_assert — verify both.
- Keep pointer-valued constants (static addresses, fn pointers, allocations) on the `ConstValue::Slice`/`ByRef`/`Scalar(Scalar::Ptr)` paths; never route them through `const_from_scalar`.
When it happens
Trigger: Triggered in a debug rustc build when a caller passes `Scalar::Ptr(ptr, ..)` (a pointer into an allocation) instead of `Scalar::Int(int)` to `Operand::const_from_scalar`. Reproducible by a codegen/mir-opt path that reuses a pointer scalar where an integer literal scalar is required.
Common situations: Out-of-tree backend or mir-opt that treats any `Scalar` uniformly; refactoring that changed an integer constant into a reference/pointer constant without switching the constructor; debug-toolchain build hitting an assertion that release builds would silently skip.
Related errors
- got a pointer where a ScalarInt was expected
- could not compute layout for {ty:?}: {e:?}
- range should be nonempty
- there must be provenance somewhere here
- an interpreter error got improperly discarded; use `discard_
AI-assisted analysis of rust-lang/rust@22057b88b0 (2026-08-03).
Data as JSON: /data/errors/6fb8f787f60999fe.json.
Report an issue: GitHub.