{"id":"8d9b9526c44c9641","repo":"rust-lang/rust","slug":"cannot-create-a-zero-sized-constant-for-type-ty-8d9b95","errorCode":null,"errorMessage":"Cannot create a zero-sized constant for type `{ty_internal}`: Type `{ty_internal}` has {} bytes","messagePattern":"Cannot create a zero-sized constant for type `(.+?)`: Type `(.+?)` has (.+?) bytes","errorType":"exception","errorClass":"B::Error","httpStatus":null,"severity":"error","filePath":"compiler/rustc_public_bridge/src/context/impls.rs","lineNumber":470,"sourceCode":"    }\n\n    pub fn eval_target_usize_ty(&self, cnst: ty::Const<'tcx>) -> Result<u64, B::Error> {\n        cnst.try_to_target_usize(self.tcx)\n            .ok_or_else(|| B::Error::new(format!(\"Const `{cnst:?}` cannot be encoded as u64\")))\n    }\n\n    pub fn try_new_const_zst(&self, ty_internal: Ty<'tcx>) -> Result<MirConst<'tcx>, B::Error> {\n        let size = self\n            .tcx\n            .layout_of(self.fully_monomorphized().as_query_input(ty_internal))\n            .map_err(|err| {\n                B::Error::new(format!(\n                    \"Cannot create a zero-sized constant for type `{ty_internal}`: {err}\"\n                ))\n            })?\n            .size;\n        if size.bytes() != 0 {\n            return Err(B::Error::new(format!(\n                \"Cannot create a zero-sized constant for type `{ty_internal}`: \\\n                Type `{ty_internal}` has {} bytes\",\n                size.bytes()\n            )));\n        }\n\n        Ok(MirConst::Ty(ty_internal, self.const_zero_sized(ty_internal)))\n    }\n\n    pub fn const_zero_sized(&self, ty_internal: Ty<'tcx>) -> ty::Const<'tcx> {\n        ty::Const::zero_sized(self.tcx, ty_internal)\n    }\n\n    /// Create a caller location constant from a span.\n    ///\n    /// This produces a `&'static core::panic::Location<'static>` constant,\n    /// which is the implicit extra argument for `#[track_caller]` functions.\n    pub fn span_as_caller_location(&self, span: Span) -> MirConst<'tcx> {","sourceCodeStart":452,"sourceCodeEnd":488,"githubUrl":"https://github.com/rust-lang/rust/blob/22057b88b091743bc0fd8d592a9264f0a6951403/compiler/rustc_public_bridge/src/context/impls.rs#L452-L488","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","solutions":["Verify the type is genuinely zero-sized before calling `try_new_const_zst` (check `layout_of(...).size.bytes() == 0`).","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`.","Pass the correct unit type (`Ty::new_unit`) if a ZST value is what you actually need."],"exampleFix":"// before\nlet c = cx.try_new_const_zst(ty)?;  // ty is e.g. struct Foo(u32)\n// after\nlet c = if cx.tcx.layout_of(cx.fully_monomorphized().as_query_input(ty)).unwrap().size.bytes() == 0 {\n    cx.try_new_const_zst(ty)?\n} else {\n    cx.mir_const_from_scalar(Scalar::Int(scalar), ty) // build a real value\n};","handlingStrategy":"type-guard","validationCode":"// Before MirConst::try_new_zero_sized(ty):\nlet layout = ty.layout()?;\nlet size = layout.shape().size; // rustc_public::target::MachineSize\nif size.bytes() != 0 {\n    return Err(format!(\n        \"type {:?} is {} bytes, not a ZST\",\n        ty, size.bytes()\n    ));\n}\nlet zst = MirConst::try_new_zero_sized(ty)?;","typeGuard":"// True only for zero-sized (ZST) types that have a computable layout.\nfn is_zst(ty: &Ty) -> bool {\n    ty.layout()\n        .map(|l| !l.shape().is_unsized() && l.shape().size.bytes() == 0)\n        .unwrap_or(false)\n}","tryCatchPattern":"match MirConst::try_new_zero_sized(ty) {\n    Ok(c) => c,\n    Err(e) if e.to_string().contains(\"bytes\") => {\n        // Type is sized but non-ZST. Use the typed value constructor\n        // (e.g. MirConst::try_from_uint) instead of the ZST shortcut.\n        return typed_default(ty);\n    }\n    Err(e) => return Err(e.into()),\n}","preventionTips":["Check `layout.shape().size.bytes() == 0` (and `!is_unsized()`) before constructing a ZST constant; `try_new_zero_sized` rejects any non-zero size.","Common ZSTs: unit `()`, `PhantomData`, empty enums/structs, `Option<&T>::None`-shaped values — but always verify via layout rather than assuming from the source spelling.","Do not confuse `ZSTValue` (a TyConstKind variant) with this constructor; the constructor enforces the size invariant at construction time."],"tags":["rust","const","zst","layout"],"analyzedSha":"22057b88b091743bc0fd8d592a9264f0a6951403","analyzedAt":"2026-08-03T08:09:25.915Z","schemaVersion":2}