rust-lang/rust · critical

expected pointee to have a layout

Error message

expected pointee to have a layout

What it means

This fires in Cranelift codegen when processing the `CopyNonOverlapping` non-diverging intrinsic. The code extracts the pointee type from the destination raw pointer (`dst.layout().ty`) and calls `fx.tcx.layout_of(pointee).expect("expected pointee to have a layout")`. If the pointee type doesn't have a computable layout (e.g., it's unsized in an unsupported way, it's an extern type, or it's an error type from a prior compilation failure), `layout_of` returns `Err` and this panics.

Source

Thrown at compiler/rustc_codegen_cranelift/src/base.rs:953

        StatementKind::Coverage { .. } => unreachable!(),
        StatementKind::Intrinsic(intrinsic) => match &**intrinsic {
            // We ignore `assume` intrinsics, they are only useful for optimizations
            NonDivergingIntrinsic::Assume(_) => {}
            NonDivergingIntrinsic::CopyNonOverlapping(mir::CopyNonOverlapping {
                src,
                dst,
                count,
            }) => {
                let dst = codegen_operand(fx, dst);

                let &ty::RawPtr(pointee, _) = dst.layout().ty.kind() else {
                    bug!("expected pointer")
                };
                let pointee_layout = fx
                    .tcx
                    .layout_of(fx.typing_env().as_query_input(pointee))
                    .expect("expected pointee to have a layout");
                let elem_size: u64 = pointee_layout.layout.size().bytes();

                let dst = dst.load_scalar(fx);
                let src = codegen_operand(fx, src).load_scalar(fx);
                let count = codegen_operand(fx, count).load_scalar(fx);

                let bytes = if elem_size != 1 {
                    fx.bcx.ins().imul_imm_u(count, elem_size as i64)
                } else {
                    count
                };

                fx.bcx.call_memcpy(fx.target_config, dst, src, bytes);
            }
        },
    }
}

View on GitHub (pinned to 7088e4b63a)

Solutions

  1. Fix any preceding compilation errors first — a `ty::Error` leaking to codegen is often the root cause.
  2. Avoid `copy_nonoverlapping` with pointers to extern types or unsupported unsized types; use a concrete sized type instead.
  3. If the pointee is legitimately sized, file a bug — `layout_of` should succeed for all sized types at codegen time.
  4. Use the LLVM backend (`-Zcodegen-backend=llvm`) to check if this is cg_clif-specific.
  5. If contributing to cg_clif, handle `layout_of` errors with a proper diagnostic instead of panicking.

Example fix

// before (extern type pointee → no layout → panic)
extern "C" { type Opaque; }
unsafe fn copy(ptr: *const Opaque, dst: *mut Opaque) {
    std::ptr::copy_nonoverlapping(ptr, dst, 1);
}

// after (use a concrete sized type or byte buffer)
unsafe fn copy(ptr: *const u8, dst: *mut u8, len: usize) {
    std::ptr::copy_nonoverlapping(ptr, dst, len);
}
Defensive patterns

Strategy: validation

Validate before calling

// Before calling copy_nonoverlapping, ensure the pointee is sized
// and has a valid layout:
fn safe_copy_nonoverlapping<T: Sized>(src: *const T, dst: *mut T, count: usize) {
    // T: Sized guarantees layout_of succeeds
    unsafe { std::ptr::copy_nonoverlapping(src, dst, count); }
}
// Never call with pointers to extern types or ty::Error

Type guard

// Type guard: only allow copy_nonoverlapping on Sized types
fn is_sized_pointee<T: ?Sized>() -> bool {
    std::mem::size_of_val(&()) > 0 // placeholder
}
// Better: use a trait bound
trait SafeCopy: Sized {}
impl<T: Sized> SafeCopy for T {}
fn copy_safe<T: SafeCopy>(src: *const T, dst: *mut T, len: usize) {
    unsafe { std::ptr::copy_nonoverlapping(src, dst, len) }
}

Prevention

When it happens

Trigger: Calling `core::intrinsics::copy_nonoverlapping` (or code that desugars to the `CopyNonOverlapping` MIR intrinsic) with a raw pointer whose pointee type has no valid layout — extern types, `?Sized` types that aren't slices/str/trait objects, or types containing errors from failed compilation.

Common situations: Using raw pointers to extern types (`extern type`) or custom unsized types with `copy_nonoverlapping`. Also triggered when an earlier type-check error produces a type error (ty::Error) that propagates to codegen — the error type has no layout.

Related errors


AI-assisted analysis of rust-lang/rust@7088e4b63a (2026-08-10). Data as JSON: /api/errors/81dfdc95b2a56459. Report an issue: GitHub.