Auto merge of #109035 - scottmcm:ptr-read-should-know-undef, r=WaffleLapkin,JakobDegen
Ensure `ptr::read` gets all the same LLVM `load` metadata that dereferencing does I was looking into `array::IntoIter` optimization, and noticed that it wasn't annotating the loads with `noundef` for simple things like `array::IntoIter<i32, N>`. Trying to narrow it down, it seems that was because `MaybeUninit::assume_init_read` isn't marking the load as initialized (<https://rust.godbolt.org/z/Mxd8TPTnv>), which is unfortunate since that's basically its reason to exist. The root cause is that `ptr::read` is currently implemented via the *untyped* `copy_nonoverlapping`, and thus the `load` doesn't get any type-aware metadata: no `noundef`, no `!range`. This PR solves that by lowering `ptr::read(p)` to `copy *p` in MIR, for which the backends already do the right thing. Fortuitiously, this also improves the IR we give to LLVM for things like `mem::replace`, and fixes a couple of long-standing bugs where `ptr::read` on `Copy` types was worse than `*`ing them. Zulip conversation: <https://rust-lang.zulipchat.com/#narrow/stream/219381-t-libs/topic/Move.20array.3A.3AIntoIter.20to.20ManuallyDrop/near/341189936> cc `@erikdesjardins` `@JakobDegen` `@workingjubilee` `@the8472` Fixes #106369 Fixes #73258
This commit is contained in:
commit
e4b9f86054
17 changed files with 358 additions and 48 deletions
|
@ -149,6 +149,35 @@ impl<'tcx> MirPass<'tcx> for LowerIntrinsics {
|
|||
terminator.kind = TerminatorKind::Goto { target };
|
||||
}
|
||||
}
|
||||
sym::read_via_copy => {
|
||||
let [arg] = args.as_slice() else {
|
||||
span_bug!(terminator.source_info.span, "Wrong number of arguments");
|
||||
};
|
||||
let derefed_place =
|
||||
if let Some(place) = arg.place() && let Some(local) = place.as_local() {
|
||||
tcx.mk_place_deref(local.into())
|
||||
} else {
|
||||
span_bug!(terminator.source_info.span, "Only passing a local is supported");
|
||||
};
|
||||
terminator.kind = match *target {
|
||||
None => {
|
||||
// No target means this read something uninhabited,
|
||||
// so it must be unreachable, and we don't need to
|
||||
// preserve the assignment either.
|
||||
TerminatorKind::Unreachable
|
||||
}
|
||||
Some(target) => {
|
||||
block.statements.push(Statement {
|
||||
source_info: terminator.source_info,
|
||||
kind: StatementKind::Assign(Box::new((
|
||||
*destination,
|
||||
Rvalue::Use(Operand::Copy(derefed_place)),
|
||||
))),
|
||||
});
|
||||
TerminatorKind::Goto { target }
|
||||
}
|
||||
}
|
||||
}
|
||||
sym::discriminant_value => {
|
||||
if let (Some(target), Some(arg)) = (*target, args[0].place()) {
|
||||
let arg = tcx.mk_place_deref(arg);
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue