1
Fork 0

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:
Matthew Jasper 2018-12-23 19:00:58 +00:00
parent 19bd934676
commit 3a19fbf95d
20 changed files with 306 additions and 168 deletions

View file

@ -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) => {

View file

@ -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) => {

View file

@ -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:
///

View file

@ -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,
}

View file

@ -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);
}

View file

@ -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: [],

View file

@ -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(..) |

View file

@ -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)

View file

@ -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)

View file

@ -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(..)

View file

@ -335,6 +335,7 @@ impl<'b, 'a, 'tcx> Gatherer<'b, 'a, 'tcx> {
}
}
Rvalue::Ref(..)
| Rvalue::AddressOf(..)
| Rvalue::Discriminant(..)
| Rvalue::Len(..)
| Rvalue::NullaryOp(NullOp::SizeOf, _)

View file

@ -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 {

View file

@ -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

View file

@ -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 {

View file

@ -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,
});
}
}

View file

@ -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);

View file

@ -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;

View file

@ -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),
}
}

View file

@ -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) |

View file

@ -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),