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 a

View on GitHub (pinned to 22057b88b0)

Solutions

  1. 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).
  2. 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`.
  3. 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).
  4. 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

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


AI-assisted analysis of rust-lang/rust@22057b88b0 (2026-08-03). Data as JSON: /data/errors/6fb8f787f60999fe.json. Report an issue: GitHub.