rust-lang / rust-lang/rust

`size_of_val(p) == 0` doesn't optimize out for clearly-not-ZST values

Open
#152,788 5 comments 0 reactions 1 assignee View on GitHub

@TKanX is already working on this.

Since Feb 19, 2026.

A-codegen A-LLVM C-optimization T-compiler
Dominant language
Rust
Stars
119k
Forks
16.2k
PR merge metrics
PR metrics pending

Description

The following rust

pub struct Foo<T: ?Sized>(pub [u32; 3], pub T);

#[unsafe(no_mangle)]
pub fn demo(p: &Foo<dyn std::fmt::Debug>) -> bool {
    std::mem::size_of_val(p) == 0
}

currently https://rust.godbolt.org/z/r1d5n6Phe optimizes to

define noundef zeroext i1 @demo(ptr noundef nonnull readnone align 4 captures(none) %p.0, ptr noalias noundef readonly align 8 captures(none) dereferenceable(32) %p.1) unnamed_addr #0 {
start:
  %0 = getelementptr inbounds nuw i8, ptr %p.1, i64 8
  %1 = load i64, ptr %0, align 8, !range !3, !invariant.load !4
  %2 = getelementptr inbounds nuw i8, ptr %p.1, i64 16
  %3 = load i64, ptr %2, align 8, !range !5, !invariant.load !4
  %4 = tail call i64 @llvm.umax.i64(i64 %3, i64 4)
  %5 = add nuw i64 %1, 11
  %6 = add i64 %5, %4
  %7 = sub i64 0, %4
  %8 = and i64 %6, %7
  %_0 = icmp eq i64 %8, 0
  ret i1 %_0
}

but clearly that type has to be at least 12 bytes no matter what.

Why does that matter? Well, whenever you drop a Box it needs to check for ZSTs before calling the allocator. So that check should optimize out in these cases, but it doesn't today.

Filed here because we're probably not telling LLVM enough to be able to do that itself. #152786 will give it a bit more information, but probably not enough to solve this.


For some DSTs it does optimize, notably

pub fn demo_simpleslice(p: &Foo<[i32]>) -> bool {
    std::mem::size_of_val(p) == 0
}

optimizes to false.

However, this one

pub fn demo_lessalignedslice(p: &Foo<[u8]>) -> bool {
    std::mem::size_of_val(p) == 0
}

doesn't today https://rust.godbolt.org/z/nnhGKz767

define noundef zeroext i1 @demo_lessalignedslice(ptr noalias noundef readonly align 4 captures(none) dereferenceable(12) %p.0, i64 noundef %p.1) unnamed_addr #0 {
start:
  %0 = add i64 %p.1, 15
  %_0 = icmp ult i64 %0, 4
  ret i1 %_0
}

(That last one might get fixed with #152786, though, because the icmp can only be true if it wraps, which definitely can't happen.)

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.