Open
Labels
A-layoutArea: Memory layout of typesArea: Memory layout of typesA-raw-pointersArea: raw pointers, MaybeUninit, NonNullArea: raw pointers, MaybeUninit, NonNullC-optimizationCategory: An issue highlighting optimization opportunities or PRs implementing suchCategory: An issue highlighting optimization opportunities or PRs implementing suchT-compilerRelevant to the compiler team, which will review and decide on the PR/issue.Relevant to the compiler team, which will review and decide on the PR/issue.T-opsemRelevant to the opsem teamRelevant to the opsem teamneeds-triageThis issue may need triage. Remove when done. See docs forge.rust-lang.org/release/issue-triagingThis issue may need triage. Remove when done. See docs forge.rust-lang.org/release/issue-triaging
Description
I tried this code:
#![feature(layout_for_ptr)]
use std::mem::size_of_val_raw;
#[unsafe(no_mangle)]
pub fn a(x: *const [u8]) -> bool {
unsafe { size_of_val_raw(x) <= isize::MAX.cast_unsigned() }
}
#[unsafe(no_mangle)]
pub fn b(x: *const [u16]) -> bool {
unsafe { size_of_val_raw(x) <= isize::MAX.cast_unsigned() }
}I expected both functions to optimize to returning true, since the documentation for size_of_val_raw states that, for the operation to not be UB, the size of the slice must be at most isize::MAX.
Instead, only the b function optimizes to returning true.
a:
test rsi, rsi
setns al
ret
b:
mov al, 1
retMeta
Reproducible on godbolt with version info:
rustc 1.99.0-nightly (0e29c21d9 2026-07-21)
binary: rustc
commit-hash: 0e29c21d93abc9bdc330182be1fbd33cfd5fee68
commit-date: 2026-07-21
host: x86_64-unknown-linux-gnu
release: 1.99.0-nightly
LLVM version: 22.1.8
Internal compiler ID: nightly
Metadata
Metadata
Assignees
Labels
A-layoutArea: Memory layout of typesArea: Memory layout of typesA-raw-pointersArea: raw pointers, MaybeUninit, NonNullArea: raw pointers, MaybeUninit, NonNullC-optimizationCategory: An issue highlighting optimization opportunities or PRs implementing suchCategory: An issue highlighting optimization opportunities or PRs implementing suchT-compilerRelevant to the compiler team, which will review and decide on the PR/issue.Relevant to the compiler team, which will review and decide on the PR/issue.T-opsemRelevant to the opsem teamRelevant to the opsem teamneeds-triageThis issue may need triage. Remove when done. See docs forge.rust-lang.org/release/issue-triagingThis issue may need triage. Remove when done. See docs forge.rust-lang.org/release/issue-triaging
Activity
hanna-kruppe commentedon Jul 23, 2026
This is probably because rustc encodes the size-in-bytes restriction by making the
len * size_of::<T>()multiplynuw nswand that doesn’t imply anything whensize_of::<T>() == 1.hanna-kruppe commentedon Jul 23, 2026
I guess we could fix this by special casing 1-byte-sized element types to emit
assume(len <= isize::MAX). The same special case could avoid emitting the unnecessary multiply to sweeten the deal. But I’m not sure it’s worth it (assumes have downsides/costs, so it’s better to have evidence of real world impact before adding them).asquared31415 commentedon Jul 23, 2026
@rustbot claim
hanna-kruppe commentedon Jul 26, 2026
@theemathas Is this minimized from some less trivial code where lack of range information caused missed optimizations? If yes, could you share it?
theemathas commentedon Jul 26, 2026
I was just playing around with some code after reading the safety requirements of
size_of_val_raw😅asquared31415 commentedon Jul 27, 2026
Update from #159921: we're not seeing any significant optimization improvements when providing the necessary information to LLVM via
assumein the case of*const [u8](and similar). LLVM does become able to optimize the example cases in the original issue report, but we overall see some compile time regressions, presumably because of the additional IR for LLVM to manipulate. It may be possible to mitigate the regressions by introducing a second intrinsic forsize_of_val_rawto call specifically, but it would likely need to come with more convincing optimization improvements to justify the complexity.@rustbot release-assignment
scottmcm commentedon Jul 28, 2026
This is one of those places where I wish we has a
mem::Sizeto return, like we havemem::Alignment. Then the assertion -- and range metadata -- could be carried by that type in the return value.For LLVM, though, the other thing that would be nice is if we could have range assume operand bundles, which would be less impactful than needing the
icmp. Last I checked those don't work, though.