Closed
Description
Expects the following function to always return true since it's undefined behaviour otherwise.
use std::ptr;
pub unsafe fn test(s: &Vec<&[i32]>, idx: usize) -> bool {
unsafe { Some(ptr::read(s.as_ptr().add(idx))).is_some() }
}
Actual result:
example::test:
mov rax, qword ptr [rdi + 8]
shl rsi, 4
cmp qword ptr [rax + rsi], 0
setne al
ret
Activity
[-]Compiler unable to assume slice is always not null[/-][+]`ptr::read` unable to assume slice is always not null[/+]AnsonYeung commentedon Jan 2, 2023
This is related to the function
ptr::read
, replacing it with deref produces the expected result.https://rust.godbolt.org/z/z3bKfac6s
saethlin commentedon Jan 2, 2023
This looks a lot like #93011 to me.
ptr::read
does acopy_nonoverlapping
into aMaybeUninit
, perhaps that wrapping also causes LLVM to lose thenonnull
.Noratrieb commentedon Jan 2, 2023
This can be minimized even further to just this
which on master emits (
rustc read.rs --crate-type=lib -Copt-level=3 --emit=asm
)This actually gets fixed by applying
which is weird, because this shouldn't change anything as
dereferenceable
impliesnonnull
(at least as far as I know and opts seem to rely on this).With this applied, I now get
which is good.
But, this still doesn't help with the original example in the issue, which is the same with and without the patch.
clubby789 commentedon Jan 2, 2023
If we add a
!nonnull
when the slice pointer is loaded then the codegen (-Copt-level=3 -Cdebuginfo=0 -Cno-prepopulate-passes
) for this case looks better (godbolt). The IR before the generated assume isn't removed, but it codegens to just amov al, 1; ret
clubby789 commentedon Jan 2, 2023
It looks like the problem isn't the CopyNonOverlapping - rather, when building the load, the layout of MaybeUninit (used in
ptr::read
) is used, (even though we're loading from anassume_init
), so we don't know of any niches. godboltAnsonYeung commentedon Jan 3, 2023
After some more digging it seems the issue is reported back in 2020 in #73258 . Seems like if it is imported internally to the crate, it can realize the optimization for reference but not slice
https://godbolt.org/z/MTWEbsvvc
ptr::read
gets all the same LLVMload
metadata that dereferencing does #109035scottmcm commentedon Mar 15, 2023
Test: https://github.com/rust-lang/rust/blob/master/tests/codegen/issues/issue-106369.rs