Represent the raw pointer for a array length check as a new kind of fake borrow
This commit is contained in:
parent
057313b7a6
commit
eeecb56b73
26 changed files with 199 additions and 89 deletions
|
@ -1284,15 +1284,18 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, '_, 'tcx> {
|
|||
);
|
||||
}
|
||||
|
||||
&Rvalue::RawPtr(mutability, place) => {
|
||||
let access_kind = match mutability {
|
||||
Mutability::Mut => (
|
||||
&Rvalue::RawPtr(kind, place) => {
|
||||
let access_kind = match kind {
|
||||
RawPtrKind::Mut => (
|
||||
Deep,
|
||||
Write(WriteKind::MutableBorrow(BorrowKind::Mut {
|
||||
kind: MutBorrowKind::Default,
|
||||
})),
|
||||
),
|
||||
Mutability::Not => (Deep, Read(ReadKind::Borrow(BorrowKind::Shared))),
|
||||
RawPtrKind::Const => (Deep, Read(ReadKind::Borrow(BorrowKind::Shared))),
|
||||
RawPtrKind::FakeForPtrMetadata => {
|
||||
(Shallow(Some(ArtificialField::ArrayLength)), Read(ReadKind::Copy))
|
||||
}
|
||||
};
|
||||
|
||||
self.access_place(
|
||||
|
|
|
@ -3,11 +3,7 @@ use std::ops::ControlFlow;
|
|||
use rustc_data_structures::graph::dominators::Dominators;
|
||||
use rustc_middle::bug;
|
||||
use rustc_middle::mir::visit::Visitor;
|
||||
use rustc_middle::mir::{
|
||||
self, BasicBlock, Body, BorrowKind, FakeBorrowKind, InlineAsmOperand, Location, Mutability,
|
||||
NonDivergingIntrinsic, Operand, Place, Rvalue, Statement, StatementKind, Terminator,
|
||||
TerminatorKind,
|
||||
};
|
||||
use rustc_middle::mir::*;
|
||||
use rustc_middle::ty::TyCtxt;
|
||||
use tracing::debug;
|
||||
|
||||
|
@ -60,7 +56,7 @@ impl<'a, 'tcx> Visitor<'tcx> for LoanInvalidationsGenerator<'a, 'tcx> {
|
|||
StatementKind::Intrinsic(box NonDivergingIntrinsic::Assume(op)) => {
|
||||
self.consume_operand(location, op);
|
||||
}
|
||||
StatementKind::Intrinsic(box NonDivergingIntrinsic::CopyNonOverlapping(mir::CopyNonOverlapping {
|
||||
StatementKind::Intrinsic(box NonDivergingIntrinsic::CopyNonOverlapping(CopyNonOverlapping {
|
||||
src,
|
||||
dst,
|
||||
count,
|
||||
|
@ -273,15 +269,18 @@ impl<'a, 'tcx> LoanInvalidationsGenerator<'a, 'tcx> {
|
|||
self.access_place(location, place, access_kind, LocalMutationIsAllowed::No);
|
||||
}
|
||||
|
||||
&Rvalue::RawPtr(mutability, place) => {
|
||||
let access_kind = match mutability {
|
||||
Mutability::Mut => (
|
||||
&Rvalue::RawPtr(kind, place) => {
|
||||
let access_kind = match kind {
|
||||
RawPtrKind::Mut => (
|
||||
Deep,
|
||||
Write(WriteKind::MutableBorrow(BorrowKind::Mut {
|
||||
kind: mir::MutBorrowKind::Default,
|
||||
kind: MutBorrowKind::Default,
|
||||
})),
|
||||
),
|
||||
Mutability::Not => (Deep, Read(ReadKind::Borrow(BorrowKind::Shared))),
|
||||
RawPtrKind::Const => (Deep, Read(ReadKind::Borrow(BorrowKind::Shared))),
|
||||
RawPtrKind::FakeForPtrMetadata => {
|
||||
(Shallow(Some(ArtificialField::ArrayLength)), Read(ReadKind::Copy))
|
||||
}
|
||||
};
|
||||
|
||||
self.access_place(location, place, access_kind, LocalMutationIsAllowed::No);
|
||||
|
|
|
@ -612,9 +612,10 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
|
|||
mir::Rvalue::CopyForDeref(place) => {
|
||||
self.codegen_operand(bx, &mir::Operand::Copy(place))
|
||||
}
|
||||
mir::Rvalue::RawPtr(mutability, place) => {
|
||||
let mk_ptr =
|
||||
move |tcx: TyCtxt<'tcx>, ty: Ty<'tcx>| Ty::new_ptr(tcx, ty, mutability);
|
||||
mir::Rvalue::RawPtr(kind, place) => {
|
||||
let mk_ptr = move |tcx: TyCtxt<'tcx>, ty: Ty<'tcx>| {
|
||||
Ty::new_ptr(tcx, ty, kind.to_mutbl_lossy())
|
||||
};
|
||||
self.codegen_place_to_pointer(bx, place, mk_ptr)
|
||||
}
|
||||
|
||||
|
|
|
@ -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.
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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)?;
|
||||
|
|
|
@ -180,6 +180,59 @@ pub enum BorrowKind {
|
|||
Mut { kind: MutBorrowKind },
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, TyEncodable, TyDecodable)]
|
||||
#[derive(Hash, HashStable)]
|
||||
pub enum RawPtrKind {
|
||||
Mut,
|
||||
Const,
|
||||
/// Creates a raw pointer to a place that will only be used to access its metadata,
|
||||
/// not the data behind the pointer. Note that this limitation is *not* enforced
|
||||
/// by the validator.
|
||||
///
|
||||
/// The borrow checker allows overlap of these raw pointers with references to the
|
||||
/// data. This is sound even if the pointer is "misused" since any such use is anyway
|
||||
/// unsafe. In terms of the operational semantics (i.e., Miri), this is equivalent
|
||||
/// to `RawPtrKind::Mut`, but will never incur a retag.
|
||||
FakeForPtrMetadata,
|
||||
}
|
||||
|
||||
impl From<Mutability> for RawPtrKind {
|
||||
fn from(other: Mutability) -> Self {
|
||||
match other {
|
||||
Mutability::Mut => RawPtrKind::Mut,
|
||||
Mutability::Not => RawPtrKind::Const,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl RawPtrKind {
|
||||
pub fn is_fake(self) -> bool {
|
||||
match self {
|
||||
RawPtrKind::Mut | RawPtrKind::Const => false,
|
||||
RawPtrKind::FakeForPtrMetadata => true,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn to_mutbl_lossy(self) -> Mutability {
|
||||
match self {
|
||||
RawPtrKind::Mut => Mutability::Mut,
|
||||
RawPtrKind::Const => Mutability::Not,
|
||||
|
||||
// We have no type corresponding to a fake borrow, so use
|
||||
// `*const` as an approximation.
|
||||
RawPtrKind::FakeForPtrMetadata => Mutability::Not,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn ptr_str(self) -> &'static str {
|
||||
match self {
|
||||
RawPtrKind::Mut => "mut",
|
||||
RawPtrKind::Const => "const",
|
||||
RawPtrKind::FakeForPtrMetadata => "const (fake)",
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, TyEncodable, TyDecodable)]
|
||||
#[derive(Hash, HashStable)]
|
||||
pub enum MutBorrowKind {
|
||||
|
@ -1356,7 +1409,7 @@ pub enum Rvalue<'tcx> {
|
|||
///
|
||||
/// Like with references, the semantics of this operation are heavily dependent on the aliasing
|
||||
/// model.
|
||||
RawPtr(Mutability, Place<'tcx>),
|
||||
RawPtr(RawPtrKind, Place<'tcx>),
|
||||
|
||||
/// Yields the length of the place, as a `usize`.
|
||||
///
|
||||
|
|
|
@ -206,9 +206,9 @@ impl<'tcx> Rvalue<'tcx> {
|
|||
let place_ty = place.ty(local_decls, tcx).ty;
|
||||
Ty::new_ref(tcx, reg, place_ty, bk.to_mutbl_lossy())
|
||||
}
|
||||
Rvalue::RawPtr(mutability, ref place) => {
|
||||
Rvalue::RawPtr(kind, ref place) => {
|
||||
let place_ty = place.ty(local_decls, tcx).ty;
|
||||
Ty::new_ptr(tcx, place_ty, mutability)
|
||||
Ty::new_ptr(tcx, place_ty, kind.to_mutbl_lossy())
|
||||
}
|
||||
Rvalue::Len(..) => tcx.types.usize,
|
||||
Rvalue::Cast(.., ty) => ty,
|
||||
|
|
|
@ -15,6 +15,7 @@ TrivialTypeTraversalImpls! {
|
|||
SourceScopeLocalData,
|
||||
UserTypeAnnotationIndex,
|
||||
BorrowKind,
|
||||
RawPtrKind,
|
||||
CastKind,
|
||||
BasicBlock,
|
||||
SwitchTargets,
|
||||
|
|
|
@ -685,12 +685,15 @@ macro_rules! make_mir_visitor {
|
|||
|
||||
Rvalue::RawPtr(m, path) => {
|
||||
let ctx = match m {
|
||||
Mutability::Mut => PlaceContext::MutatingUse(
|
||||
RawPtrKind::Mut => PlaceContext::MutatingUse(
|
||||
MutatingUseContext::RawBorrow
|
||||
),
|
||||
Mutability::Not => PlaceContext::NonMutatingUse(
|
||||
RawPtrKind::Const => PlaceContext::NonMutatingUse(
|
||||
NonMutatingUseContext::RawBorrow
|
||||
),
|
||||
RawPtrKind::FakeForPtrMetadata => PlaceContext::NonMutatingUse(
|
||||
NonMutatingUseContext::Inspect
|
||||
),
|
||||
};
|
||||
self.visit_place(path, ctx, location);
|
||||
}
|
||||
|
|
|
@ -253,7 +253,7 @@ impl<'a, 'tcx> ParseCtxt<'a, 'tcx> {
|
|||
Rvalue::Ref(self.tcx.lifetimes.re_erased, *borrow_kind, self.parse_place(*arg)?)
|
||||
),
|
||||
ExprKind::RawBorrow { mutability, arg } => Ok(
|
||||
Rvalue::RawPtr(*mutability, self.parse_place(*arg)?)
|
||||
Rvalue::RawPtr((*mutability).into(), self.parse_place(*arg)?)
|
||||
),
|
||||
ExprKind::Binary { op, lhs, rhs } => Ok(
|
||||
Rvalue::BinaryOp(*op, Box::new((self.parse_operand(*lhs)?, self.parse_operand(*rhs)?)))
|
||||
|
|
|
@ -11,7 +11,7 @@ use rustc_middle::mir::*;
|
|||
use rustc_middle::thir::*;
|
||||
use rustc_middle::ty::{self, AdtDef, CanonicalUserTypeAnnotation, Ty, Variance};
|
||||
use rustc_middle::{bug, span_bug};
|
||||
use rustc_span::{DesugaringKind, Span};
|
||||
use rustc_span::Span;
|
||||
use tracing::{debug, instrument, trace};
|
||||
|
||||
use crate::builder::ForGuard::{OutsideGuard, RefWithinGuard};
|
||||
|
@ -643,8 +643,6 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
|||
source_info: SourceInfo,
|
||||
) -> Operand<'tcx> {
|
||||
let place_ty = place.ty(&self.local_decls, self.tcx).ty;
|
||||
let usize_ty = self.tcx.types.usize;
|
||||
|
||||
match place_ty.kind() {
|
||||
ty::Array(_elem_ty, len_const) => {
|
||||
// We know how long an array is, so just use that as a constant
|
||||
|
@ -668,27 +666,18 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
|||
// the MIR we're building here needs to pass NLL later.
|
||||
Operand::Copy(Place::from(place.local))
|
||||
} else {
|
||||
let len_span = self.tcx.with_stable_hashing_context(|hcx| {
|
||||
let span = source_info.span;
|
||||
span.mark_with_reason(
|
||||
None,
|
||||
DesugaringKind::IndexBoundsCheckReborrow,
|
||||
span.edition(),
|
||||
hcx,
|
||||
)
|
||||
});
|
||||
let ptr_ty = Ty::new_imm_ptr(self.tcx, place_ty);
|
||||
let slice_ptr = self.temp(ptr_ty, span);
|
||||
self.cfg.push_assign(
|
||||
block,
|
||||
SourceInfo { span: len_span, ..source_info },
|
||||
source_info,
|
||||
slice_ptr,
|
||||
Rvalue::RawPtr(Mutability::Not, place),
|
||||
Rvalue::RawPtr(RawPtrKind::FakeForPtrMetadata, place),
|
||||
);
|
||||
Operand::Move(slice_ptr)
|
||||
};
|
||||
|
||||
let len = self.temp(usize_ty, span);
|
||||
let len = self.temp(self.tcx.types.usize, span);
|
||||
self.cfg.push_assign(
|
||||
block,
|
||||
source_info,
|
||||
|
|
|
@ -303,7 +303,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
|||
hir::Mutability::Not => this.as_read_only_place(block, arg),
|
||||
hir::Mutability::Mut => this.as_place(block, arg),
|
||||
};
|
||||
let address_of = Rvalue::RawPtr(mutability, unpack!(block = place));
|
||||
let address_of = Rvalue::RawPtr(mutability.into(), unpack!(block = place));
|
||||
this.cfg.push_assign(block, source_info, destination, address_of);
|
||||
block.unit()
|
||||
}
|
||||
|
|
|
@ -700,7 +700,7 @@ where
|
|||
statements: vec![
|
||||
self.assign(
|
||||
ptr,
|
||||
Rvalue::RawPtr(Mutability::Mut, tcx.mk_place_index(self.place, cur)),
|
||||
Rvalue::RawPtr(RawPtrKind::Mut, tcx.mk_place_index(self.place, cur)),
|
||||
),
|
||||
self.assign(
|
||||
cur.into(),
|
||||
|
@ -816,7 +816,7 @@ where
|
|||
|
||||
let mut delegate_block = BasicBlockData {
|
||||
statements: vec![
|
||||
self.assign(Place::from(array_ptr), Rvalue::RawPtr(Mutability::Mut, self.place)),
|
||||
self.assign(Place::from(array_ptr), Rvalue::RawPtr(RawPtrKind::Mut, self.place)),
|
||||
self.assign(
|
||||
Place::from(slice_ptr),
|
||||
Rvalue::Cast(
|
||||
|
|
|
@ -192,7 +192,7 @@ enum AggregateTy<'tcx> {
|
|||
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
|
||||
enum AddressKind {
|
||||
Ref(BorrowKind),
|
||||
Address(Mutability),
|
||||
Address(RawPtrKind),
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, Eq, Hash)]
|
||||
|
@ -504,7 +504,9 @@ impl<'body, 'tcx> VnState<'body, 'tcx> {
|
|||
mplace.layout.ty,
|
||||
bk.to_mutbl_lossy(),
|
||||
),
|
||||
AddressKind::Address(mutbl) => Ty::new_ptr(self.tcx, mplace.layout.ty, mutbl),
|
||||
AddressKind::Address(mutbl) => {
|
||||
Ty::new_ptr(self.tcx, mplace.layout.ty, mutbl.to_mutbl_lossy())
|
||||
}
|
||||
};
|
||||
let layout = self.ecx.layout_of(ty).ok()?;
|
||||
ImmTy::from_immediate(pointer, layout).into()
|
||||
|
|
|
@ -125,7 +125,7 @@ impl<'tcx> crate::MirPass<'tcx> for EnumSizeOpt {
|
|||
source_info,
|
||||
kind: StatementKind::Assign(Box::new((
|
||||
dst,
|
||||
Rvalue::RawPtr(Mutability::Mut, *lhs),
|
||||
Rvalue::RawPtr(RawPtrKind::Mut, *lhs),
|
||||
))),
|
||||
};
|
||||
|
||||
|
@ -146,7 +146,7 @@ impl<'tcx> crate::MirPass<'tcx> for EnumSizeOpt {
|
|||
source_info,
|
||||
kind: StatementKind::Assign(Box::new((
|
||||
src,
|
||||
Rvalue::RawPtr(Mutability::Not, *rhs),
|
||||
Rvalue::RawPtr(RawPtrKind::Const, *rhs),
|
||||
))),
|
||||
};
|
||||
|
||||
|
|
|
@ -2,17 +2,11 @@ use std::iter;
|
|||
|
||||
use itertools::Itertools;
|
||||
use rustc_abi::{FieldIdx, VariantIdx};
|
||||
use rustc_ast::Mutability;
|
||||
use rustc_const_eval::interpret;
|
||||
use rustc_hir::def_id::DefId;
|
||||
use rustc_hir::lang_items::LangItem;
|
||||
use rustc_index::{Idx, IndexVec};
|
||||
use rustc_middle::mir::{
|
||||
BasicBlock, BasicBlockData, Body, CallSource, CastKind, CoercionSource, Const, ConstOperand,
|
||||
ConstValue, Local, LocalDecl, MirSource, Operand, Place, PlaceElem, RETURN_PLACE, Rvalue,
|
||||
SourceInfo, Statement, StatementKind, Terminator, TerminatorKind, UnwindAction,
|
||||
UnwindTerminateReason,
|
||||
};
|
||||
use rustc_middle::mir::*;
|
||||
use rustc_middle::ty::adjustment::PointerCoercion;
|
||||
use rustc_middle::ty::util::{AsyncDropGlueMorphology, Discr};
|
||||
use rustc_middle::ty::{self, Ty, TyCtxt};
|
||||
|
@ -345,7 +339,7 @@ impl<'tcx> AsyncDestructorCtorShimBuilder<'tcx> {
|
|||
.tcx
|
||||
.mk_place_elems(&[PlaceElem::Deref, PlaceElem::Field(field, field_ty)]),
|
||||
};
|
||||
self.put_temp_rvalue(Rvalue::RawPtr(Mutability::Mut, place))
|
||||
self.put_temp_rvalue(Rvalue::RawPtr(RawPtrKind::Mut, place))
|
||||
}
|
||||
|
||||
/// If given Self is an enum puts `to_drop: *mut FieldTy` on top of
|
||||
|
@ -365,7 +359,7 @@ impl<'tcx> AsyncDestructorCtorShimBuilder<'tcx> {
|
|||
PlaceElem::Field(field, field_ty),
|
||||
]),
|
||||
};
|
||||
self.put_temp_rvalue(Rvalue::RawPtr(Mutability::Mut, place))
|
||||
self.put_temp_rvalue(Rvalue::RawPtr(RawPtrKind::Mut, place))
|
||||
}
|
||||
|
||||
/// If given Self is an enum puts `to_drop: *mut FieldTy` on top of
|
||||
|
|
|
@ -232,6 +232,18 @@ impl<'tcx> Stable<'tcx> for mir::Mutability {
|
|||
}
|
||||
}
|
||||
|
||||
impl<'tcx> Stable<'tcx> for mir::RawPtrKind {
|
||||
type T = stable_mir::mir::RawPtrKind;
|
||||
fn stable(&self, _: &mut Tables<'_>) -> Self::T {
|
||||
use mir::RawPtrKind::*;
|
||||
match *self {
|
||||
Const => stable_mir::mir::RawPtrKind::Const,
|
||||
Mut => stable_mir::mir::RawPtrKind::Mut,
|
||||
FakeForPtrMetadata => stable_mir::mir::RawPtrKind::FakeForPtrMetadata,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> Stable<'tcx> for mir::BorrowKind {
|
||||
type T = stable_mir::mir::BorrowKind;
|
||||
fn stable(&self, tables: &mut Tables<'_>) -> Self::T {
|
||||
|
|
|
@ -1163,9 +1163,6 @@ pub enum DesugaringKind {
|
|||
WhileLoop,
|
||||
/// `async Fn()` bound modifier
|
||||
BoundModifier,
|
||||
/// Marks a `&raw const *_1` needed as part of getting the length of a mutable
|
||||
/// slice for the bounds check, so that MIRI's retag handling can recognize it.
|
||||
IndexBoundsCheckReborrow,
|
||||
}
|
||||
|
||||
impl DesugaringKind {
|
||||
|
@ -1182,7 +1179,6 @@ impl DesugaringKind {
|
|||
DesugaringKind::ForLoop => "`for` loop",
|
||||
DesugaringKind::WhileLoop => "`while` loop",
|
||||
DesugaringKind::BoundModifier => "trait bound modifier",
|
||||
DesugaringKind::IndexBoundsCheckReborrow => "slice indexing",
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -457,7 +457,7 @@ pub enum Rvalue {
|
|||
///
|
||||
/// This is generated by pointer casts like `&v as *const _` or raw address of expressions like
|
||||
/// `&raw v` or `addr_of!(v)`.
|
||||
AddressOf(Mutability, Place),
|
||||
AddressOf(RawPtrKind, Place),
|
||||
|
||||
/// Creates an aggregate value, like a tuple or struct.
|
||||
///
|
||||
|
@ -577,7 +577,7 @@ impl Rvalue {
|
|||
}
|
||||
Rvalue::AddressOf(mutability, place) => {
|
||||
let place_ty = place.ty(locals)?;
|
||||
Ok(Ty::new_ptr(place_ty, *mutability))
|
||||
Ok(Ty::new_ptr(place_ty, mutability.to_mutable_lossy()))
|
||||
}
|
||||
Rvalue::Len(..) => Ok(Ty::usize_ty()),
|
||||
Rvalue::Cast(.., ty) => Ok(*ty),
|
||||
|
@ -903,6 +903,24 @@ impl BorrowKind {
|
|||
}
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug, Eq, PartialEq, Serialize)]
|
||||
pub enum RawPtrKind {
|
||||
Mut,
|
||||
Const,
|
||||
FakeForPtrMetadata,
|
||||
}
|
||||
|
||||
impl RawPtrKind {
|
||||
pub fn to_mutable_lossy(self) -> Mutability {
|
||||
match self {
|
||||
RawPtrKind::Mut { .. } => Mutability::Mut,
|
||||
RawPtrKind::Const => Mutability::Not,
|
||||
// FIXME: There's no type corresponding to a shallow borrow, so use `&` as an approximation.
|
||||
RawPtrKind::FakeForPtrMetadata => Mutability::Not,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug, Eq, PartialEq, Serialize)]
|
||||
pub enum MutBorrowKind {
|
||||
Default,
|
||||
|
|
|
@ -6,7 +6,9 @@ use std::{fmt, io, iter};
|
|||
use fmt::{Display, Formatter};
|
||||
|
||||
use super::{AggregateKind, AssertMessage, BinOp, BorrowKind, FakeBorrowKind, TerminatorKind};
|
||||
use crate::mir::{Operand, Place, Rvalue, StatementKind, UnwindAction, VarDebugInfoContents};
|
||||
use crate::mir::{
|
||||
Operand, Place, RawPtrKind, Rvalue, StatementKind, UnwindAction, VarDebugInfoContents,
|
||||
};
|
||||
use crate::ty::{AdtKind, IndexedVal, MirConst, Ty, TyConst};
|
||||
use crate::{Body, CrateDef, Mutability, with};
|
||||
|
||||
|
@ -325,7 +327,7 @@ fn pretty_ty_const(ct: &TyConst) -> String {
|
|||
fn pretty_rvalue<W: Write>(writer: &mut W, rval: &Rvalue) -> io::Result<()> {
|
||||
match rval {
|
||||
Rvalue::AddressOf(mutability, place) => {
|
||||
write!(writer, "&raw {} {:?}", pretty_mut(*mutability), place)
|
||||
write!(writer, "&raw {} {:?}", pretty_raw_ptr_kind(*mutability), place)
|
||||
}
|
||||
Rvalue::Aggregate(aggregate_kind, operands) => {
|
||||
// FIXME: Add pretty_aggregate function that returns a pretty string
|
||||
|
@ -437,3 +439,11 @@ fn pretty_mut(mutability: Mutability) -> &'static str {
|
|||
Mutability::Mut => "mut ",
|
||||
}
|
||||
}
|
||||
|
||||
fn pretty_raw_ptr_kind(kind: RawPtrKind) -> &'static str {
|
||||
match kind {
|
||||
RawPtrKind::Const => "const",
|
||||
RawPtrKind::Mut => "mut",
|
||||
RawPtrKind::FakeForPtrMetadata => "const (fake)",
|
||||
}
|
||||
}
|
||||
|
|
|
@ -308,7 +308,7 @@ pub trait MirVisitor {
|
|||
fn super_rvalue(&mut self, rvalue: &Rvalue, location: Location) {
|
||||
match rvalue {
|
||||
Rvalue::AddressOf(mutability, place) => {
|
||||
let pcx = PlaceContext { is_mut: *mutability == Mutability::Mut };
|
||||
let pcx = PlaceContext { is_mut: *mutability == RawPtrKind::Mut };
|
||||
self.visit_place(place, pcx, location);
|
||||
}
|
||||
Rvalue::Aggregate(_, operands) => {
|
||||
|
|
35
src/tools/miri/tests/pass/disjoint-array-accesses.rs
Normal file
35
src/tools/miri/tests/pass/disjoint-array-accesses.rs
Normal file
|
@ -0,0 +1,35 @@
|
|||
// This is a regression test for issue #135671 where a MIR refactor about arrays and their lengths
|
||||
// unexpectedly caused borrowck errors for disjoint borrows of array elements, for which we had no
|
||||
// tests. This is a collection of a few code samples from that issue.
|
||||
|
||||
//@revisions: stack tree
|
||||
//@[tree]compile-flags: -Zmiri-tree-borrows
|
||||
|
||||
struct Test {
|
||||
a: i32,
|
||||
b: i32,
|
||||
}
|
||||
|
||||
fn one() {
|
||||
let inputs: &mut [_] = &mut [Test { a: 0, b: 0 }];
|
||||
let a = &mut inputs[0].a;
|
||||
let b = &mut inputs[0].b;
|
||||
|
||||
*a = 0;
|
||||
*b = 1;
|
||||
}
|
||||
|
||||
fn two() {
|
||||
let slice = &mut [(0, 0)][..];
|
||||
std::mem::swap(&mut slice[0].0, &mut slice[0].1);
|
||||
}
|
||||
|
||||
fn three(a: &mut [(i32, i32)], i: usize, j: usize) -> (&mut i32, &mut i32) {
|
||||
(&mut a[i].0, &mut a[j].1)
|
||||
}
|
||||
|
||||
fn main() {
|
||||
one();
|
||||
two();
|
||||
three(&mut [(1, 2), (3, 4)], 0, 1);
|
||||
}
|
|
@ -14,7 +14,7 @@ fn index_custom(_1: &WithSliceTail, _2: usize) -> &i32 {
|
|||
StorageLive(_3);
|
||||
StorageLive(_4);
|
||||
_4 = copy _2;
|
||||
_5 = &raw const ((*_1).1: [i32]);
|
||||
_5 = &raw const (fake) ((*_1).1: [i32]);
|
||||
_6 = PtrMetadata(move _5);
|
||||
_7 = Lt(copy _4, copy _6);
|
||||
assert(move _7, "index out of bounds: the length is {} but the index is {}", move _6, copy _4) -> [success: bb1, unwind: bb2];
|
||||
|
|
|
@ -14,7 +14,7 @@ fn index_mut_slice(_1: &mut [i32], _2: usize) -> &i32 {
|
|||
StorageLive(_3);
|
||||
StorageLive(_4);
|
||||
_4 = copy _2;
|
||||
_5 = &raw const (*_1);
|
||||
_5 = &raw const (fake) (*_1);
|
||||
_6 = PtrMetadata(move _5);
|
||||
_7 = Lt(copy _4, copy _6);
|
||||
assert(move _7, "index out of bounds: the length is {} but the index is {}", move _6, copy _4) -> [success: bb1, unwind: bb2];
|
||||
|
|
|
@ -54,7 +54,7 @@ struct WithSliceTail(f64, [i32]);
|
|||
// EMIT_MIR index_array_and_slice.index_custom.built.after.mir
|
||||
fn index_custom(custom: &WithSliceTail, index: usize) -> &i32 {
|
||||
// CHECK: bb0:
|
||||
// CHECK: [[PTR:_.+]] = &raw const ((*_1).1: [i32]);
|
||||
// CHECK: [[PTR:_.+]] = &raw const (fake) ((*_1).1: [i32]);
|
||||
// CHECK: [[LEN:_.+]] = PtrMetadata(move [[PTR]]);
|
||||
// CHECK: [[LT:_.+]] = Lt(copy _2, copy [[LEN]]);
|
||||
// CHECK: assert(move [[LT]], "index out of bounds{{.+}}", move [[LEN]], copy _2) -> [success: bb1,
|
||||
|
|
|
@ -18,7 +18,7 @@ fn foo(_1: Box<[T]>) -> T {
|
|||
StorageLive(_3);
|
||||
StorageLive(_4);
|
||||
_4 = const 0_usize;
|
||||
_5 = &raw const (*_1);
|
||||
_5 = &raw const (fake) (*_1);
|
||||
_6 = PtrMetadata(move _5);
|
||||
_7 = Lt(copy _4, copy _6);
|
||||
assert(move _7, "index out of bounds: the length is {} but the index is {}", move _6, copy _4) -> [success: bb1, unwind: bb5];
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue