rust-lang/rust · error · B::Error

Cannot create a zero-sized constant for type `{ty_internal}`

Error message

Cannot create a zero-sized constant for type `{ty_internal}`: Type `{ty_internal}` has {} bytes

What it means

Thrown by `try_new_const_zst` in compiler/rustc_public_bridge/src/context/impls.rs:470 when the type's layout was computed successfully but its size is non-zero. The API's contract is to produce a zero-sized constant; a type with a positive byte size is, by definition, not a ZST, so the call is rejected. This catches mismatches between caller intent (build a unit value) and the actual type.

Source

Thrown at compiler/rustc_public_bridge/src/context/impls.rs:470

    }

    pub fn eval_target_usize_ty(&self, cnst: ty::Const<'tcx>) -> Result<u64, B::Error> {
        cnst.try_to_target_usize(self.tcx)
            .ok_or_else(|| B::Error::new(format!("Const `{cnst:?}` cannot be encoded as u64")))
    }

    pub fn try_new_const_zst(&self, ty_internal: Ty<'tcx>) -> Result<MirConst<'tcx>, B::Error> {
        let size = self
            .tcx
            .layout_of(self.fully_monomorphized().as_query_input(ty_internal))
            .map_err(|err| {
                B::Error::new(format!(
                    "Cannot create a zero-sized constant for type `{ty_internal}`: {err}"
                ))
            })?
            .size;
        if size.bytes() != 0 {
            return Err(B::Error::new(format!(
                "Cannot create a zero-sized constant for type `{ty_internal}`: \
                Type `{ty_internal}` has {} bytes",
                size.bytes()
            )));
        }

        Ok(MirConst::Ty(ty_internal, self.const_zero_sized(ty_internal)))
    }

    pub fn const_zero_sized(&self, ty_internal: Ty<'tcx>) -> ty::Const<'tcx> {
        ty::Const::zero_sized(self.tcx, ty_internal)
    }

    /// Create a caller location constant from a span.
    ///
    /// This produces a `&'static core::panic::Location<'static>` constant,
    /// which is the implicit extra argument for `#[track_caller]` functions.
    pub fn span_as_caller_location(&self, span: Span) -> MirConst<'tcx> {

View on GitHub (pinned to 22057b88b0)

Solutions

  1. Verify the type is genuinely zero-sized before calling `try_new_const_zst` (check `layout_of(...).size.bytes() == 0`).
  2. If you need a zero value for a non-ZST type, use the appropriate scalar/aggregate const-construction API rather than `try_new_const_zst`.
  3. Pass the correct unit type (`Ty::new_unit`) if a ZST value is what you actually need.

Example fix

// before
let c = cx.try_new_const_zst(ty)?;  // ty is e.g. struct Foo(u32)
// after
let c = if cx.tcx.layout_of(cx.fully_monomorphized().as_query_input(ty)).unwrap().size.bytes() == 0 {
    cx.try_new_const_zst(ty)?
} else {
    cx.mir_const_from_scalar(Scalar::Int(scalar), ty) // build a real value
};
Defensive patterns

Strategy: type-guard

Validate before calling

// Before MirConst::try_new_zero_sized(ty):
let layout = ty.layout()?;
let size = layout.shape().size; // rustc_public::target::MachineSize
if size.bytes() != 0 {
    return Err(format!(
        "type {:?} is {} bytes, not a ZST",
        ty, size.bytes()
    ));
}
let zst = MirConst::try_new_zero_sized(ty)?;

Type guard

// True only for zero-sized (ZST) types that have a computable layout.
fn is_zst(ty: &Ty) -> bool {
    ty.layout()
        .map(|l| !l.shape().is_unsized() && l.shape().size.bytes() == 0)
        .unwrap_or(false)
}

Try / catch

match MirConst::try_new_zero_sized(ty) {
    Ok(c) => c,
    Err(e) if e.to_string().contains("bytes") => {
        // Type is sized but non-ZST. Use the typed value constructor
        // (e.g. MirConst::try_from_uint) instead of the ZST shortcut.
        return typed_default(ty);
    }
    Err(e) => return Err(e.into()),
}

Prevention

When it happens

Trigger: Calling `context.try_new_const_zst(ty)` on a type like `struct Foo(u32)`, a non-unit struct, an enum with payload, or any type whose layout size is greater than zero.

Common situations: Assuming a type is a unit/ZST when it actually carries data (e.g. after a refactor added a field). Passing a `PhantomData`-free wrapper type where a ZST was expected. Confusing `()` with a single-field struct.

Related errors


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