Represent the raw pointer for a array length check as a new kind of fake borrow

This commit is contained in:
Michael Goulet 2025-01-19 22:45:03 +00:00
parent 057313b7a6
commit eeecb56b73
26 changed files with 199 additions and 89 deletions

View file

@ -518,7 +518,7 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> {
}
Rvalue::Ref(_, BorrowKind::Mut { .. }, place)
| Rvalue::RawPtr(Mutability::Mut, place) => {
| Rvalue::RawPtr(RawPtrKind::Mut, place) => {
// Inside mutable statics, we allow arbitrary mutable references.
// We've allowed `static mut FOO = &mut [elements];` for a long time (the exact
// reasons why are lost to history), and there is no reason to restrict that to
@ -536,7 +536,7 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> {
}
Rvalue::Ref(_, BorrowKind::Shared | BorrowKind::Fake(_), place)
| Rvalue::RawPtr(Mutability::Not, place) => {
| Rvalue::RawPtr(RawPtrKind::Const, place) => {
let borrowed_place_has_mut_interior = qualifs::in_place::<HasMutInterior, _>(
self.ccx,
&mut |local| self.qualifs.has_mut_interior(self.ccx, local, location),
@ -548,6 +548,12 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> {
}
}
Rvalue::RawPtr(RawPtrKind::FakeForPtrMetadata, place) => {
// These are only inserted for slice length, so the place must already be indirect.
// This implies we do not have to worry about whether the borrow escapes.
assert!(place.is_indirect(), "fake borrows are always indirect");
}
Rvalue::Cast(
CastKind::PointerCoercion(
PointerCoercion::MutToConstPointer
@ -600,12 +606,8 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> {
}
}
UnOp::PtrMetadata => {
if !ty.is_ref() && !ty.is_unsafe_ptr() {
span_bug!(
self.span,
"non-pointer type in `Rvalue::UnaryOp({op:?})`: {ty:?}",
);
}
// Getting the metadata from a pointer is always const.
// We already validated the type is valid in the validator.
}
}
}

View file

@ -9,7 +9,6 @@ use rustc_middle::ty::layout::FnAbiOf;
use rustc_middle::ty::{self, Instance, Ty};
use rustc_middle::{bug, mir, span_bug};
use rustc_span::source_map::Spanned;
use rustc_span::{DesugaringKind, Span};
use rustc_target::callconv::FnAbi;
use tracing::{info, instrument, trace};
@ -81,9 +80,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
use rustc_middle::mir::StatementKind::*;
match &stmt.kind {
Assign(box (place, rvalue)) => {
self.eval_rvalue_into_place(rvalue, *place, stmt.source_info.span)?
}
Assign(box (place, rvalue)) => self.eval_rvalue_into_place(rvalue, *place)?,
SetDiscriminant { place, variant_index } => {
let dest = self.eval_place(**place)?;
@ -162,7 +159,6 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
&mut self,
rvalue: &mir::Rvalue<'tcx>,
place: mir::Place<'tcx>,
span: Span,
) -> InterpResult<'tcx> {
let dest = self.eval_place(place)?;
// FIXME: ensure some kind of non-aliasing between LHS and RHS?
@ -241,7 +237,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
self.write_immediate(*val, &dest)?;
}
RawPtr(_, place) => {
RawPtr(kind, place) => {
// Figure out whether this is an addr_of of an already raw place.
let place_base_raw = if place.is_indirect_first_projection() {
let ty = self.frame().body.local_decls[place.local].ty;
@ -254,13 +250,9 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
let src = self.eval_place(place)?;
let place = self.force_allocation(&src)?;
let mut val = ImmTy::from_immediate(place.to_ref(self), dest.layout);
if !place_base_raw
&& span.desugaring_kind() != Some(DesugaringKind::IndexBoundsCheckReborrow)
{
// If this was not already raw, it needs retagging.
// As a special hack, we exclude the desugared `PtrMetadata(&raw const *_n)`
// from indexing. (Really we should not do any retag on `&raw` but that does not
// currently work with Stacked Borrows.)
if !place_base_raw && !kind.is_fake() {
// If this was not already raw, it needs retagging -- except for "fake"
// raw borrows whose defining property is that they do not get retagged.
val = M::retag_ptr_value(self, mir::RetagKind::Raw, &val)?;
}
self.write_immediate(*val, &dest)?;