Add Rvalue::AddressOf to MIR
This operator creates a raw pointer to a Place directly, without first creating a reference. See RFC #2582 for motivation. The Rvalue is currently unused.
This commit is contained in:
parent
19bd934676
commit
3a19fbf95d
20 changed files with 306 additions and 168 deletions
|
@ -2060,6 +2060,11 @@ pub enum Rvalue<'tcx> {
|
|||
/// &x or &mut x
|
||||
Ref(Region<'tcx>, BorrowKind, Place<'tcx>),
|
||||
|
||||
/// Create a raw pointer to the given place
|
||||
/// Can be generated by raw address of expressions (`&raw const x`),
|
||||
/// or when casting a reference to a raw pointer.
|
||||
AddressOf(Mutability, Place<'tcx>),
|
||||
|
||||
/// length of a [X] or [X;n] value
|
||||
Len(Place<'tcx>),
|
||||
|
||||
|
@ -2214,6 +2219,15 @@ impl<'tcx> Debug for Rvalue<'tcx> {
|
|||
write!(fmt, "&{}{}{:?}", region, kind_str, place)
|
||||
}
|
||||
|
||||
AddressOf(mutability, ref place) => {
|
||||
let kind_str = match mutability {
|
||||
Mutability::Mut => "mut",
|
||||
Mutability::Not => "const",
|
||||
};
|
||||
|
||||
write!(fmt, "&raw {} {:?}", kind_str, place)
|
||||
}
|
||||
|
||||
Aggregate(ref kind, ref places) => {
|
||||
fn fmt_tuple(fmt: &mut Formatter<'_>, places: &[Operand<'_>]) -> fmt::Result {
|
||||
let mut tuple_fmt = fmt.debug_tuple("");
|
||||
|
@ -3085,6 +3099,9 @@ impl<'tcx> TypeFoldable<'tcx> for Rvalue<'tcx> {
|
|||
Ref(region, bk, ref place) => {
|
||||
Ref(region.fold_with(folder), bk, place.fold_with(folder))
|
||||
}
|
||||
AddressOf(mutability, ref place) => {
|
||||
AddressOf(mutability, place.fold_with(folder))
|
||||
}
|
||||
Len(ref place) => Len(place.fold_with(folder)),
|
||||
Cast(kind, ref op, ty) => Cast(kind, op.fold_with(folder), ty.fold_with(folder)),
|
||||
BinaryOp(op, ref rhs, ref lhs) => {
|
||||
|
@ -3125,6 +3142,7 @@ impl<'tcx> TypeFoldable<'tcx> for Rvalue<'tcx> {
|
|||
Use(ref op) => op.visit_with(visitor),
|
||||
Repeat(ref op, _) => op.visit_with(visitor),
|
||||
Ref(region, _, ref place) => region.visit_with(visitor) || place.visit_with(visitor),
|
||||
AddressOf(_, ref place) => place.visit_with(visitor),
|
||||
Len(ref place) => place.visit_with(visitor),
|
||||
Cast(_, ref op, ty) => op.visit_with(visitor) || ty.visit_with(visitor),
|
||||
BinaryOp(_, ref rhs, ref lhs) | CheckedBinaryOp(_, ref rhs, ref lhs) => {
|
||||
|
|
|
@ -172,6 +172,13 @@ impl<'tcx> Rvalue<'tcx> {
|
|||
}
|
||||
)
|
||||
}
|
||||
Rvalue::AddressOf(mutability, ref place) => {
|
||||
let place_ty = place.ty(local_decls, tcx).ty;
|
||||
tcx.mk_ptr(ty::TypeAndMut {
|
||||
ty: place_ty,
|
||||
mutbl: mutability.into(),
|
||||
})
|
||||
}
|
||||
Rvalue::Len(..) => tcx.types.usize,
|
||||
Rvalue::Cast(.., ty) => ty,
|
||||
Rvalue::BinaryOp(op, ref lhs, ref rhs) => {
|
||||
|
|
|
@ -570,6 +570,18 @@ macro_rules! make_mir_visitor {
|
|||
self.visit_place(path, ctx, location);
|
||||
}
|
||||
|
||||
Rvalue::AddressOf(m, path) => {
|
||||
let ctx = match m {
|
||||
Mutability::Mut => PlaceContext::MutatingUse(
|
||||
MutatingUseContext::AddressOf
|
||||
),
|
||||
Mutability::Not => PlaceContext::NonMutatingUse(
|
||||
NonMutatingUseContext::AddressOf
|
||||
),
|
||||
};
|
||||
self.visit_place(path, ctx, location);
|
||||
}
|
||||
|
||||
Rvalue::Len(path) => {
|
||||
self.visit_place(
|
||||
path,
|
||||
|
@ -1031,6 +1043,8 @@ pub enum NonMutatingUseContext {
|
|||
ShallowBorrow,
|
||||
/// Unique borrow.
|
||||
UniqueBorrow,
|
||||
/// AddressOf for *const pointer.
|
||||
AddressOf,
|
||||
/// Used as base for another place, e.g., `x` in `x.y`. Will not mutate the place.
|
||||
/// For example, the projection `x.y` is not marked as a mutation in these cases:
|
||||
///
|
||||
|
@ -1054,6 +1068,8 @@ pub enum MutatingUseContext {
|
|||
Drop,
|
||||
/// Mutable borrow.
|
||||
Borrow,
|
||||
/// AddressOf for *mut pointer.
|
||||
AddressOf,
|
||||
/// Used as base for another place, e.g., `x` in `x.y`. Could potentially mutate the place.
|
||||
/// For example, the projection `x.y` is marked as a mutation in these cases:
|
||||
///
|
||||
|
|
|
@ -28,8 +28,6 @@ pub enum CastTy<'tcx> {
|
|||
FnPtr,
|
||||
/// Raw pointers
|
||||
Ptr(ty::TypeAndMut<'tcx>),
|
||||
/// References
|
||||
RPtr(ty::TypeAndMut<'tcx>),
|
||||
}
|
||||
|
||||
/// Cast Kind. See RFC 401 (or librustc_typeck/check/cast.rs)
|
||||
|
@ -63,7 +61,6 @@ impl<'tcx> CastTy<'tcx> {
|
|||
ty::Adt(d,_) if d.is_enum() && d.is_payloadfree() =>
|
||||
Some(CastTy::Int(IntTy::CEnum)),
|
||||
ty::RawPtr(mt) => Some(CastTy::Ptr(mt)),
|
||||
ty::Ref(_, ty, mutbl) => Some(CastTy::RPtr(ty::TypeAndMut { ty, mutbl })),
|
||||
ty::FnPtr(..) => Some(CastTy::FnPtr),
|
||||
_ => None,
|
||||
}
|
||||
|
|
|
@ -340,10 +340,12 @@ impl<'mir, 'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> Visitor<'tcx>
|
|||
PlaceContext::MutatingUse(MutatingUseContext::Store) |
|
||||
PlaceContext::MutatingUse(MutatingUseContext::AsmOutput) |
|
||||
PlaceContext::MutatingUse(MutatingUseContext::Borrow) |
|
||||
PlaceContext::MutatingUse(MutatingUseContext::AddressOf) |
|
||||
PlaceContext::MutatingUse(MutatingUseContext::Projection) |
|
||||
PlaceContext::NonMutatingUse(NonMutatingUseContext::SharedBorrow) |
|
||||
PlaceContext::NonMutatingUse(NonMutatingUseContext::UniqueBorrow) |
|
||||
PlaceContext::NonMutatingUse(NonMutatingUseContext::ShallowBorrow) |
|
||||
PlaceContext::NonMutatingUse(NonMutatingUseContext::AddressOf) |
|
||||
PlaceContext::NonMutatingUse(NonMutatingUseContext::Projection) => {
|
||||
self.not_ssa(local);
|
||||
}
|
||||
|
|
|
@ -448,7 +448,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
|
|||
let cx = self.cx;
|
||||
let tcx = self.cx.tcx();
|
||||
|
||||
let result = match &place_ref {
|
||||
let result = match place_ref {
|
||||
mir::PlaceRef {
|
||||
base: mir::PlaceBase::Local(index),
|
||||
projection: [],
|
||||
|
|
|
@ -7,7 +7,7 @@ use crate::MemFlags;
|
|||
use crate::common::{self, RealPredicate, IntPredicate};
|
||||
use crate::traits::*;
|
||||
|
||||
use rustc::ty::{self, Ty, adjustment::{PointerCast}, Instance};
|
||||
use rustc::ty::{self, Ty, TyCtxt, adjustment::{PointerCast}, Instance};
|
||||
use rustc::ty::cast::{CastTy, IntTy};
|
||||
use rustc::ty::layout::{self, LayoutOf, HasTyCtxt};
|
||||
use rustc::mir;
|
||||
|
@ -342,8 +342,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
|
|||
}
|
||||
}
|
||||
(CastTy::Ptr(_), CastTy::Ptr(_)) |
|
||||
(CastTy::FnPtr, CastTy::Ptr(_)) |
|
||||
(CastTy::RPtr(_), CastTy::Ptr(_)) =>
|
||||
(CastTy::FnPtr, CastTy::Ptr(_)) =>
|
||||
bx.pointercast(llval, ll_t_out),
|
||||
(CastTy::Ptr(_), CastTy::Int(_)) |
|
||||
(CastTy::FnPtr, CastTy::Int(_)) =>
|
||||
|
@ -370,24 +369,18 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
|
|||
}
|
||||
|
||||
mir::Rvalue::Ref(_, bk, ref place) => {
|
||||
let cg_place = self.codegen_place(&mut bx, &place.as_ref());
|
||||
let mk_ref = move |tcx: TyCtxt<'tcx>, ty: Ty<'tcx>| tcx.mk_ref(
|
||||
tcx.lifetimes.re_erased,
|
||||
ty::TypeAndMut { ty, mutbl: bk.to_mutbl_lossy() }
|
||||
);
|
||||
self.codegen_place_to_pointer(bx, place, mk_ref)
|
||||
}
|
||||
|
||||
let ty = cg_place.layout.ty;
|
||||
|
||||
// Note: places are indirect, so storing the `llval` into the
|
||||
// destination effectively creates a reference.
|
||||
let val = if !bx.cx().type_has_metadata(ty) {
|
||||
OperandValue::Immediate(cg_place.llval)
|
||||
} else {
|
||||
OperandValue::Pair(cg_place.llval, cg_place.llextra.unwrap())
|
||||
};
|
||||
(bx, OperandRef {
|
||||
val,
|
||||
layout: self.cx.layout_of(self.cx.tcx().mk_ref(
|
||||
self.cx.tcx().lifetimes.re_erased,
|
||||
ty::TypeAndMut { ty, mutbl: bk.to_mutbl_lossy() }
|
||||
)),
|
||||
})
|
||||
mir::Rvalue::AddressOf(mutability, ref place) => {
|
||||
let mk_ptr = move |tcx: TyCtxt<'tcx>, ty: Ty<'tcx>| tcx.mk_ptr(
|
||||
ty::TypeAndMut { ty, mutbl: mutability.into() }
|
||||
);
|
||||
self.codegen_place_to_pointer(bx, place, mk_ptr)
|
||||
}
|
||||
|
||||
mir::Rvalue::Len(ref place) => {
|
||||
|
@ -543,6 +536,30 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
|
|||
cg_value.len(bx.cx())
|
||||
}
|
||||
|
||||
/// Codegen an `Rvalue::AddressOf` or `Rvalue::Ref`
|
||||
fn codegen_place_to_pointer(
|
||||
&mut self,
|
||||
mut bx: Bx,
|
||||
place: &mir::Place<'tcx>,
|
||||
mk_ptr_ty: impl FnOnce(TyCtxt<'tcx>, Ty<'tcx>) -> Ty<'tcx>,
|
||||
) -> (Bx, OperandRef<'tcx, Bx::Value>) {
|
||||
let cg_place = self.codegen_place(&mut bx, &place.as_ref());
|
||||
|
||||
let ty = cg_place.layout.ty;
|
||||
|
||||
// Note: places are indirect, so storing the `llval` into the
|
||||
// destination effectively creates a reference.
|
||||
let val = if !bx.cx().type_has_metadata(ty) {
|
||||
OperandValue::Immediate(cg_place.llval)
|
||||
} else {
|
||||
OperandValue::Pair(cg_place.llval, cg_place.llextra.unwrap())
|
||||
};
|
||||
(bx, OperandRef {
|
||||
val,
|
||||
layout: self.cx.layout_of(mk_ptr_ty(self.cx.tcx(), ty)),
|
||||
})
|
||||
}
|
||||
|
||||
pub fn codegen_scalar_binop(
|
||||
&mut self,
|
||||
bx: &mut Bx,
|
||||
|
@ -699,6 +716,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
|
|||
pub fn rvalue_creates_operand(&self, rvalue: &mir::Rvalue<'tcx>, span: Span) -> bool {
|
||||
match *rvalue {
|
||||
mir::Rvalue::Ref(..) |
|
||||
mir::Rvalue::AddressOf(..) |
|
||||
mir::Rvalue::Len(..) |
|
||||
mir::Rvalue::Cast(..) | // (*)
|
||||
mir::Rvalue::BinaryOp(..) |
|
||||
|
|
|
@ -3,7 +3,7 @@ use rustc::mir::visit::Visitor;
|
|||
use rustc::mir::{BasicBlock, Location, Body, Place, ReadOnlyBodyAndCache, Rvalue};
|
||||
use rustc::mir::{Statement, StatementKind};
|
||||
use rustc::mir::TerminatorKind;
|
||||
use rustc::mir::{Operand, BorrowKind};
|
||||
use rustc::mir::{Operand, BorrowKind, Mutability};
|
||||
use rustc_data_structures::graph::dominators::Dominators;
|
||||
|
||||
use crate::dataflow::indexes::BorrowIndex;
|
||||
|
@ -337,6 +337,22 @@ impl<'cx, 'tcx> InvalidationGenerator<'cx, 'tcx> {
|
|||
);
|
||||
}
|
||||
|
||||
Rvalue::AddressOf(mutability, ref place) => {
|
||||
let access_kind = match mutability {
|
||||
Mutability::Mut => (Deep, Write(WriteKind::MutableBorrow(BorrowKind::Mut {
|
||||
allow_two_phase_borrow: false,
|
||||
}))),
|
||||
Mutability::Not => (Deep, Read(ReadKind::Borrow(BorrowKind::Shared))),
|
||||
};
|
||||
|
||||
self.access_place(
|
||||
location,
|
||||
place,
|
||||
access_kind,
|
||||
LocalMutationIsAllowed::No,
|
||||
);
|
||||
}
|
||||
|
||||
Rvalue::Use(ref operand)
|
||||
| Rvalue::Repeat(ref operand, _)
|
||||
| Rvalue::UnaryOp(_ /*un_op*/, ref operand)
|
||||
|
|
|
@ -1233,6 +1233,31 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
|||
);
|
||||
}
|
||||
|
||||
|
||||
Rvalue::AddressOf(mutability, ref place) => {
|
||||
let access_kind = match mutability {
|
||||
Mutability::Mut => (Deep, Write(WriteKind::MutableBorrow(BorrowKind::Mut {
|
||||
allow_two_phase_borrow: false,
|
||||
}))),
|
||||
Mutability::Not => (Deep, Read(ReadKind::Borrow(BorrowKind::Shared))),
|
||||
};
|
||||
|
||||
self.access_place(
|
||||
location,
|
||||
(place, span),
|
||||
access_kind,
|
||||
LocalMutationIsAllowed::No,
|
||||
flow_state,
|
||||
);
|
||||
|
||||
self.check_if_path_or_subpath_is_moved(
|
||||
location,
|
||||
InitializationRequiringAction::Borrow,
|
||||
(place.as_ref(), span),
|
||||
flow_state,
|
||||
);
|
||||
}
|
||||
|
||||
Rvalue::Use(ref operand)
|
||||
| Rvalue::Repeat(ref operand, _)
|
||||
| Rvalue::UnaryOp(_ /*un_op*/, ref operand)
|
||||
|
|
|
@ -2273,41 +2273,6 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
|
|||
let cast_ty_from = CastTy::from_ty(ty_from);
|
||||
let cast_ty_to = CastTy::from_ty(ty);
|
||||
match (cast_ty_from, cast_ty_to) {
|
||||
(Some(CastTy::RPtr(ref_tm)), Some(CastTy::Ptr(ptr_tm))) => {
|
||||
if let hir::Mutability::Mutable = ptr_tm.mutbl {
|
||||
if let Err(terr) = self.eq_types(
|
||||
ref_tm.ty,
|
||||
ptr_tm.ty,
|
||||
location.to_locations(),
|
||||
ConstraintCategory::Cast,
|
||||
) {
|
||||
span_mirbug!(
|
||||
self,
|
||||
rvalue,
|
||||
"equating {:?} with {:?} yields {:?}",
|
||||
ref_tm.ty,
|
||||
ptr_tm.ty,
|
||||
terr
|
||||
)
|
||||
}
|
||||
} else {
|
||||
if let Err(terr) = self.sub_types(
|
||||
ref_tm.ty,
|
||||
ptr_tm.ty,
|
||||
location.to_locations(),
|
||||
ConstraintCategory::Cast,
|
||||
) {
|
||||
span_mirbug!(
|
||||
self,
|
||||
rvalue,
|
||||
"relating {:?} with {:?} yields {:?}",
|
||||
ref_tm.ty,
|
||||
ptr_tm.ty,
|
||||
terr
|
||||
)
|
||||
}
|
||||
}
|
||||
},
|
||||
(None, _)
|
||||
| (_, None)
|
||||
| (_, Some(CastTy::FnPtr))
|
||||
|
@ -2320,7 +2285,15 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
|
|||
ty_from,
|
||||
ty,
|
||||
),
|
||||
_ => (),
|
||||
(Some(CastTy::Int(_)), Some(CastTy::Int(_)))
|
||||
| (Some(CastTy::Float), Some(CastTy::Int(_)))
|
||||
| (Some(CastTy::Int(_)), Some(CastTy::Float))
|
||||
| (Some(CastTy::Float), Some(CastTy::Float))
|
||||
| (Some(CastTy::Ptr(_)), Some(CastTy::Int(_)))
|
||||
| (Some(CastTy::FnPtr), Some(CastTy::Int(_)))
|
||||
| (Some(CastTy::Int(_)), Some(CastTy::Ptr(_)))
|
||||
| (Some(CastTy::Ptr(_)), Some(CastTy::Ptr(_)))
|
||||
| (Some(CastTy::FnPtr), Some(CastTy::Ptr(_))) => (),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -2371,7 +2344,8 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
|
|||
}
|
||||
}
|
||||
|
||||
Rvalue::Use(..)
|
||||
Rvalue::AddressOf(..)
|
||||
| Rvalue::Use(..)
|
||||
| Rvalue::Len(..)
|
||||
| Rvalue::BinaryOp(..)
|
||||
| Rvalue::CheckedBinaryOp(..)
|
||||
|
@ -2388,6 +2362,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
|
|||
Rvalue::Use(_)
|
||||
| Rvalue::Repeat(..)
|
||||
| Rvalue::Ref(..)
|
||||
| Rvalue::AddressOf(..)
|
||||
| Rvalue::Len(..)
|
||||
| Rvalue::Cast(..)
|
||||
| Rvalue::BinaryOp(..)
|
||||
|
|
|
@ -335,6 +335,7 @@ impl<'b, 'a, 'tcx> Gatherer<'b, 'a, 'tcx> {
|
|||
}
|
||||
}
|
||||
Rvalue::Ref(..)
|
||||
| Rvalue::AddressOf(..)
|
||||
| Rvalue::Discriminant(..)
|
||||
| Rvalue::Len(..)
|
||||
| Rvalue::NullaryOp(NullOp::SizeOf, _)
|
||||
|
|
|
@ -248,7 +248,7 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
|
|||
)?;
|
||||
}
|
||||
|
||||
Ref(_, _, ref place) => {
|
||||
AddressOf(_, ref place) | Ref(_, _, ref place) => {
|
||||
let src = self.eval_place(place)?;
|
||||
let place = self.force_allocation(src)?;
|
||||
if place.layout.size.bytes() > 0 {
|
||||
|
|
|
@ -136,21 +136,9 @@ impl<'tcx> MirPass<'tcx> for AddRetag {
|
|||
// iterate backwards using indices.
|
||||
for i in (0..block_data.statements.len()).rev() {
|
||||
let (retag_kind, place) = match block_data.statements[i].kind {
|
||||
// If we are casting *from* a reference, we may have to retag-as-raw.
|
||||
StatementKind::Assign(box(ref place, Rvalue::Cast(
|
||||
CastKind::Misc,
|
||||
ref src,
|
||||
dest_ty,
|
||||
))) => {
|
||||
let src_ty = src.ty(&*local_decls, tcx);
|
||||
if src_ty.is_region_ptr() {
|
||||
// The only `Misc` casts on references are those creating raw pointers.
|
||||
assert!(dest_ty.is_unsafe_ptr());
|
||||
(RetagKind::Raw, place.clone())
|
||||
} else {
|
||||
// Some other cast, no retag
|
||||
continue
|
||||
}
|
||||
// Retag-as-raw after escaping to a raw pointer.
|
||||
StatementKind::Assign(box (ref place, Rvalue::AddressOf(..))) => {
|
||||
(RetagKind::Raw, place.clone())
|
||||
}
|
||||
// Assignments of reference or ptr type are the ones where we may have
|
||||
// to update tags. This includes `x = &[mut] ...` and hence
|
||||
|
|
|
@ -224,6 +224,23 @@ impl NonConstOp for MutBorrow {
|
|||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct MutAddressOf;
|
||||
impl NonConstOp for MutAddressOf {
|
||||
fn feature_gate(tcx: TyCtxt<'_>) -> Option<bool> {
|
||||
Some(tcx.features().const_mut_refs)
|
||||
}
|
||||
|
||||
fn emit_error(&self, item: &Item<'_, '_>, span: Span) {
|
||||
feature_err(
|
||||
&item.tcx.sess.parse_sess,
|
||||
sym::const_mut_refs,
|
||||
span,
|
||||
&format!("`&raw mut` is not allowed in {}s", item.const_kind())
|
||||
).emit();
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct MutDeref;
|
||||
impl NonConstOp for MutDeref {
|
||||
|
|
|
@ -151,17 +151,15 @@ pub trait Qualif {
|
|||
Self::in_operand(cx, per_local, lhs) || Self::in_operand(cx, per_local, rhs)
|
||||
}
|
||||
|
||||
Rvalue::Ref(_, _, ref place) => {
|
||||
Rvalue::Ref(_, _, ref place) | Rvalue::AddressOf(_, ref place) => {
|
||||
// Special-case reborrows to be more like a copy of the reference.
|
||||
if let &[ref proj_base @ .., elem] = place.projection.as_ref() {
|
||||
if ProjectionElem::Deref == elem {
|
||||
let base_ty = Place::ty_from(&place.base, proj_base, *cx.body, cx.tcx).ty;
|
||||
if let ty::Ref(..) = base_ty.kind {
|
||||
return Self::in_place(cx, per_local, PlaceRef {
|
||||
base: &place.base,
|
||||
projection: proj_base,
|
||||
});
|
||||
}
|
||||
if let [proj_base @ .., ProjectionElem::Deref] = place.projection.as_ref() {
|
||||
let base_ty = Place::ty_from(&place.base, proj_base, *cx.body, cx.tcx).ty;
|
||||
if let ty::Ref(..) = base_ty.kind {
|
||||
return Self::in_place(cx, per_local, PlaceRef {
|
||||
base: &place.base,
|
||||
projection: proj_base,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -276,6 +276,27 @@ impl Validator<'a, 'mir, 'tcx> {
|
|||
self.check_op_spanned(ops::StaticAccess, span)
|
||||
}
|
||||
}
|
||||
|
||||
fn check_immutable_borrow_like(
|
||||
&mut self,
|
||||
location: Location,
|
||||
place: &Place<'tcx>,
|
||||
) {
|
||||
// FIXME: Change the `in_*` methods to take a `FnMut` so we don't have to manually
|
||||
// seek the cursors beforehand.
|
||||
self.qualifs.has_mut_interior.cursor.seek_before(location);
|
||||
self.qualifs.indirectly_mutable.seek(location);
|
||||
|
||||
let borrowed_place_has_mut_interior = HasMutInterior::in_place(
|
||||
&self.item,
|
||||
&|local| self.qualifs.has_mut_interior_eager_seek(local),
|
||||
place.as_ref(),
|
||||
);
|
||||
|
||||
if borrowed_place_has_mut_interior {
|
||||
self.check_op(ops::CellBorrow);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Visitor<'tcx> for Validator<'_, 'mir, 'tcx> {
|
||||
|
@ -302,26 +323,44 @@ impl Visitor<'tcx> for Validator<'_, 'mir, 'tcx> {
|
|||
trace!("visit_rvalue: rvalue={:?} location={:?}", rvalue, location);
|
||||
|
||||
// Special-case reborrows to be more like a copy of a reference.
|
||||
if let Rvalue::Ref(_, kind, ref place) = *rvalue {
|
||||
if let Some(reborrowed_proj) = place_as_reborrow(self.tcx, *self.body, place) {
|
||||
let ctx = match kind {
|
||||
BorrowKind::Shared => PlaceContext::NonMutatingUse(
|
||||
NonMutatingUseContext::SharedBorrow,
|
||||
),
|
||||
BorrowKind::Shallow => PlaceContext::NonMutatingUse(
|
||||
NonMutatingUseContext::ShallowBorrow,
|
||||
),
|
||||
BorrowKind::Unique => PlaceContext::NonMutatingUse(
|
||||
NonMutatingUseContext::UniqueBorrow,
|
||||
),
|
||||
BorrowKind::Mut { .. } => PlaceContext::MutatingUse(
|
||||
MutatingUseContext::Borrow,
|
||||
),
|
||||
};
|
||||
self.visit_place_base(&place.base, ctx, location);
|
||||
self.visit_projection(&place.base, reborrowed_proj, ctx, location);
|
||||
return;
|
||||
match *rvalue {
|
||||
Rvalue::Ref(_, kind, ref place) => {
|
||||
if let Some(reborrowed_proj) = place_as_reborrow(self.tcx, *self.body, place) {
|
||||
let ctx = match kind {
|
||||
BorrowKind::Shared => PlaceContext::NonMutatingUse(
|
||||
NonMutatingUseContext::SharedBorrow,
|
||||
),
|
||||
BorrowKind::Shallow => PlaceContext::NonMutatingUse(
|
||||
NonMutatingUseContext::ShallowBorrow,
|
||||
),
|
||||
BorrowKind::Unique => PlaceContext::NonMutatingUse(
|
||||
NonMutatingUseContext::UniqueBorrow,
|
||||
),
|
||||
BorrowKind::Mut { .. } => PlaceContext::MutatingUse(
|
||||
MutatingUseContext::Borrow,
|
||||
),
|
||||
};
|
||||
self.visit_place_base(&place.base, ctx, location);
|
||||
self.visit_projection(&place.base, reborrowed_proj, ctx, location);
|
||||
return;
|
||||
}
|
||||
}
|
||||
Rvalue::AddressOf(mutbl, ref place) => {
|
||||
if let Some(reborrowed_proj) = place_as_reborrow(self.tcx, *self.body, place) {
|
||||
let ctx = match mutbl {
|
||||
Mutability::Not => PlaceContext::NonMutatingUse(
|
||||
NonMutatingUseContext::AddressOf,
|
||||
),
|
||||
Mutability::Mut => PlaceContext::MutatingUse(
|
||||
MutatingUseContext::AddressOf,
|
||||
),
|
||||
};
|
||||
self.visit_place_base(&place.base, ctx, location);
|
||||
self.visit_projection(&place.base, reborrowed_proj, ctx, location);
|
||||
return;
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
|
||||
self.super_rvalue(rvalue, location);
|
||||
|
@ -367,34 +406,25 @@ impl Visitor<'tcx> for Validator<'_, 'mir, 'tcx> {
|
|||
}
|
||||
}
|
||||
|
||||
Rvalue::AddressOf(Mutability::Mut, _) => {
|
||||
self.check_op(ops::MutAddressOf)
|
||||
}
|
||||
|
||||
// At the moment, `PlaceBase::Static` is only used for promoted MIR.
|
||||
| Rvalue::Ref(_, BorrowKind::Shared, ref place)
|
||||
| Rvalue::Ref(_, BorrowKind::Shallow, ref place)
|
||||
| Rvalue::AddressOf(Mutability::Not, ref place)
|
||||
if matches!(place.base, PlaceBase::Static(_))
|
||||
=> bug!("Saw a promoted during const-checking, which must run before promotion"),
|
||||
|
||||
| Rvalue::Ref(_, kind @ BorrowKind::Shared, ref place)
|
||||
| Rvalue::Ref(_, kind @ BorrowKind::Shallow, ref place)
|
||||
=> {
|
||||
// FIXME: Change the `in_*` methods to take a `FnMut` so we don't have to manually
|
||||
// seek the cursors beforehand.
|
||||
self.qualifs.has_mut_interior.cursor.seek_before(location);
|
||||
self.qualifs.indirectly_mutable.seek(location);
|
||||
| Rvalue::Ref(_, BorrowKind::Shared, ref place)
|
||||
| Rvalue::Ref(_, BorrowKind::Shallow, ref place) => {
|
||||
self.check_immutable_borrow_like(location, place)
|
||||
},
|
||||
|
||||
let borrowed_place_has_mut_interior = HasMutInterior::in_place(
|
||||
&self.item,
|
||||
&|local| self.qualifs.has_mut_interior_eager_seek(local),
|
||||
place.as_ref(),
|
||||
);
|
||||
|
||||
if borrowed_place_has_mut_interior {
|
||||
if let BorrowKind::Mut{ .. } = kind {
|
||||
self.check_op(ops::MutBorrow);
|
||||
} else {
|
||||
self.check_op(ops::CellBorrow);
|
||||
}
|
||||
}
|
||||
}
|
||||
Rvalue::AddressOf(Mutability::Not, ref place) => {
|
||||
self.check_immutable_borrow_like(location, place)
|
||||
},
|
||||
|
||||
Rvalue::Cast(CastKind::Misc, ref operand, cast_ty) => {
|
||||
let operand_ty = operand.ty(*self.body, self.tcx);
|
||||
|
|
|
@ -196,7 +196,12 @@ impl<'tcx> Visitor<'tcx> for Collector<'_, 'tcx> {
|
|||
} else if let TempState::Defined { ref mut uses, .. } = *temp {
|
||||
// We always allow borrows, even mutable ones, as we need
|
||||
// to promote mutable borrows of some ZSTs e.g., `&mut []`.
|
||||
let allowed_use = context.is_borrow() || context.is_nonmutating_use();
|
||||
let allowed_use = match context {
|
||||
PlaceContext::MutatingUse(MutatingUseContext::Borrow)
|
||||
| PlaceContext::NonMutatingUse(_) => true,
|
||||
PlaceContext::MutatingUse(_)
|
||||
| PlaceContext::NonUse(_) => false,
|
||||
};
|
||||
debug!("visit_local: allowed_use={:?}", allowed_use);
|
||||
if allowed_use {
|
||||
*uses += 1;
|
||||
|
@ -618,6 +623,21 @@ impl<'tcx> Validator<'_, 'tcx> {
|
|||
self.validate_operand(rhs)
|
||||
}
|
||||
|
||||
Rvalue::AddressOf(_, place) => {
|
||||
// Raw reborrows can come from reference to pointer coercions,
|
||||
// so are allowed.
|
||||
if let [proj_base @ .., ProjectionElem::Deref] = place.projection.as_ref() {
|
||||
let base_ty = Place::ty_from(&place.base, proj_base, *self.body, self.tcx).ty;
|
||||
if let ty::Ref(..) = base_ty.kind {
|
||||
return self.validate_place(PlaceRef {
|
||||
base: &place.base,
|
||||
projection: proj_base,
|
||||
});
|
||||
}
|
||||
}
|
||||
Err(Unpromotable)
|
||||
}
|
||||
|
||||
Rvalue::Ref(_, kind, place) => {
|
||||
if let BorrowKind::Mut { .. } = kind {
|
||||
let ty = place.ty(*self.body, self.tcx).ty;
|
||||
|
@ -950,7 +970,7 @@ impl<'a, 'tcx> Promoter<'a, 'tcx> {
|
|||
Candidate::Ref(loc) => {
|
||||
let ref mut statement = blocks[loc.block].statements[loc.statement_index];
|
||||
match statement.kind {
|
||||
StatementKind::Assign(box(_, Rvalue::Ref(_, _, ref mut place))) => {
|
||||
StatementKind::Assign(box (_, Rvalue::Ref(_, _, ref mut place))) => {
|
||||
// Use the underlying local for this (necessarily interior) borrow.
|
||||
let ty = place.base.ty(local_decls).ty;
|
||||
let span = statement.source_info.span;
|
||||
|
|
|
@ -135,7 +135,10 @@ fn check_rvalue(
|
|||
Rvalue::Repeat(operand, _) | Rvalue::Use(operand) => {
|
||||
check_operand(tcx, operand, span, def_id, body)
|
||||
}
|
||||
Rvalue::Len(place) | Rvalue::Discriminant(place) | Rvalue::Ref(_, _, place) => {
|
||||
Rvalue::Len(place)
|
||||
| Rvalue::Discriminant(place)
|
||||
| Rvalue::Ref(_, _, place)
|
||||
| Rvalue::AddressOf(_, place) => {
|
||||
check_place(tcx, place, span, def_id, body)
|
||||
}
|
||||
Rvalue::Cast(CastKind::Misc, operand, cast_ty) => {
|
||||
|
@ -147,9 +150,6 @@ fn check_rvalue(
|
|||
span,
|
||||
"casting pointers to ints is unstable in const fn".into(),
|
||||
)),
|
||||
(CastTy::RPtr(_), CastTy::Float) => bug!(),
|
||||
(CastTy::RPtr(_), CastTy::Int(_)) => bug!(),
|
||||
(CastTy::Ptr(_), CastTy::RPtr(_)) => bug!(),
|
||||
_ => check_operand(tcx, operand, span, def_id, body),
|
||||
}
|
||||
}
|
||||
|
|
|
@ -167,6 +167,8 @@ pub fn categorize(context: PlaceContext) -> Option<DefUse> {
|
|||
PlaceContext::NonMutatingUse(NonMutatingUseContext::ShallowBorrow) |
|
||||
PlaceContext::NonMutatingUse(NonMutatingUseContext::UniqueBorrow) |
|
||||
|
||||
PlaceContext::MutatingUse(MutatingUseContext::AddressOf) |
|
||||
PlaceContext::NonMutatingUse(NonMutatingUseContext::AddressOf) |
|
||||
PlaceContext::NonMutatingUse(NonMutatingUseContext::Inspect) |
|
||||
PlaceContext::NonMutatingUse(NonMutatingUseContext::Copy) |
|
||||
PlaceContext::NonMutatingUse(NonMutatingUseContext::Move) |
|
||||
|
|
|
@ -469,22 +469,48 @@ impl<'a, 'tcx> CastCheck<'tcx> {
|
|||
(Some(t_from), Some(t_cast)) => (t_from, t_cast),
|
||||
// Function item types may need to be reified before casts.
|
||||
(None, Some(t_cast)) => {
|
||||
if let ty::FnDef(..) = self.expr_ty.kind {
|
||||
// Attempt a coercion to a fn pointer type.
|
||||
let f = self.expr_ty.fn_sig(fcx.tcx);
|
||||
let res = fcx.try_coerce(self.expr,
|
||||
self.expr_ty,
|
||||
fcx.tcx.mk_fn_ptr(f),
|
||||
AllowTwoPhase::No);
|
||||
if let Err(TypeError::IntrinsicCast) = res {
|
||||
return Err(CastError::IllegalCast);
|
||||
match self.expr_ty.kind {
|
||||
ty::FnDef(..) => {
|
||||
// Attempt a coercion to a fn pointer type.
|
||||
let f = self.expr_ty.fn_sig(fcx.tcx);
|
||||
let res = fcx.try_coerce(self.expr,
|
||||
self.expr_ty,
|
||||
fcx.tcx.mk_fn_ptr(f),
|
||||
AllowTwoPhase::No);
|
||||
if let Err(TypeError::IntrinsicCast) = res {
|
||||
return Err(CastError::IllegalCast);
|
||||
}
|
||||
if res.is_err() {
|
||||
return Err(CastError::NonScalar);
|
||||
}
|
||||
(FnPtr, t_cast)
|
||||
}
|
||||
if res.is_err() {
|
||||
return Err(CastError::NonScalar);
|
||||
// Special case some errors for references, and check for
|
||||
// array-ptr-casts. `Ref` is not a CastTy because the cast
|
||||
// is split into a coercion to a pointer type, followed by
|
||||
// a cast.
|
||||
ty::Ref(_, inner_ty, mutbl) => {
|
||||
return match t_cast {
|
||||
Int(_) | Float => match inner_ty.kind {
|
||||
ty::Int(_) |
|
||||
ty::Uint(_) |
|
||||
ty::Float(_) |
|
||||
ty::Infer(ty::InferTy::IntVar(_)) |
|
||||
ty::Infer(ty::InferTy::FloatVar(_)) => {
|
||||
Err(CastError::NeedDeref)
|
||||
}
|
||||
_ => Err(CastError::NeedViaPtr),
|
||||
}
|
||||
// array-ptr-cast
|
||||
Ptr(mt) => self.check_ref_cast(
|
||||
fcx,
|
||||
TypeAndMut { mutbl, ty: inner_ty },
|
||||
mt,
|
||||
),
|
||||
_ => Err(CastError::NonScalar),
|
||||
};
|
||||
}
|
||||
(FnPtr, t_cast)
|
||||
} else {
|
||||
return Err(CastError::NonScalar);
|
||||
_ => return Err(CastError::NonScalar),
|
||||
}
|
||||
}
|
||||
_ => return Err(CastError::NonScalar),
|
||||
|
@ -492,7 +518,7 @@ impl<'a, 'tcx> CastCheck<'tcx> {
|
|||
|
||||
match (t_from, t_cast) {
|
||||
// These types have invariants! can't cast into them.
|
||||
(_, RPtr(_)) | (_, Int(CEnum)) | (_, FnPtr) => Err(CastError::NonScalar),
|
||||
(_, Int(CEnum)) | (_, FnPtr) => Err(CastError::NonScalar),
|
||||
|
||||
// * -> Bool
|
||||
(_, Int(Bool)) => Err(CastError::CastToBool),
|
||||
|
@ -517,28 +543,10 @@ impl<'a, 'tcx> CastCheck<'tcx> {
|
|||
(Ptr(m_e), Ptr(m_c)) => self.check_ptr_ptr_cast(fcx, m_e, m_c), // ptr-ptr-cast
|
||||
(Ptr(m_expr), Int(_)) => self.check_ptr_addr_cast(fcx, m_expr), // ptr-addr-cast
|
||||
(FnPtr, Int(_)) => Ok(CastKind::FnPtrAddrCast),
|
||||
(RPtr(p), Int(_)) |
|
||||
(RPtr(p), Float) => {
|
||||
match p.ty.kind {
|
||||
ty::Int(_) |
|
||||
ty::Uint(_) |
|
||||
ty::Float(_) => {
|
||||
Err(CastError::NeedDeref)
|
||||
}
|
||||
ty::Infer(t) => {
|
||||
match t {
|
||||
ty::InferTy::IntVar(_) |
|
||||
ty::InferTy::FloatVar(_) => Err(CastError::NeedDeref),
|
||||
_ => Err(CastError::NeedViaPtr),
|
||||
}
|
||||
}
|
||||
_ => Err(CastError::NeedViaPtr),
|
||||
}
|
||||
}
|
||||
|
||||
// * -> ptr
|
||||
(Int(_), Ptr(mt)) => self.check_addr_ptr_cast(fcx, mt), // addr-ptr-cast
|
||||
(FnPtr, Ptr(mt)) => self.check_fptr_ptr_cast(fcx, mt),
|
||||
(RPtr(rmt), Ptr(mt)) => self.check_ref_cast(fcx, rmt, mt), // array-ptr-cast
|
||||
|
||||
// prim -> prim
|
||||
(Int(CEnum), Int(_)) => Ok(CastKind::EnumCast),
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue