/// changing or disturbing program state.
#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash, RustcEncodable, HashStable)]
pub struct Place<'tcx> {
- pub base: PlaceBase,
+ pub local: Local,
/// projection out of a place (access a field, deref a pointer, etc)
pub projection: &'tcx List<PlaceElem<'tcx>>,
impl<'tcx> rustc_serialize::UseSpecializedDecodable for Place<'tcx> {}
-#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash, RustcEncodable, RustcDecodable, HashStable)]
-pub enum PlaceBase {
- /// local variable
- Local(Local),
-}
-
#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
#[derive(RustcEncodable, RustcDecodable, HashStable)]
pub enum ProjectionElem<V, T> {
#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct PlaceRef<'a, 'tcx> {
- pub base: &'a PlaceBase,
+ pub local: &'a Local,
pub projection: &'a [PlaceElem<'tcx>],
}
impl<'tcx> Place<'tcx> {
// FIXME change this to a const fn by also making List::empty a const fn.
pub fn return_place() -> Place<'tcx> {
- Place { base: PlaceBase::Local(RETURN_PLACE), projection: List::empty() }
+ Place { local: RETURN_PLACE, projection: List::empty() }
}
/// Returns `true` if this `Place` contains a `Deref` projection.
// FIXME: can we safely swap the semantics of `fn base_local` below in here instead?
pub fn local_or_deref_local(&self) -> Option<Local> {
match self.as_ref() {
- PlaceRef { base: &PlaceBase::Local(local), projection: &[] }
- | PlaceRef { base: &PlaceBase::Local(local), projection: &[ProjectionElem::Deref] } => {
- Some(local)
- }
+ PlaceRef { local, projection: &[] }
+ | PlaceRef { local, projection: &[ProjectionElem::Deref] } => Some(*local),
_ => None,
}
}
}
pub fn as_ref(&self) -> PlaceRef<'_, 'tcx> {
- PlaceRef { base: &self.base, projection: &self.projection }
+ PlaceRef { local: &self.local, projection: &self.projection }
}
}
impl From<Local> for Place<'_> {
fn from(local: Local) -> Self {
- Place { base: local.into(), projection: List::empty() }
- }
-}
-
-impl From<Local> for PlaceBase {
- fn from(local: Local) -> Self {
- PlaceBase::Local(local)
+ Place { local: local.into(), projection: List::empty() }
}
}
// FIXME: can we safely swap the semantics of `fn base_local` below in here instead?
pub fn local_or_deref_local(&self) -> Option<Local> {
match self {
- PlaceRef { base: PlaceBase::Local(local), projection: [] }
- | PlaceRef { base: PlaceBase::Local(local), projection: [ProjectionElem::Deref] } => {
- Some(*local)
- }
+ PlaceRef { local, projection: [] }
+ | PlaceRef { local, projection: [ProjectionElem::Deref] } => Some(**local),
_ => None,
}
}
/// projections, return `Some(_X)`.
pub fn as_local(&self) -> Option<Local> {
match self {
- PlaceRef { base: PlaceBase::Local(l), projection: [] } => Some(*l),
+ PlaceRef { local, projection: [] } => Some(**local),
_ => None,
}
}
}
}
- write!(fmt, "{:?}", self.base)?;
+ write!(fmt, "{:?}", self.local)?;
for elem in self.projection.iter() {
match elem {
}
}
-impl Debug for PlaceBase {
- fn fmt(&self, fmt: &mut Formatter<'_>) -> fmt::Result {
- match *self {
- PlaceBase::Local(id) => write!(fmt, "{:?}", id),
- }
- }
-}
-
///////////////////////////////////////////////////////////////////////////
// Scopes
impl<'tcx> TypeFoldable<'tcx> for Place<'tcx> {
fn super_fold_with<F: TypeFolder<'tcx>>(&self, folder: &mut F) -> Self {
- Place { base: self.base.fold_with(folder), projection: self.projection.fold_with(folder) }
+ Place { local: self.local.fold_with(folder), projection: self.projection.fold_with(folder) }
}
fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> bool {
- self.base.visit_with(visitor) || self.projection.visit_with(visitor)
- }
-}
-
-impl<'tcx> TypeFoldable<'tcx> for PlaceBase {
- fn super_fold_with<F: TypeFolder<'tcx>>(&self, folder: &mut F) -> Self {
- match self {
- PlaceBase::Local(local) => PlaceBase::Local(local.fold_with(folder)),
- }
- }
-
- fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> bool {
- match self {
- PlaceBase::Local(local) => local.visit_with(visitor),
- }
+ self.local.visit_with(visitor) || self.projection.visit_with(visitor)
}
}
impl<'tcx> Place<'tcx> {
pub fn ty_from<D>(
- base: &PlaceBase,
+ local: &Local,
projection: &[PlaceElem<'tcx>],
local_decls: &D,
tcx: TyCtxt<'tcx>,
{
projection
.iter()
- .fold(base.ty(local_decls), |place_ty, elem| place_ty.projection_ty(tcx, elem))
+ .fold(PlaceTy::from_ty(local_decls.local_decls()[*local].ty), |place_ty, elem| {
+ place_ty.projection_ty(tcx, elem)
+ })
}
pub fn ty<D>(&self, local_decls: &D, tcx: TyCtxt<'tcx>) -> PlaceTy<'tcx>
where
D: HasLocalDecls<'tcx>,
{
- Place::ty_from(&self.base, &self.projection, local_decls, tcx)
- }
-}
-
-impl<'tcx> PlaceBase {
- pub fn ty<D>(&self, local_decls: &D) -> PlaceTy<'tcx>
- where
- D: HasLocalDecls<'tcx>,
- {
- match self {
- PlaceBase::Local(index) => PlaceTy::from_ty(local_decls.local_decls()[*index].ty),
- }
+ Place::ty_from(&self.local, &self.projection, local_decls, tcx)
}
}
}
fn visit_place_base(&mut self,
- base: & $($mutability)? PlaceBase,
+ local: & $($mutability)? Local,
context: PlaceContext,
location: Location) {
- self.super_place_base(base, context, location);
+ self.super_place_base(local, context, location);
}
visit_place_fns!($($mutability)?);
}
fn super_place_base(&mut self,
- place_base: & $($mutability)? PlaceBase,
+ local: & $($mutability)? Local,
context: PlaceContext,
location: Location) {
- match place_base {
- PlaceBase::Local(local) => {
- self.visit_local(local, context, location);
- }
- }
+ self.visit_local(local, context, location);
}
fn super_local_decl(&mut self,
context: PlaceContext,
location: Location,
) {
- self.visit_place_base(&mut place.base, context, location);
+ self.visit_place_base(&mut place.local, context, location);
if let Some(new_projection) = self.process_projection(&place.projection) {
place.projection = self.tcx().intern_place_elems(&new_projection);
() => (
fn visit_projection(
&mut self,
- base: &PlaceBase,
+ local: &Local,
projection: &[PlaceElem<'tcx>],
context: PlaceContext,
location: Location,
) {
- self.super_projection(base, projection, context, location);
+ self.super_projection(local, projection, context, location);
}
fn visit_projection_elem(
&mut self,
- base: &PlaceBase,
+ local: &Local,
proj_base: &[PlaceElem<'tcx>],
elem: &PlaceElem<'tcx>,
context: PlaceContext,
location: Location,
) {
- self.super_projection_elem(base, proj_base, elem, context, location);
+ self.super_projection_elem(local, proj_base, elem, context, location);
}
fn super_place(
};
}
- self.visit_place_base(&place.base, context, location);
+ self.visit_place_base(&place.local, context, location);
- self.visit_projection(&place.base,
+ self.visit_projection(&place.local,
&place.projection,
context,
location);
fn super_projection(
&mut self,
- base: &PlaceBase,
+ local: &Local,
projection: &[PlaceElem<'tcx>],
context: PlaceContext,
location: Location,
let mut cursor = projection;
while let [proj_base @ .., elem] = cursor {
cursor = proj_base;
- self.visit_projection_elem(base, cursor, elem, context, location);
+ self.visit_projection_elem(local, cursor, elem, context, location);
}
}
fn super_projection_elem(
&mut self,
- _base: &PlaceBase,
+ _local: &Local,
_proj_base: &[PlaceElem<'tcx>],
elem: &PlaceElem<'tcx>,
_context: PlaceContext,
where
D: TyDecoder<'tcx>,
{
- let base: mir::PlaceBase = Decodable::decode(decoder)?;
+ let local: mir::Local = Decodable::decode(decoder)?;
let len = decoder.read_usize()?;
let projection: &'tcx List<mir::PlaceElem<'tcx>> =
decoder.tcx().mk_place_elems((0..len).map(|_| Decodable::decode(decoder)))?;
- Ok(mir::Place { base, projection })
+ Ok(mir::Place { local, projection })
}
#[inline]
let mut projection = place.projection.to_vec();
projection.push(elem);
- Place { base: place.base, projection: self.intern_place_elems(&projection) }
+ Place { local: place.local, projection: self.intern_place_elems(&projection) }
}
pub fn intern_existential_predicates(
let generator_layout = body.generator_layout.as_ref().unwrap();
let mut generator_saved_local_names = IndexVec::from_elem(None, &generator_layout.field_tys);
- let state_arg = mir::PlaceBase::Local(mir::Local::new(1));
+ let state_arg = mir::Local::new(1);
for var in &body.var_debug_info {
- if var.place.base != state_arg {
+ if var.place.local != state_arg {
continue;
}
match var.place.projection[..] {
};
if is_consume {
let base_ty =
- mir::Place::ty_from(place_ref.base, proj_base, *self.fx.mir, cx.tcx());
+ mir::Place::ty_from(place_ref.local, proj_base, *self.fx.mir, cx.tcx());
let base_ty = self.fx.monomorphize(&base_ty);
// ZSTs don't require any actual memory access.
let elem_ty = base_ty.projection_ty(cx.tcx(), elem).ty;
let elem_ty = self.fx.monomorphize(&elem_ty);
- let span = match place_ref.base {
- mir::PlaceBase::Local(index) => {
- self.fx.mir.local_decls[*index].source_info.span
- }
- };
+ let span = self.fx.mir.local_decls[*place_ref.local].source_info.span;
if cx.spanned_layout_of(elem_ty, span).is_zst() {
return;
}
// We use `NonUseContext::VarDebugInfo` for the base,
// which might not force the base local to memory,
// so we have to do it manually.
- match place_ref.base {
- mir::PlaceBase::Local(local) => self.visit_local(&local, context, location),
- }
+ self.visit_local(place_ref.local, context, location);
}
}
}
self.process_place(
- &mir::PlaceRef { base: place_ref.base, projection: proj_base },
+ &mir::PlaceRef { local: place_ref.local, projection: proj_base },
base_context,
location,
);
};
}
- self.visit_place_base(place_ref.base, context, location);
- self.visit_projection(place_ref.base, place_ref.projection, context, location);
+ self.visit_place_base(place_ref.local, context, location);
+ self.visit_projection(place_ref.local, place_ref.projection, context, location);
}
}
}
} else {
self.codegen_place(
bx,
- &mir::PlaceRef { base: &dest.base, projection: &dest.projection },
+ &mir::PlaceRef { local: &dest.local, projection: &dest.projection },
)
};
if fn_ret.is_indirect() {
if tcx.sess.opts.debuginfo == DebugInfo::Full || !tcx.sess.fewer_names() {
let mut per_local = IndexVec::from_elem(vec![], &body.local_decls);
for var in &body.var_debug_info {
- match var.place.base {
- mir::PlaceBase::Local(local) => per_local[local].push(var),
- }
+ per_local[var.place.local].push(var);
}
Some(per_local)
} else {
) -> Option<OperandRef<'tcx, Bx::Value>> {
debug!("maybe_codegen_consume_direct(place_ref={:?})", place_ref);
- match place_ref.base {
- mir::PlaceBase::Local(index) => {
- match self.locals[*index] {
- LocalRef::Operand(Some(mut o)) => {
- // Moves out of scalar and scalar pair fields are trivial.
- for elem in place_ref.projection.iter() {
- match elem {
- mir::ProjectionElem::Field(ref f, _) => {
- o = o.extract_field(bx, f.index());
- }
- mir::ProjectionElem::Index(_)
- | mir::ProjectionElem::ConstantIndex { .. } => {
- // ZSTs don't require any actual memory access.
- // FIXME(eddyb) deduplicate this with the identical
- // checks in `codegen_consume` and `extract_field`.
- let elem = o.layout.field(bx.cx(), 0);
- if elem.is_zst() {
- o = OperandRef::new_zst(bx, elem);
- } else {
- return None;
- }
- }
- _ => return None,
+ match self.locals[*place_ref.local] {
+ LocalRef::Operand(Some(mut o)) => {
+ // Moves out of scalar and scalar pair fields are trivial.
+ for elem in place_ref.projection.iter() {
+ match elem {
+ mir::ProjectionElem::Field(ref f, _) => {
+ o = o.extract_field(bx, f.index());
+ }
+ mir::ProjectionElem::Index(_)
+ | mir::ProjectionElem::ConstantIndex { .. } => {
+ // ZSTs don't require any actual memory access.
+ // FIXME(eddyb) deduplicate this with the identical
+ // checks in `codegen_consume` and `extract_field`.
+ let elem = o.layout.field(bx.cx(), 0);
+ if elem.is_zst() {
+ o = OperandRef::new_zst(bx, elem);
+ } else {
+ return None;
}
}
-
- Some(o)
- }
- LocalRef::Operand(None) => {
- bug!("use of {:?} before def", place_ref);
- }
- LocalRef::Place(..) | LocalRef::UnsizedPlace(..) => {
- // watch out for locals that do not have an
- // alloca; they are handled somewhat differently
- None
+ _ => return None,
}
}
+
+ Some(o)
+ }
+ LocalRef::Operand(None) => {
+ bug!("use of {:?} before def", place_ref);
+ }
+ LocalRef::Place(..) | LocalRef::UnsizedPlace(..) => {
+ // watch out for locals that do not have an
+ // alloca; they are handled somewhat differently
+ None
}
}
}
let tcx = self.cx.tcx();
let result = match place_ref {
- mir::PlaceRef { base: mir::PlaceBase::Local(index), projection: [] } => {
- match self.locals[*index] {
- LocalRef::Place(place) => {
- return place;
- }
- LocalRef::UnsizedPlace(place) => {
- return bx.load_operand(place).deref(cx);
- }
- LocalRef::Operand(..) => {
- bug!("using operand local {:?} as place", place_ref);
- }
+ mir::PlaceRef { local, projection: [] } => match self.locals[**local] {
+ LocalRef::Place(place) => {
+ return place;
}
- }
- mir::PlaceRef { base, projection: [proj_base @ .., mir::ProjectionElem::Deref] } => {
+ LocalRef::UnsizedPlace(place) => {
+ return bx.load_operand(place).deref(cx);
+ }
+ LocalRef::Operand(..) => {
+ bug!("using operand local {:?} as place", place_ref);
+ }
+ },
+ mir::PlaceRef { local, projection: [proj_base @ .., mir::ProjectionElem::Deref] } => {
// Load the pointer from its location.
- self.codegen_consume(bx, &mir::PlaceRef { base, projection: proj_base })
+ self.codegen_consume(bx, &mir::PlaceRef { local, projection: proj_base })
.deref(bx.cx())
}
- mir::PlaceRef { base, projection: [proj_base @ .., elem] } => {
+ mir::PlaceRef { local, projection: [proj_base @ .., elem] } => {
// FIXME turn this recursion into iteration
let cg_base =
- self.codegen_place(bx, &mir::PlaceRef { base, projection: proj_base });
+ self.codegen_place(bx, &mir::PlaceRef { local, projection: proj_base });
match elem {
mir::ProjectionElem::Deref => bug!(),
pub fn monomorphized_place_ty(&self, place_ref: &mir::PlaceRef<'_, 'tcx>) -> Ty<'tcx> {
let tcx = self.cx.tcx();
- let place_ty = mir::Place::ty_from(place_ref.base, place_ref.projection, *self.mir, tcx);
+ let place_ty = mir::Place::ty_from(place_ref.local, place_ref.projection, *self.mir, tcx);
self.monomorphize(&place_ty.ty)
}
}
self.insert_as_pending_if_two_phase(location, &assigned_place, kind, idx);
- match borrowed_place.base {
- mir::PlaceBase::Local(local) => {
- self.local_map.entry(local).or_default().insert(idx);
- }
- }
+ self.local_map.entry(borrowed_place.local).or_default().insert(idx);
}
self.super_assign(assigned_place, rvalue, location)
use rustc::mir::visit::TyContext;
use rustc::mir::visit::Visitor;
use rustc::mir::{
- BasicBlock, BasicBlockData, Body, Local, Location, Place, PlaceBase, PlaceRef, ProjectionElem,
- Rvalue, SourceInfo, Statement, StatementKind, Terminator, TerminatorKind, UserTypeProjection,
+ BasicBlock, BasicBlockData, Body, Local, Location, Place, PlaceRef, ProjectionElem, Rvalue,
+ SourceInfo, Statement, StatementKind, Terminator, TerminatorKind, UserTypeProjection,
};
use rustc::ty::fold::TypeFoldable;
use rustc::ty::subst::SubstsRef;
// of the borrows are killed: the ones whose `borrowed_place`
// conflicts with the `place`.
match place.as_ref() {
- PlaceRef { base: &PlaceBase::Local(local), projection: &[] }
- | PlaceRef {
- base: &PlaceBase::Local(local),
- projection: &[ProjectionElem::Deref],
- } => {
+ PlaceRef { local, projection: &[] }
+ | PlaceRef { local, projection: &[ProjectionElem::Deref] } => {
debug!(
"Recording `killed` facts for borrows of local={:?} at location={:?}",
local, location
all_facts,
self.borrow_set,
self.location_table,
- &local,
+ local,
location,
);
}
- PlaceRef { base: &PlaceBase::Local(local), projection: &[.., _] } => {
+ PlaceRef { local, projection: &[.., _] } => {
// Kill conflicting borrows of the innermost local.
debug!(
"Recording `killed` facts for borrows of \
local, location
);
- if let Some(borrow_indices) = self.borrow_set.local_map.get(&local) {
+ if let Some(borrow_indices) = self.borrow_set.local_map.get(local) {
for &borrow_index in borrow_indices {
let places_conflict = places_conflict::places_conflict(
self.infcx.tcx,
use rustc::mir::{
self, AggregateKind, BindingForm, BorrowKind, ClearCrossCrate, ConstraintCategory,
- FakeReadCause, Local, LocalDecl, LocalInfo, LocalKind, Location, Operand, Place, PlaceBase,
- PlaceRef, ProjectionElem, Rvalue, Statement, StatementKind, TerminatorKind, VarBindingForm,
+ FakeReadCause, Local, LocalDecl, LocalInfo, LocalKind, Location, Operand, Place, PlaceRef,
+ ProjectionElem, Rvalue, Statement, StatementKind, TerminatorKind, VarBindingForm,
};
use rustc::traits::error_reporting::suggest_constraining_type_param;
use rustc::ty::{self, Ty};
}
let ty =
- Place::ty_from(used_place.base, used_place.projection, *self.body, self.infcx.tcx)
+ Place::ty_from(used_place.local, used_place.projection, *self.body, self.infcx.tcx)
.ty;
let needs_note = match ty.kind {
ty::Closure(id, _) => {
// field access to a union. If we find that, then we will keep the place of the
// union being accessed and the field that was being accessed so we can check the
// second borrowed place for the same union and a access to a different field.
- let Place { base, projection } = first_borrowed_place;
+ let Place { local, projection } = first_borrowed_place;
let mut cursor = projection.as_ref();
while let [proj_base @ .., elem] = cursor {
cursor = proj_base;
match elem {
- ProjectionElem::Field(field, _) if union_ty(base, proj_base).is_some() => {
- return Some((PlaceRef { base: base, projection: proj_base }, field));
+ ProjectionElem::Field(field, _) if union_ty(local, proj_base).is_some() => {
+ return Some((PlaceRef { local, projection: proj_base }, field));
}
_ => {}
}
.and_then(|(target_base, target_field)| {
// With the place of a union and a field access into it, we traverse the second
// borrowed place and look for a access to a different field of the same union.
- let Place { base, projection } = second_borrowed_place;
+ let Place { local, projection } = second_borrowed_place;
let mut cursor = projection.as_ref();
while let [proj_base @ .., elem] = cursor {
cursor = proj_base;
if let ProjectionElem::Field(field, _) = elem {
- if let Some(union_ty) = union_ty(base, proj_base) {
+ if let Some(union_ty) = union_ty(local, proj_base) {
if field != target_field
- && base == target_base.base
+ && local == target_base.local
&& proj_base == target_base.projection
{
// FIXME when we avoid clone reuse describe_place closure
let describe_base_place = self
- .describe_place(PlaceRef { base: base, projection: proj_base })
+ .describe_place(PlaceRef { local, projection: proj_base })
.unwrap_or_else(|| "_".to_owned());
return Some((
let borrow_span = borrow_spans.var_or_use();
assert!(root_place.projection.is_empty());
- let proper_span = match root_place.base {
- PlaceBase::Local(local) => self.body.local_decls[*local].source_info.span,
- };
+ let proper_span = self.body.local_decls[*root_place.local].source_info.span;
let root_place_projection = self.infcx.tcx.intern_place_elems(root_place.projection);
if self.access_place_error_reported.contains(&(
- Place { base: root_place.base.clone(), projection: root_place_projection },
+ Place { local: root_place.local.clone(), projection: root_place_projection },
borrow_span,
)) {
debug!(
}
self.access_place_error_reported.insert((
- Place { base: root_place.base.clone(), projection: root_place_projection },
+ Place { local: root_place.local.clone(), projection: root_place_projection },
borrow_span,
));
- match borrow.borrowed_place.base {
- PlaceBase::Local(local) => {
- if self.body.local_decls[local].is_ref_to_thread_local() {
- let err = self.report_thread_local_value_does_not_live_long_enough(
- drop_span,
- borrow_span,
- );
- err.buffer(&mut self.errors_buffer);
- return;
- }
- }
- };
+ let borrowed_local = borrow.borrowed_place.local;
+ if self.body.local_decls[borrowed_local].is_ref_to_thread_local() {
+ let err =
+ self.report_thread_local_value_does_not_live_long_enough(drop_span, borrow_span);
+ err.buffer(&mut self.errors_buffer);
+ return;
+ }
if let StorageDeadOrDrop::Destructor(dropped_ty) =
self.classify_drop_access_kind(borrow.borrowed_place.as_ref())
} else {
let root_place =
self.prefixes(borrow.borrowed_place.as_ref(), PrefixSet::All).last().unwrap();
- let local =
- if let PlaceRef { base: PlaceBase::Local(local), projection: [] } = root_place {
- local
- } else {
- bug!("try_report_cannot_return_reference_to_local: not a local")
- };
+ let local = root_place.local;
match self.body.local_kind(*local) {
LocalKind::ReturnPointer | LocalKind::Temp => {
("temporary value".to_string(), "temporary value created here".to_string())
[proj_base @ .., elem] => {
// FIXME(spastorino) make this iterate
let base_access = self.classify_drop_access_kind(PlaceRef {
- base: place.base,
+ local: place.local,
projection: proj_base,
});
match elem {
StorageDeadOrDrop::LocalStorageDead
| StorageDeadOrDrop::BoxedStorageDead => {
assert!(
- Place::ty_from(&place.base, proj_base, *self.body, tcx).ty.is_box(),
+ Place::ty_from(&place.local, proj_base, *self.body, tcx)
+ .ty
+ .is_box(),
"Drop of value behind a reference or raw pointer"
);
StorageDeadOrDrop::BoxedStorageDead
StorageDeadOrDrop::Destructor(_) => base_access,
},
ProjectionElem::Field(..) | ProjectionElem::Downcast(..) => {
- let base_ty = Place::ty_from(&place.base, proj_base, *self.body, tcx).ty;
+ let base_ty = Place::ty_from(&place.local, proj_base, *self.body, tcx).ty;
match base_ty.kind {
ty::Adt(def, _) if def.has_dtor(tcx) => {
// Report the outermost adt with a destructor
use rustc::mir::{
AggregateKind, Constant, Field, Local, LocalInfo, LocalKind, Location, Operand, Place,
- PlaceBase, PlaceRef, ProjectionElem, Rvalue, Statement, StatementKind, Terminator,
- TerminatorKind,
+ PlaceRef, ProjectionElem, Rvalue, Statement, StatementKind, Terminator, TerminatorKind,
};
use rustc::ty::layout::VariantIdx;
use rustc::ty::print::Print;
including_downcast: &IncludingDowncast,
) -> Result<(), ()> {
match place {
- PlaceRef { base: PlaceBase::Local(local), projection: [] } => {
+ PlaceRef { local, projection: [] } => {
self.append_local_to_string(*local, buf)?;
}
- PlaceRef { base: &PlaceBase::Local(local), projection: [ProjectionElem::Deref] }
- if self.body.local_decls[local].is_ref_for_guard() =>
+ PlaceRef { local, projection: [ProjectionElem::Deref] }
+ if self.body.local_decls[*local].is_ref_for_guard() =>
{
self.append_place_to_string(
- PlaceRef { base: &PlaceBase::Local(local), projection: &[] },
+ PlaceRef { local: local, projection: &[] },
buf,
autoderef,
&including_downcast,
)?;
}
- PlaceRef { base: &PlaceBase::Local(local), projection: [ProjectionElem::Deref] }
- if self.body.local_decls[local].is_ref_to_static() =>
+ PlaceRef { local, projection: [ProjectionElem::Deref] }
+ if self.body.local_decls[*local].is_ref_to_static() =>
{
- let local_info = &self.body.local_decls[local].local_info;
+ let local_info = &self.body.local_decls[*local].local_info;
if let LocalInfo::StaticRef { def_id, .. } = *local_info {
buf.push_str(&self.infcx.tcx.item_name(def_id).as_str());
} else {
unreachable!();
}
}
- PlaceRef { base, projection: [proj_base @ .., elem] } => {
+ PlaceRef { local, projection: [proj_base @ .., elem] } => {
match elem {
ProjectionElem::Deref => {
let upvar_field_projection = self.is_upvar_field_projection(place);
if autoderef {
// FIXME turn this recursion into iteration
self.append_place_to_string(
- PlaceRef { base, projection: proj_base },
+ PlaceRef { local, projection: proj_base },
buf,
autoderef,
&including_downcast,
)?;
} else {
- match (proj_base, base) {
- _ => {
- buf.push_str(&"*");
- self.append_place_to_string(
- PlaceRef { base, projection: proj_base },
- buf,
- autoderef,
- &including_downcast,
- )?;
- }
- }
+ buf.push_str(&"*");
+ self.append_place_to_string(
+ PlaceRef { local, projection: proj_base },
+ buf,
+ autoderef,
+ &including_downcast,
+ )?;
}
}
}
ProjectionElem::Downcast(..) => {
self.append_place_to_string(
- PlaceRef { base, projection: proj_base },
+ PlaceRef { local, projection: proj_base },
buf,
autoderef,
&including_downcast,
buf.push_str(&name);
} else {
let field_name = self
- .describe_field(PlaceRef { base, projection: proj_base }, *field);
+ .describe_field(PlaceRef { local, projection: proj_base }, *field);
self.append_place_to_string(
- PlaceRef { base, projection: proj_base },
+ PlaceRef { local, projection: proj_base },
buf,
autoderef,
&including_downcast,
autoderef = true;
self.append_place_to_string(
- PlaceRef { base, projection: proj_base },
+ PlaceRef { local, projection: proj_base },
buf,
autoderef,
&including_downcast,
// then use another while the borrow is held, don't output indices details
// to avoid confusing the end-user
self.append_place_to_string(
- PlaceRef { base, projection: proj_base },
+ PlaceRef { local, projection: proj_base },
buf,
autoderef,
&including_downcast,
fn describe_field(&self, place: PlaceRef<'cx, 'tcx>, field: Field) -> String {
// FIXME Place2 Make this work iteratively
match place {
- PlaceRef { base: PlaceBase::Local(local), projection: [] } => {
+ PlaceRef { local, projection: [] } => {
let local = &self.body.local_decls[*local];
self.describe_field_from_ty(&local.ty, field, None)
}
- PlaceRef { base, projection: [proj_base @ .., elem] } => match elem {
+ PlaceRef { local, projection: [proj_base @ .., elem] } => match elem {
ProjectionElem::Deref => {
- self.describe_field(PlaceRef { base, projection: proj_base }, field)
+ self.describe_field(PlaceRef { local, projection: proj_base }, field)
}
ProjectionElem::Downcast(_, variant_index) => {
let base_ty =
- Place::ty_from(place.base, place.projection, *self.body, self.infcx.tcx).ty;
+ Place::ty_from(place.local, place.projection, *self.body, self.infcx.tcx)
+ .ty;
self.describe_field_from_ty(&base_ty, field, Some(*variant_index))
}
ProjectionElem::Field(_, field_type) => {
ProjectionElem::Index(..)
| ProjectionElem::ConstantIndex { .. }
| ProjectionElem::Subslice { .. } => {
- self.describe_field(PlaceRef { base, projection: proj_base }, field)
+ self.describe_field(PlaceRef { local, projection: proj_base }, field)
}
},
}
// If we didn't find an overloaded deref or index, then assume it's a
// built in deref and check the type of the base.
- let base_ty = Place::ty_from(deref_base.base, deref_base.projection, *self.body, tcx).ty;
+ let base_ty = Place::ty_from(deref_base.local, deref_base.projection, *self.body, tcx).ty;
if base_ty.is_unsafe_ptr() {
BorrowedContentSource::DerefRawPointer
} else if base_ty.is_mutable_ptr() {
let description = if place.projection.len() == 1 {
format!("static item `{}`", self.describe_place(place.as_ref()).unwrap())
} else {
- let base_static = PlaceRef { base: &place.base, projection: &[ProjectionElem::Deref] };
+ let base_static =
+ PlaceRef { local: &place.local, projection: &[ProjectionElem::Deref] };
format!(
"`{:?}` as `{:?}` is a static item",
let deref_base = match deref_target_place.projection.as_ref() {
&[ref proj_base @ .., ProjectionElem::Deref] => {
- PlaceRef { base: &deref_target_place.base, projection: &proj_base }
+ PlaceRef { local: &deref_target_place.local, projection: &proj_base }
}
_ => bug!("deref_target_place is not a deref projection"),
};
- if let PlaceRef { base: PlaceBase::Local(local), projection: [] } = deref_base {
+ if let PlaceRef { local, projection: [] } = deref_base {
let decl = &self.body.local_decls[*local];
if decl.is_ref_for_guard() {
let mut err = self.cannot_move_out_of(
use rustc::mir::{self, ClearCrossCrate, Local, LocalInfo, Location, ReadOnlyBodyAndCache};
-use rustc::mir::{Mutability, Place, PlaceBase, PlaceRef, ProjectionElem};
+use rustc::mir::{Mutability, Place, PlaceRef, ProjectionElem};
use rustc::ty::{self, Ty, TyCtxt};
use rustc_hir as hir;
use rustc_hir::Node;
debug!("report_mutability_error: access_place_desc={:?}", access_place_desc);
match the_place_err {
- PlaceRef { base: PlaceBase::Local(local), projection: [] } => {
+ PlaceRef { local, projection: [] } => {
item_msg = format!("`{}`", access_place_desc.unwrap());
if access_place.as_local().is_some() {
reason = ", as it is not declared as mutable".to_string();
}
PlaceRef {
- base: _,
+ local,
projection: [proj_base @ .., ProjectionElem::Field(upvar_index, _)],
} => {
debug_assert!(is_closure_or_generator(
- Place::ty_from(&the_place_err.base, proj_base, *self.body, self.infcx.tcx).ty
+ Place::ty_from(local, proj_base, *self.body, self.infcx.tcx).ty
));
item_msg = format!("`{}`", access_place_desc.unwrap());
}
}
- PlaceRef { base: &PlaceBase::Local(local), projection: [ProjectionElem::Deref] }
- if self.body.local_decls[local].is_ref_for_guard() =>
+ PlaceRef { local, projection: [ProjectionElem::Deref] }
+ if self.body.local_decls[*local].is_ref_for_guard() =>
{
item_msg = format!("`{}`", access_place_desc.unwrap());
reason = ", as it is immutable for the pattern guard".to_string();
}
- PlaceRef { base: &PlaceBase::Local(local), projection: [ProjectionElem::Deref] }
- if self.body.local_decls[local].is_ref_to_static() =>
+ PlaceRef { local, projection: [ProjectionElem::Deref] }
+ if self.body.local_decls[*local].is_ref_to_static() =>
{
if access_place.projection.len() == 1 {
item_msg = format!("immutable static item `{}`", access_place_desc.unwrap());
reason = String::new();
} else {
item_msg = format!("`{}`", access_place_desc.unwrap());
- let local_info = &self.body.local_decls[local].local_info;
+ let local_info = &self.body.local_decls[*local].local_info;
if let LocalInfo::StaticRef { def_id, .. } = *local_info {
let static_name = &self.infcx.tcx.item_name(def_id);
reason = format!(", as `{}` is an immutable static item", static_name);
}
}
}
- PlaceRef { base: _, projection: [proj_base @ .., ProjectionElem::Deref] } => {
- if the_place_err.base == &PlaceBase::Local(Local::new(1))
+ PlaceRef { local: _, projection: [proj_base @ .., ProjectionElem::Deref] } => {
+ if *the_place_err.local == Local::new(1)
&& proj_base.is_empty()
&& !self.upvars.is_empty()
{
debug_assert!(self.body.local_decls[Local::new(1)].ty.is_region_ptr());
debug_assert!(is_closure_or_generator(
Place::ty_from(
- the_place_err.base,
+ the_place_err.local,
the_place_err.projection,
*self.body,
self.infcx.tcx
}
} else {
let source = self.borrowed_content_source(PlaceRef {
- base: the_place_err.base,
+ local: the_place_err.local,
projection: proj_base,
});
let pointer_type = source.describe_for_immutable_place();
}
}
- PlaceRef { base: _, projection: [.., ProjectionElem::Index(_)] }
- | PlaceRef { base: _, projection: [.., ProjectionElem::ConstantIndex { .. }] }
- | PlaceRef { base: _, projection: [.., ProjectionElem::Subslice { .. }] }
- | PlaceRef { base: _, projection: [.., ProjectionElem::Downcast(..)] } => {
+ PlaceRef { local: _, projection: [.., ProjectionElem::Index(_)] }
+ | PlaceRef { local: _, projection: [.., ProjectionElem::ConstantIndex { .. }] }
+ | PlaceRef { local: _, projection: [.., ProjectionElem::Subslice { .. }] }
+ | PlaceRef { local: _, projection: [.., ProjectionElem::Downcast(..)] } => {
bug!("Unexpected immutable place.")
}
}
// struct we've got a field access of (it must be a reference since there's a deref
// after the field access).
PlaceRef {
- base,
+ local,
projection:
[proj_base @ .., ProjectionElem::Deref, ProjectionElem::Field(field, _), ProjectionElem::Deref],
} => {
if let Some((span, message)) = annotate_struct_field(
self.infcx.tcx,
- Place::ty_from(base, proj_base, *self.body, self.infcx.tcx).ty,
+ Place::ty_from(local, proj_base, *self.body, self.infcx.tcx).ty,
field,
) {
err.span_suggestion(
}
// Suggest removing a `&mut` from the use of a mutable reference.
- PlaceRef { base: PlaceBase::Local(local), projection: [] }
+ PlaceRef { local, projection: [] }
if {
self.body
.local_decls
// We want to suggest users use `let mut` for local (user
// variable) mutations...
- PlaceRef { base: PlaceBase::Local(local), projection: [] }
+ PlaceRef { local, projection: [] }
if self.body.local_decls[*local].can_be_made_mutable() =>
{
// ... but it doesn't make sense to suggest it on
// Also suggest adding mut for upvars
PlaceRef {
- base,
+ local,
projection: [proj_base @ .., ProjectionElem::Field(upvar_index, _)],
} => {
debug_assert!(is_closure_or_generator(
- Place::ty_from(base, proj_base, *self.body, self.infcx.tcx).ty
+ Place::ty_from(local, proj_base, *self.body, self.infcx.tcx).ty
));
err.span_label(span, format!("cannot {ACT}", ACT = act));
// complete hack to approximate old AST-borrowck
// diagnostic: if the span starts with a mutable borrow of
// a local variable, then just suggest the user remove it.
- PlaceRef { base: PlaceBase::Local(_), projection: [] }
+ PlaceRef { local: _, projection: [] }
if {
if let Ok(snippet) = self.infcx.tcx.sess.source_map().span_to_snippet(span) {
snippet.starts_with("&mut ")
err.span_label(span, "try removing `&mut` here");
}
- PlaceRef { base: PlaceBase::Local(local), projection: [ProjectionElem::Deref] }
+ PlaceRef { local, projection: [ProjectionElem::Deref] }
if self.body.local_decls[*local].is_ref_for_guard() =>
{
err.span_label(span, format!("cannot {ACT}", ACT = act));
//
// FIXME: can this case be generalized to work for an
// arbitrary base for the projection?
- PlaceRef { base: PlaceBase::Local(local), projection: [ProjectionElem::Deref] }
+ PlaceRef { local, projection: [ProjectionElem::Deref] }
if self.body.local_decls[*local].is_user_variable() =>
{
let local_decl = &self.body.local_decls[*local];
}
PlaceRef {
- base,
+ local,
projection: [ProjectionElem::Deref],
// FIXME document what is this 1 magic number about
- } if *base == PlaceBase::Local(Local::new(1)) && !self.upvars.is_empty() => {
+ } if *local == Local::new(1) && !self.upvars.is_empty() => {
err.span_label(span, format!("cannot {ACT}", ACT = act));
err.span_help(
self.body.span,
);
}
- PlaceRef { base: _, projection: [.., ProjectionElem::Deref] } => {
+ PlaceRef { local: _, projection: [.., ProjectionElem::Deref] } => {
err.span_label(span, format!("cannot {ACT}", ACT = act));
match opt_source {
use rustc::lint::builtin::UNUSED_MUT;
use rustc::mir::{
read_only, Body, BodyAndCache, ClearCrossCrate, Local, Location, Mutability, Operand, Place,
- PlaceBase, PlaceElem, PlaceRef, ReadOnlyBodyAndCache,
+ PlaceElem, PlaceRef, ReadOnlyBodyAndCache,
};
use rustc::mir::{AggregateKind, BasicBlock, BorrowCheckResult, BorrowKind};
use rustc::mir::{Field, ProjectionElem, Promoted, Rvalue, Statement, StatementKind};
}
struct RootPlace<'d, 'tcx> {
- place_base: &'d PlaceBase,
+ place_local: &'d Local,
place_projection: &'d [PlaceElem<'tcx>],
is_local_mutation_allowed: LocalMutationIsAllowed,
}
this.used_mut_upvars.push(field);
}
} else {
- match place.base {
- PlaceBase::Local(local) => {
- this.used_mut.insert(local);
- }
- }
+ this.used_mut.insert(place.local);
}
};
debug!("check_for_invalidation_at_exit({:?})", borrow);
let place = &borrow.borrowed_place;
let deref = [ProjectionElem::Deref];
- let mut root_place = PlaceRef { base: &place.base, projection: &[] };
+ let mut root_place = PlaceRef { local: &place.local, projection: &[] };
// FIXME(nll-rfc#40): do more precise destructor tracking here. For now
// we just know that all locals are dropped at function exit (otherwise
//
// FIXME: allow thread-locals to borrow other thread locals?
- let (might_be_alive, will_be_dropped) = match root_place.base {
- PlaceBase::Local(local) => {
- if self.body.local_decls[*local].is_ref_to_thread_local() {
- // Thread-locals might be dropped after the function exits
- // We have to dereference the outer reference because
- // borrows don't conflict behind shared references.
- root_place.projection = &deref;
- (true, true)
- } else {
- (false, self.locals_are_invalidated_at_exit)
- }
- }
- };
+ let (might_be_alive, will_be_dropped) =
+ if self.body.local_decls[*root_place.local].is_ref_to_thread_local() {
+ // Thread-locals might be dropped after the function exits
+ // We have to dereference the outer reference because
+ // borrows don't conflict behind shared references.
+ root_place.projection = &deref;
+ (true, true)
+ } else {
+ (false, self.locals_are_invalidated_at_exit)
+ };
if !will_be_dropped {
debug!("place_is_invalidated_at_exit({:?}) - won't be dropped", place);
place_span.0.projection
{
let place_ty =
- Place::ty_from(place_span.0.base, base_proj, self.body(), self.infcx.tcx);
+ Place::ty_from(place_span.0.local, base_proj, self.body(), self.infcx.tcx);
if let ty::Array(..) = place_ty.ty.kind {
- let array_place = PlaceRef { base: place_span.0.base, projection: base_proj };
+ let array_place = PlaceRef { local: place_span.0.local, projection: base_proj };
self.check_if_subslice_element_is_moved(
location,
desired_action,
self.check_if_full_path_is_moved(
location, InitializationRequiringAction::Use,
(PlaceRef {
- base: &place.base,
+ local: &place.local,
projection: proj_base,
}, span), flow_state);
// (base initialized; no need to
// assigning to `P.f` requires `P` itself
// be already initialized
let tcx = self.infcx.tcx;
- let base_ty = Place::ty_from(&place.base, proj_base, self.body(), tcx).ty;
+ let base_ty = Place::ty_from(&place.local, proj_base, self.body(), tcx).ty;
match base_ty.kind {
ty::Adt(def, _) if def.has_dtor(tcx) => {
self.check_if_path_or_subpath_is_moved(
location, InitializationRequiringAction::Assignment,
(PlaceRef {
- base: &place.base,
+ local: &place.local,
projection: proj_base,
}, span), flow_state);
// is allowed, remove this match arm.
ty::Adt(..) | ty::Tuple(..) => {
check_parent_of_field(self, location, PlaceRef {
- base: &place.base,
+ local: &place.local,
projection: proj_base,
}, span, flow_state);
- match place.base {
- // rust-lang/rust#21232,
- // #54499, #54986: during
- // period where we reject
- // partial initialization, do
- // not complain about
- // unnecessary `mut` on an
- // attempt to do a partial
- // initialization.
- PlaceBase::Local(local) => {
- self.used_mut.insert(local);
- }
- }
+ // rust-lang/rust#21232, #54499, #54986: during period where we reject
+ // partial initialization, do not complain about unnecessary `mut` on
+ // an attempt to do a partial initialization.
+ self.used_mut.insert(place.local);
}
_ => {}
// of the union - we should error in that case.
let tcx = this.infcx.tcx;
if let ty::Adt(def, _) =
- Place::ty_from(base.base, base.projection, this.body(), tcx).ty.kind
+ Place::ty_from(base.local, base.projection, this.body(), tcx).ty.kind
{
if def.is_union() {
if this.move_data.path_map[mpi].iter().any(|moi| {
// partial initialization, do not complain about mutability
// errors except for actual mutation (as opposed to an attempt
// to do a partial initialization).
- let previously_initialized = match place.base {
- PlaceBase::Local(local) => self.is_local_ever_initialized(local, flow_state).is_some(),
- };
+ let previously_initialized =
+ self.is_local_ever_initialized(place.local, flow_state).is_some();
// at this point, we have set up the error reporting state.
if previously_initialized {
/// Adds the place into the used mutable variables set
fn add_used_mut<'d>(&mut self, root_place: RootPlace<'d, 'tcx>, flow_state: &Flows<'cx, 'tcx>) {
match root_place {
- RootPlace {
- place_base: PlaceBase::Local(local),
- place_projection: [],
- is_local_mutation_allowed,
- } => {
+ RootPlace { place_local: local, place_projection: [], is_local_mutation_allowed } => {
// If the local may have been initialized, and it is now currently being
// mutated, then it is justified to be annotated with the `mut`
// keyword, since the mutation may be a possible reassignment.
}
}
RootPlace {
- place_base: _,
+ place_local: _,
place_projection: _,
is_local_mutation_allowed: LocalMutationIsAllowed::Yes,
} => {}
RootPlace {
- place_base,
+ place_local,
place_projection: place_projection @ [.., _],
is_local_mutation_allowed: _,
} => {
if let Some(field) = self.is_upvar_field_projection(PlaceRef {
- base: &place_base,
- projection: &place_projection,
+ local: place_local,
+ projection: place_projection,
}) {
self.used_mut_upvars.push(field);
}
is_local_mutation_allowed: LocalMutationIsAllowed,
) -> Result<RootPlace<'d, 'tcx>, PlaceRef<'d, 'tcx>> {
match place {
- PlaceRef { base: PlaceBase::Local(local), projection: [] } => {
+ PlaceRef { local, projection: [] } => {
let local = &self.body.local_decls[*local];
match local.mutability {
Mutability::Not => match is_local_mutation_allowed {
LocalMutationIsAllowed::Yes => Ok(RootPlace {
- place_base: place.base,
+ place_local: place.local,
place_projection: place.projection,
is_local_mutation_allowed: LocalMutationIsAllowed::Yes,
}),
LocalMutationIsAllowed::ExceptUpvars => Ok(RootPlace {
- place_base: place.base,
+ place_local: place.local,
place_projection: place.projection,
is_local_mutation_allowed: LocalMutationIsAllowed::ExceptUpvars,
}),
LocalMutationIsAllowed::No => Err(place),
},
Mutability::Mut => Ok(RootPlace {
- place_base: place.base,
+ place_local: place.local,
place_projection: place.projection,
is_local_mutation_allowed,
}),
}
}
- PlaceRef { base: _, projection: [proj_base @ .., elem] } => {
+ PlaceRef { local: _, projection: [proj_base @ .., elem] } => {
match elem {
ProjectionElem::Deref => {
let base_ty =
- Place::ty_from(place.base, proj_base, self.body(), self.infcx.tcx).ty;
+ Place::ty_from(place.local, proj_base, self.body(), self.infcx.tcx).ty;
// Check the kind of deref to decide
match base_ty.kind {
};
self.is_mutable(
- PlaceRef { base: place.base, projection: proj_base },
+ PlaceRef { local: place.local, projection: proj_base },
mode,
)
}
// `*mut` raw pointers are always mutable, regardless of
// context. The users have to check by themselves.
hir::Mutability::Mut => Ok(RootPlace {
- place_base: place.base,
+ place_local: place.local,
place_projection: place.projection,
is_local_mutation_allowed,
}),
}
// `Box<T>` owns its content, so mutable if its location is mutable
_ if base_ty.is_box() => self.is_mutable(
- PlaceRef { base: place.base, projection: proj_base },
+ PlaceRef { local: place.local, projection: proj_base },
is_local_mutation_allowed,
),
// Deref should only be for reference, pointers or boxes
// }
// ```
let _ = self.is_mutable(
- PlaceRef { base: place.base, projection: proj_base },
+ PlaceRef { local: place.local, projection: proj_base },
is_local_mutation_allowed,
)?;
Ok(RootPlace {
- place_base: place.base,
+ place_local: place.local,
place_projection: place.projection,
is_local_mutation_allowed,
})
}
} else {
self.is_mutable(
- PlaceRef { base: place.base, projection: proj_base },
+ PlaceRef { local: place.local, projection: proj_base },
is_local_mutation_allowed,
)
}
match place_projection {
[base @ .., ProjectionElem::Field(field, _ty)] => {
let tcx = self.infcx.tcx;
- let base_ty = Place::ty_from(place_ref.base, base, self.body(), tcx).ty;
+ let base_ty = Place::ty_from(place_ref.local, base, self.body(), tcx).ty;
if (base_ty.is_closure() || base_ty.is_generator())
&& (!by_ref || self.upvars[field.index()].by_ref)
use crate::borrow_check::AccessDepth;
use crate::dataflow::indexes::BorrowIndex;
use rustc::mir::BorrowKind;
-use rustc::mir::{BasicBlock, Body, Location, Place, PlaceBase};
+use rustc::mir::{BasicBlock, Body, Location, Place};
use rustc::ty::TyCtxt;
use rustc_data_structures::graph::dominators::Dominators;
/// Determines if a given borrow is borrowing local data
/// This is called for all Yield expressions on movable generators
pub(super) fn borrow_of_local_data(place: &Place<'_>) -> bool {
- match place.base {
- // Reborrow of already borrowed data is ignored
- // Any errors will be caught on the initial borrow
- PlaceBase::Local(_) => !place.is_indirect(),
- }
+ // Reborrow of already borrowed data is ignored
+ // Any errors will be caught on the initial borrow
+ !place.is_indirect()
}
use crate::borrow_check::borrow_set::LocalsStateAtExit;
use rustc::mir::ProjectionElem;
-use rustc::mir::{Body, Mutability, Place, PlaceBase};
+use rustc::mir::{Body, Mutability, Place};
use rustc::ty::{self, TyCtxt};
use rustc_hir as hir;
body: &Body<'tcx>,
locals_state_at_exit: &LocalsStateAtExit,
) -> bool {
- let local = match self.base {
- // If a local variable is immutable, then we only need to track borrows to guard
- // against two kinds of errors:
- // * The variable being dropped while still borrowed (e.g., because the fn returns
- // a reference to a local variable)
- // * The variable being moved while still borrowed
- //
- // In particular, the variable cannot be mutated -- the "access checks" will fail --
- // so we don't have to worry about mutation while borrowed.
- PlaceBase::Local(local) => match locals_state_at_exit {
- LocalsStateAtExit::AllAreInvalidated => local,
- LocalsStateAtExit::SomeAreInvalidated { has_storage_dead_or_moved } => {
- let ignore = !has_storage_dead_or_moved.contains(local)
- && body.local_decls[local].mutability == Mutability::Not;
- debug!("ignore_borrow: local {:?} => {:?}", local, ignore);
- if ignore {
- return true;
- } else {
- local
- }
- }
- },
- };
+ // If a local variable is immutable, then we only need to track borrows to guard
+ // against two kinds of errors:
+ // * The variable being dropped while still borrowed (e.g., because the fn returns
+ // a reference to a local variable)
+ // * The variable being moved while still borrowed
+ //
+ // In particular, the variable cannot be mutated -- the "access checks" will fail --
+ // so we don't have to worry about mutation while borrowed.
+ if let LocalsStateAtExit::SomeAreInvalidated { has_storage_dead_or_moved } =
+ locals_state_at_exit
+ {
+ let ignore = !has_storage_dead_or_moved.contains(self.local)
+ && body.local_decls[self.local].mutability == Mutability::Not;
+ debug!("ignore_borrow: local {:?} => {:?}", self.local, ignore);
+ if ignore {
+ return true;
+ }
+ }
for (i, elem) in self.projection.iter().enumerate() {
let proj_base = &self.projection[..i];
if *elem == ProjectionElem::Deref {
- let ty = Place::ty_from(&self.base, proj_base, body, tcx).ty;
+ let ty = Place::ty_from(&self.local, proj_base, body, tcx).ty;
match ty.kind {
ty::Ref(_, _, hir::Mutability::Not) if i == 0 => {
// For references to thread-local statics, we do need
// to track the borrow.
- if body.local_decls[local].is_ref_to_thread_local() {
+ if body.local_decls[self.local].is_ref_to_thread_local() {
continue;
}
return true;
use crate::borrow_check::ArtificialField;
use crate::borrow_check::Overlap;
use crate::borrow_check::{AccessDepth, Deep, Shallow};
-use rustc::mir::{Body, BorrowKind, Place, PlaceBase, PlaceElem, PlaceRef, ProjectionElem};
+use rustc::mir::{Body, BorrowKind, Local, Place, PlaceElem, PlaceRef, ProjectionElem};
use rustc::ty::{self, TyCtxt};
use rustc_hir as hir;
use std::cmp::max;
// and either equal or disjoint.
// - If we did run out of access, the borrow can access a part of it.
- let borrow_base = &borrow_place.base;
- let access_base = access_place.base;
+ let borrow_local = &borrow_place.local;
+ let access_local = access_place.local;
- match place_base_conflict(borrow_base, access_base) {
+ match place_base_conflict(borrow_local, access_local) {
Overlap::Arbitrary => {
bug!("Two base can't return Arbitrary");
}
match place_projection_conflict(
tcx,
body,
- borrow_base,
+ borrow_local,
borrow_proj_base,
borrow_c,
access_c,
// access cares about.
let proj_base = &borrow_place.projection[..access_place.projection.len() + i];
- let base_ty = Place::ty_from(borrow_base, proj_base, body, tcx).ty;
+ let base_ty = Place::ty_from(borrow_local, proj_base, body, tcx).ty;
match (elem, &base_ty.kind, access) {
(_, _, Shallow(Some(ArtificialField::ArrayLength)))
// Given that the bases of `elem1` and `elem2` are always either equal
// or disjoint (and have the same type!), return the overlap situation
// between `elem1` and `elem2`.
-fn place_base_conflict(elem1: &PlaceBase, elem2: &PlaceBase) -> Overlap {
- match (elem1, elem2) {
- (PlaceBase::Local(l1), PlaceBase::Local(l2)) => {
- if l1 == l2 {
- // the same local - base case, equal
- debug!("place_element_conflict: DISJOINT-OR-EQ-LOCAL");
- Overlap::EqualOrDisjoint
- } else {
- // different locals - base case, disjoint
- debug!("place_element_conflict: DISJOINT-LOCAL");
- Overlap::Disjoint
- }
- }
+fn place_base_conflict(l1: &Local, l2: &Local) -> Overlap {
+ if l1 == l2 {
+ // the same local - base case, equal
+ debug!("place_element_conflict: DISJOINT-OR-EQ-LOCAL");
+ Overlap::EqualOrDisjoint
+ } else {
+ // different locals - base case, disjoint
+ debug!("place_element_conflict: DISJOINT-LOCAL");
+ Overlap::Disjoint
}
}
fn place_projection_conflict<'tcx>(
tcx: TyCtxt<'tcx>,
body: &Body<'tcx>,
- pi1_base: &PlaceBase,
+ pi1_local: &Local,
pi1_proj_base: &[PlaceElem<'tcx>],
pi1_elem: &PlaceElem<'tcx>,
pi2_elem: &PlaceElem<'tcx>,
debug!("place_element_conflict: DISJOINT-OR-EQ-FIELD");
Overlap::EqualOrDisjoint
} else {
- let ty = Place::ty_from(pi1_base, pi1_proj_base, body, tcx).ty;
+ let ty = Place::ty_from(pi1_local, pi1_proj_base, body, tcx).ty;
match ty.kind {
ty::Adt(def, _) if def.is_union() => {
// Different fields of a union, we are basically stuck.
use super::MirBorrowckCtxt;
-use rustc::mir::{Place, PlaceBase, PlaceRef, ProjectionElem, ReadOnlyBodyAndCache};
+use rustc::mir::{Place, PlaceRef, ProjectionElem, ReadOnlyBodyAndCache};
use rustc::ty::{self, TyCtxt};
use rustc_hir as hir;
impl<'cx, 'tcx> IsPrefixOf<'cx, 'tcx> for PlaceRef<'cx, 'tcx> {
fn is_prefix_of(&self, other: PlaceRef<'cx, 'tcx>) -> bool {
- self.base == other.base
+ self.local == other.local
&& self.projection.len() <= other.projection.len()
&& self.projection == &other.projection[..self.projection.len()]
}
'cursor: loop {
match &cursor {
- PlaceRef { base: PlaceBase::Local(_), projection: [] } => {
+ PlaceRef { local: _, projection: [] } => {
self.next = None;
return Some(cursor);
}
- PlaceRef { base: _, projection: [proj_base @ .., elem] } => {
+ PlaceRef { local: _, projection: [proj_base @ .., elem] } => {
match elem {
ProjectionElem::Field(_ /*field*/, _ /*ty*/) => {
// FIXME: add union handling
- self.next = Some(PlaceRef { base: cursor.base, projection: proj_base });
+ self.next =
+ Some(PlaceRef { local: cursor.local, projection: proj_base });
return Some(cursor);
}
ProjectionElem::Downcast(..)
| ProjectionElem::Subslice { .. }
| ProjectionElem::ConstantIndex { .. }
| ProjectionElem::Index(_) => {
- cursor = PlaceRef { base: cursor.base, projection: proj_base };
+ cursor = PlaceRef { local: cursor.local, projection: proj_base };
continue 'cursor;
}
ProjectionElem::Deref => {
PrefixSet::All => {
// All prefixes: just blindly enqueue the base
// of the projection.
- self.next = Some(PlaceRef { base: cursor.base, projection: proj_base });
+ self.next =
+ Some(PlaceRef { local: cursor.local, projection: proj_base });
return Some(cursor);
}
PrefixSet::Supporting => {
// derefs, except we stop at the deref of a shared
// reference.
- let ty = Place::ty_from(cursor.base, proj_base, *self.body, self.tcx).ty;
+ let ty = Place::ty_from(cursor.local, proj_base, *self.body, self.tcx).ty;
match ty.kind {
ty::RawPtr(_) | ty::Ref(_ /*rgn*/, _ /*ty*/, hir::Mutability::Not) => {
// don't continue traversing over derefs of raw pointers or shared
}
ty::Ref(_ /*rgn*/, _ /*ty*/, hir::Mutability::Mut) => {
- self.next = Some(PlaceRef { base: cursor.base, projection: proj_base });
+ self.next =
+ Some(PlaceRef { local: cursor.local, projection: proj_base });
return Some(cursor);
}
ty::Adt(..) if ty.is_box() => {
- self.next = Some(PlaceRef { base: cursor.base, projection: proj_base });
+ self.next =
+ Some(PlaceRef { local: cursor.local, projection: proj_base });
return Some(cursor);
}
) -> PlaceTy<'tcx> {
debug!("sanitize_place: {:?}", place);
- let mut place_ty = match &place.base {
- PlaceBase::Local(index) => PlaceTy::from_ty(self.body.local_decls[*index].ty),
- };
+ let mut place_ty = PlaceTy::from_ty(self.body.local_decls[place.local].ty);
if place.projection.is_empty() {
if let PlaceContext::NonMutatingUse(NonMutatingUseContext::Copy) = context {
match elem {
ProjectionElem::Deref => {
let tcx = self.infcx.tcx;
- let base_ty = Place::ty_from(&borrowed_place.base, proj_base, body, tcx).ty;
+ let base_ty = Place::ty_from(&borrowed_place.local, proj_base, body, tcx).ty;
debug!("add_reborrow_constraint - base_ty = {:?}", base_ty);
match base_ty.kind {
use rustc::mir::visit::{PlaceContext, Visitor};
-use rustc::mir::{Local, Location, Place, PlaceBase, Statement, StatementKind, TerminatorKind};
+use rustc::mir::{Local, Location, Place, Statement, StatementKind, TerminatorKind};
use rustc_data_structures::fx::FxHashSet;
// be those that were never initialized - we will consider those as being used as
// they will either have been removed by unreachable code optimizations; or linted
// as unused variables.
- match into.base {
- PlaceBase::Local(local) => {
- self.never_initialized_mut_locals.remove(&local);
- }
- }
+ self.never_initialized_mut_locals.remove(&into.local);
}
}
fn visit_statement(&mut self, statement: &Statement<'tcx>, _location: Location) {
match &statement.kind {
StatementKind::Assign(box (into, _)) => {
- match into.base {
- PlaceBase::Local(local) => debug!(
- "visit_statement: statement={:?} local={:?} \
- never_initialized_mut_locals={:?}",
- statement, local, self.never_initialized_mut_locals
- ),
- }
+ debug!(
+ "visit_statement: statement={:?} local={:?} \
+ never_initialized_mut_locals={:?}",
+ statement, into.local, self.never_initialized_mut_locals
+ );
self.remove_never_initialized_mut_locals(into);
}
_ => {}
/// and `c` can be progressively pushed onto the place builder that is created when converting `a`.
#[derive(Clone)]
struct PlaceBuilder<'tcx> {
- base: PlaceBase,
+ local: Local,
projection: Vec<PlaceElem<'tcx>>,
}
impl PlaceBuilder<'tcx> {
fn into_place(self, tcx: TyCtxt<'tcx>) -> Place<'tcx> {
- Place { base: self.base, projection: tcx.intern_place_elems(&self.projection) }
+ Place { local: self.local, projection: tcx.intern_place_elems(&self.projection) }
}
fn field(self, f: Field, ty: Ty<'tcx>) -> Self {
impl From<Local> for PlaceBuilder<'tcx> {
fn from(local: Local) -> Self {
- Self { base: local.into(), projection: Vec::new() }
- }
-}
-
-impl From<PlaceBase> for PlaceBuilder<'tcx> {
- fn from(base: PlaceBase) -> Self {
- Self { base, projection: Vec::new() }
+ Self { local, projection: Vec::new() }
}
}
) {
let tcx = self.hir.tcx();
let place_ty =
- Place::ty_from(&base_place.base, &base_place.projection, &self.local_decls, tcx);
+ Place::ty_from(&base_place.local, &base_place.projection, &self.local_decls, tcx);
if let ty::Slice(_) = place_ty.ty.kind {
// We need to create fake borrows to ensure that the bounds
// check that we just did stays valid. Since we can't assign to
match elem {
ProjectionElem::Deref => {
let fake_borrow_deref_ty = Place::ty_from(
- &base_place.base,
+ &base_place.local,
&base_place.projection[..idx],
&self.local_decls,
tcx,
Rvalue::Ref(
tcx.lifetimes.re_erased,
BorrowKind::Shallow,
- Place { base: base_place.base.clone(), projection },
+ Place { local: base_place.local.clone(), projection },
),
);
fake_borrow_temps.push(fake_borrow_temp);
}
ProjectionElem::Index(_) => {
let index_ty = Place::ty_from(
- &base_place.base,
+ &base_place.local,
&base_place.projection[..idx],
&self.local_decls,
tcx,
let arg_place = unpack!(block = this.as_place(block, arg));
let mutability = match arg_place.as_ref() {
- PlaceRef { base: &PlaceBase::Local(local), projection: &[] } => {
- this.local_decls[local].mutability
- }
- PlaceRef { base: &PlaceBase::Local(local), projection: &[ProjectionElem::Deref] } => {
+ PlaceRef { local, projection: &[] } => this.local_decls[*local].mutability,
+ PlaceRef { local, projection: &[ProjectionElem::Deref] } => {
debug_assert!(
- this.local_decls[local].is_ref_for_guard(),
+ this.local_decls[*local].is_ref_for_guard(),
"Unexpected capture place",
);
- this.local_decls[local].mutability
+ this.local_decls[*local].mutability
}
PlaceRef {
- ref base,
+ ref local,
projection: &[ref proj_base @ .., ProjectionElem::Field(upvar_index, _)],
}
| PlaceRef {
- ref base,
+ ref local,
projection:
&[ref proj_base @ .., ProjectionElem::Field(upvar_index, _), ProjectionElem::Deref],
} => {
- let place = PlaceRef { base, projection: proj_base };
+ let place = PlaceRef { local, projection: proj_base };
// Not projected from the implicit `self` in a closure.
debug_assert!(
let proj_base = &source.projection[..i];
fake_borrows.insert(Place {
- base: source.base.clone(),
+ local: source.local.clone(),
projection: self.hir.tcx().intern_place_elems(proj_base),
});
}
// Insert a shallow borrow after a deref. For other
// projections the borrow of prefix_cursor will
// conflict with any mutation of base.
- all_fake_borrows.push(PlaceRef { base: &place.base, projection: proj_base });
+ all_fake_borrows.push(PlaceRef { local: &place.local, projection: proj_base });
}
}
.into_iter()
.map(|matched_place_ref| {
let matched_place = Place {
- base: matched_place_ref.base.clone(),
+ local: matched_place_ref.local.clone(),
projection: tcx.intern_place_elems(matched_place_ref.projection),
};
let fake_borrow_deref_ty = matched_place.ty(&self.local_decls, tcx).ty;
span: tcx_hir.span(var_id),
},
place: Place {
- base: closure_env_arg.into(),
+ local: closure_env_arg.into(),
projection: tcx.intern_place_elems(&projs),
},
});
}
fn find_local(place: &Place<'_>) -> Option<Local> {
- match place.base {
- PlaceBase::Local(local) if !place.is_indirect() => Some(local),
- _ => None,
- }
+ if !place.is_indirect() { Some(place.local) } else { None }
}
impl<'tcx> Visitor<'tcx> for BorrowedLocalsVisitor<'_> {
-use rustc::mir::{self, Body, Location, Place, PlaceBase};
+use rustc::mir::{self, Body, Location, Place};
use rustc::ty::RegionVid;
use rustc::ty::TyCtxt;
fn kill_borrows_on_place(&self, trans: &mut GenKillSet<BorrowIndex>, place: &Place<'tcx>) {
debug!("kill_borrows_on_place: place={:?}", place);
- match place.base {
- PlaceBase::Local(local) => {
- let other_borrows_of_local =
- self.borrow_set.local_map.get(&local).into_iter().flat_map(|bs| bs.into_iter());
-
- // If the borrowed place is a local with no projections, all other borrows of this
- // local must conflict. This is purely an optimization so we don't have to call
- // `places_conflict` for every borrow.
- if place.projection.is_empty() {
- if !self.body.local_decls[local].is_ref_to_static() {
- trans.kill_all(other_borrows_of_local);
- }
- return;
- }
-
- // By passing `PlaceConflictBias::NoOverlap`, we conservatively assume that any given
- // pair of array indices are unequal, so that when `places_conflict` returns true, we
- // will be assured that two places being compared definitely denotes the same sets of
- // locations.
- let definitely_conflicting_borrows = other_borrows_of_local.filter(|&&i| {
- places_conflict(
- self.tcx,
- self.body,
- &self.borrow_set.borrows[i].borrowed_place,
- place,
- PlaceConflictBias::NoOverlap,
- )
- });
+ let other_borrows_of_local =
+ self.borrow_set.local_map.get(&place.local).into_iter().flat_map(|bs| bs.into_iter());
- trans.kill_all(definitely_conflicting_borrows);
+ // If the borrowed place is a local with no projections, all other borrows of this
+ // local must conflict. This is purely an optimization so we don't have to call
+ // `places_conflict` for every borrow.
+ if place.projection.is_empty() {
+ if !self.body.local_decls[place.local].is_ref_to_static() {
+ trans.kill_all(other_borrows_of_local);
}
+ return;
}
+
+ // By passing `PlaceConflictBias::NoOverlap`, we conservatively assume that any given
+ // pair of array indices are unequal, so that when `places_conflict` returns true, we
+ // will be assured that two places being compared definitely denotes the same sets of
+ // locations.
+ let definitely_conflicting_borrows = other_borrows_of_local.filter(|&&i| {
+ places_conflict(
+ self.tcx,
+ self.body,
+ &self.borrow_set.borrows[i].borrowed_place,
+ place,
+ PlaceConflictBias::NoOverlap,
+ )
+ });
+
+ trans.kill_all(definitely_conflicting_borrows);
}
}
fn visit_rvalue(&mut self, rvalue: &mir::Rvalue<'tcx>, location: Location) {
if let mir::Rvalue::Ref(_, kind, ref borrowed_place) = *rvalue {
if self.borrow_allows_mutation(kind, borrowed_place) {
- match borrowed_place.base {
- mir::PlaceBase::Local(borrowed_local) if !borrowed_place.is_indirect() => {
- self.trans.gen(borrowed_local)
- }
-
- _ => (),
+ if !borrowed_place.is_indirect() {
+ self.trans.gen(borrowed_place.local);
}
}
}
match stmt.kind {
StatementKind::StorageDead(l) => sets.kill(l),
StatementKind::Assign(box (ref place, _))
- | StatementKind::SetDiscriminant { box ref place, .. } => match place.base {
- PlaceBase::Local(local) => sets.gen(local),
- },
+ | StatementKind::SetDiscriminant { box ref place, .. } => {
+ sets.gen(place.local);
+ }
StatementKind::InlineAsm(box InlineAsm { ref outputs, .. }) => {
- for p in &**outputs {
- match p.base {
- PlaceBase::Local(local) => sets.gen(local),
- }
+ for place in &**outputs {
+ sets.gen(place.local);
}
}
_ => (),
fn before_terminator_effect(&self, sets: &mut GenKillSet<Local>, loc: Location) {
self.check_for_borrow(sets, loc);
- if let TerminatorKind::Call {
- destination: Some((Place { base: PlaceBase::Local(local), .. }, _)),
- ..
- } = self.body[loc.block].terminator().kind
+ if let TerminatorKind::Call { destination: Some((Place { local, .. }, _)), .. } =
+ self.body[loc.block].terminator().kind
{
sets.gen(local);
}
_dest_bb: mir::BasicBlock,
dest_place: &mir::Place<'tcx>,
) {
- match dest_place.base {
- PlaceBase::Local(local) => {
- in_out.insert(local);
- }
- }
+ in_out.insert(dest_place.local);
}
}
/// Maybe we should have separate "borrowck" and "moveck" modes.
fn move_path_for(&mut self, place: &Place<'tcx>) -> Result<MovePathIndex, MoveError<'tcx>> {
debug!("lookup({:?})", place);
- let mut base = match place.base {
- PlaceBase::Local(local) => self.builder.data.rev_lookup.locals[local],
- };
+ let mut base = self.builder.data.rev_lookup.locals[place.local];
// The move path index of the first union that we find. Once this is
// some we stop creating child move paths, since moves from unions
let proj_base = &place.projection[..i];
let body = self.builder.body;
let tcx = self.builder.tcx;
- let place_ty = Place::ty_from(&place.base, proj_base, body, tcx).ty;
+ let place_ty = Place::ty_from(&place.local, proj_base, body, tcx).ty;
match place_ty.kind {
ty::Ref(..) | ty::RawPtr(..) => {
let proj = &place.projection[..i + 1];
self.loc,
BorrowedContent {
target_place: Place {
- base: place.base.clone(),
+ local: place.local,
projection: tcx.intern_place_elems(proj),
},
},
if union_path.is_none() {
base = self.add_move_path(base, elem, |tcx| Place {
- base: place.base.clone(),
+ local: place.local.clone(),
projection: tcx.intern_place_elems(&place.projection[..i + 1]),
});
}
// `ConstIndex` patterns. This is done to ensure that all move paths
// are disjoint, which is expected by drop elaboration.
let base_place = Place {
- base: place.base.clone(),
+ local: place.local.clone(),
projection: self.builder.tcx.intern_place_elems(base),
};
let base_path = match self.move_path_for(&base_place) {
// of the union so it is marked as initialized again.
if let [proj_base @ .., ProjectionElem::Field(_, _)] = place.projection {
if let ty::Adt(def, _) =
- Place::ty_from(place.base, proj_base, self.builder.body, self.builder.tcx).ty.kind
+ Place::ty_from(place.local, proj_base, self.builder.body, self.builder.tcx).ty.kind
{
if def.is_union() {
- place = PlaceRef { base: place.base, projection: proj_base }
+ place = PlaceRef { local: place.local, projection: proj_base }
}
}
}
// unknown place, but will rather return the nearest available
// parent.
pub fn find(&self, place: PlaceRef<'_, '_>) -> LookupResult {
- let mut result = match place.base {
- PlaceBase::Local(local) => self.locals[*local],
- };
+ let mut result = self.locals[*place.local];
for elem in place.projection.iter() {
if let Some(&subpath) = self.projections.get(&(result, elem.lift())) {
place: &mir::Place<'tcx>,
layout: Option<TyLayout<'tcx>>,
) -> InterpResult<'tcx, OpTy<'tcx, M::PointerTag>> {
- use rustc::mir::PlaceBase;
-
- let base_op = match &place.base {
- PlaceBase::Local(mir::RETURN_PLACE) => throw_unsup!(ReadFromReturnPointer),
- PlaceBase::Local(local) => {
+ let base_op = match place.local {
+ mir::RETURN_PLACE => throw_unsup!(ReadFromReturnPointer),
+ local => {
// Do not use the layout passed in as argument if the base we are looking at
// here is not the entire place.
// FIXME use place_projection.is_empty() when is available
let layout = if place.projection.is_empty() { layout } else { None };
- self.access_local(self.frame(), *local, layout)?
+ self.access_local(self.frame(), local, layout)?
}
};
&mut self,
place: &mir::Place<'tcx>,
) -> InterpResult<'tcx, PlaceTy<'tcx, M::PointerTag>> {
- use rustc::mir::PlaceBase;
-
- let mut place_ty = match &place.base {
- PlaceBase::Local(mir::RETURN_PLACE) => {
+ let mut place_ty = match place.local {
+ mir::RETURN_PLACE => {
// `return_place` has the *caller* layout, but we want to use our
// `layout to verify our assumption. The caller will validate
// their layout on return.
))?,
}
}
- PlaceBase::Local(local) => PlaceTy {
+ local => PlaceTy {
// This works even for dead/uninitialized locals; we check further when writing
- place: Place::Local { frame: self.cur_frame(), local: *local },
- layout: self.layout_of_local(self.frame(), *local, None)?,
+ place: Place::Local { frame: self.cur_frame(), local: local },
+ layout: self.layout_of_local(self.frame(), local, None)?,
},
};
use rustc::mir::interpret::{ErrorHandled, GlobalAlloc, Scalar};
use rustc::mir::mono::{InstantiationMode, MonoItem};
use rustc::mir::visit::Visitor as MirVisitor;
-use rustc::mir::{self, Location, PlaceBase};
+use rustc::mir::{self, Local, Location};
use rustc::session::config::EntryFnType;
use rustc::ty::adjustment::{CustomCoerceUnsized, PointerCast};
use rustc::ty::print::obsolete::DefPathBasedNames;
fn visit_place_base(
&mut self,
- place_base: &mir::PlaceBase,
+ _place_local: &Local,
_context: mir::visit::PlaceContext,
_location: Location,
) {
- match place_base {
- PlaceBase::Local(_) => {
- // Locals have no relevance for collector.
- }
- }
}
}
place: PlaceRef<'_, 'tcx>,
) -> bool {
if let [proj_base @ .., elem] = place.projection {
- let base_qualif =
- Self::in_place(cx, per_local, PlaceRef { base: place.base, projection: proj_base });
+ let base_qualif = Self::in_place(
+ cx,
+ per_local,
+ PlaceRef { local: place.local, projection: proj_base },
+ );
let qualif = base_qualif
&& Self::in_any_value_of_ty(
cx,
- Place::ty_from(place.base, proj_base, *cx.body, cx.tcx)
+ Place::ty_from(place.local, proj_base, *cx.body, cx.tcx)
.projection_ty(cx.tcx, elem)
.ty,
);
place: PlaceRef<'_, 'tcx>,
) -> bool {
match place {
- PlaceRef { base: PlaceBase::Local(local), projection: [] } => per_local(*local),
- PlaceRef { base: _, projection: [.., _] } => Self::in_projection(cx, per_local, place),
+ PlaceRef { local, projection: [] } => per_local(*local),
+ PlaceRef { local: _, projection: [.., _] } => Self::in_projection(cx, per_local, place),
}
}
Rvalue::Ref(_, _, ref place) | Rvalue::AddressOf(_, ref place) => {
// Special-case reborrows to be more like a copy of the reference.
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;
+ let base_ty = Place::ty_from(&place.local, 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 },
+ PlaceRef { local: &place.local, projection: proj_base },
);
}
}
debug_assert!(!place.is_indirect());
match (value, place.as_ref()) {
- (true, mir::PlaceRef { base: &mir::PlaceBase::Local(local), .. }) => {
- self.qualifs_per_local.insert(local);
+ (true, mir::PlaceRef { local, .. }) => {
+ self.qualifs_per_local.insert(*local);
}
// For now, we do not clear the qualif if a local is overwritten in full by
// an unqualified rvalue (e.g. `y = 5`). This is to be consistent
// with aggregates where we overwrite all fields with assignments, which would not
// get this feature.
- (false, mir::PlaceRef { base: &mir::PlaceBase::Local(_local), projection: &[] }) => {
+ (false, mir::PlaceRef { local: _, projection: &[] }) => {
// self.qualifs_per_local.remove(*local);
}
PlaceContext::MutatingUse(MutatingUseContext::Borrow)
}
};
- self.visit_place_base(&place.base, ctx, location);
- self.visit_projection(&place.base, reborrowed_proj, ctx, location);
+ self.visit_place_base(&place.local, ctx, location);
+ self.visit_projection(&place.local, reborrowed_proj, ctx, location);
return;
}
}
}
Mutability::Mut => PlaceContext::MutatingUse(MutatingUseContext::AddressOf),
};
- self.visit_place_base(&place.base, ctx, location);
- self.visit_projection(&place.base, reborrowed_proj, ctx, location);
+ self.visit_place_base(&place.local, ctx, location);
+ self.visit_projection(&place.local, reborrowed_proj, ctx, location);
return;
}
}
}
}
- fn visit_place_base(
- &mut self,
- place_base: &PlaceBase,
- context: PlaceContext,
- location: Location,
- ) {
+ fn visit_place_base(&mut self, place_local: &Local, context: PlaceContext, location: Location) {
trace!(
- "visit_place_base: place_base={:?} context={:?} location={:?}",
- place_base,
+ "visit_place_base: place_local={:?} context={:?} location={:?}",
+ place_local,
context,
location,
);
- self.super_place_base(place_base, context, location);
-
- match place_base {
- PlaceBase::Local(_) => {}
- }
+ self.super_place_base(place_local, context, location);
}
fn visit_operand(&mut self, op: &Operand<'tcx>, location: Location) {
}
fn visit_projection_elem(
&mut self,
- place_base: &PlaceBase,
+ place_local: &Local,
proj_base: &[PlaceElem<'tcx>],
elem: &PlaceElem<'tcx>,
context: PlaceContext,
location: Location,
) {
trace!(
- "visit_projection_elem: place_base={:?} proj_base={:?} elem={:?} \
+ "visit_projection_elem: place_local={:?} proj_base={:?} elem={:?} \
context={:?} location={:?}",
- place_base,
+ place_local,
proj_base,
elem,
context,
location,
);
- self.super_projection_elem(place_base, proj_base, elem, context, location);
+ self.super_projection_elem(place_local, proj_base, elem, context, location);
match elem {
ProjectionElem::Deref => {
- let base_ty = Place::ty_from(place_base, proj_base, *self.body, self.tcx).ty;
+ let base_ty = Place::ty_from(place_local, proj_base, *self.body, self.tcx).ty;
if let ty::RawPtr(_) = base_ty.kind {
if proj_base.is_empty() {
- if let (PlaceBase::Local(local), []) = (place_base, proj_base) {
+ if let (local, []) = (place_local, proj_base) {
let decl = &self.body.local_decls[*local];
if let LocalInfo::StaticRef { def_id, .. } = decl.local_info {
let span = decl.source_info.span;
| ProjectionElem::Subslice { .. }
| ProjectionElem::Field(..)
| ProjectionElem::Index(_) => {
- let base_ty = Place::ty_from(place_base, proj_base, *self.body, self.tcx).ty;
+ let base_ty = Place::ty_from(place_local, proj_base, *self.body, self.tcx).ty;
match base_ty.ty_adt_def() {
Some(def) if def.is_union() => {
self.check_op(ops::UnionAccess);
// A borrow of a `static` also looks like `&(*_1)` in the MIR, but `_1` is a `const`
// that points to the allocation for the static. Don't treat these as reborrows.
- match place.base {
- PlaceBase::Local(local) => {
- if body.local_decls[local].is_ref_to_static() {
- return None;
- }
- }
+ if body.local_decls[place.local].is_ref_to_static() {
+ return None;
}
// Ensure the type being derefed is a reference and not a raw pointer.
//
// This is sufficient to prevent an access to a `static mut` from being marked as a
// reborrow, even if the check above were to disappear.
- let inner_ty = Place::ty_from(&place.base, inner, body, tcx).ty;
+ let inner_ty = Place::ty_from(&place.local, inner, body, tcx).ty;
match inner_ty.kind {
ty::Ref(..) => Some(inner),
_ => None,
}
fn visit_place(&mut self, place: &Place<'tcx>, context: PlaceContext, _location: Location) {
- match place.base {
- PlaceBase::Local(..) => {
- // Locals are safe.
- }
- }
-
for (i, elem) in place.projection.iter().enumerate() {
let proj_base = &place.projection[..i];
}
}
let is_borrow_of_interior_mut = context.is_borrow()
- && !Place::ty_from(&place.base, proj_base, self.body, self.tcx).ty.is_freeze(
+ && !Place::ty_from(&place.local, proj_base, self.body, self.tcx).ty.is_freeze(
self.tcx,
self.param_env,
self.source_info.span,
self.check_mut_borrowing_layout_constrained_field(place, context.is_mutating_use());
}
let old_source_info = self.source_info;
- if let (PlaceBase::Local(local), []) = (&place.base, proj_base) {
+ if let (local, []) = (&place.local, proj_base) {
let decl = &self.body.local_decls[*local];
if decl.internal {
// Internal locals are used in the `move_val_init` desugaring.
}
}
}
- let base_ty = Place::ty_from(&place.base, proj_base, self.body, self.tcx).ty;
+ let base_ty = Place::ty_from(&place.local, proj_base, self.body, self.tcx).ty;
match base_ty.kind {
ty::RawPtr(..) => self.require_unsafe(
"dereference of raw pointer",
match elem {
ProjectionElem::Field(..) => {
let ty =
- Place::ty_from(&place.base, proj_base, &self.body.local_decls, self.tcx).ty;
+ Place::ty_from(&place.local, proj_base, &self.body.local_decls, self.tcx)
+ .ty;
match ty.kind {
ty::Adt(def, _) => match self.tcx.layout_scalar_valid_range(def.did) {
(Bound::Unbounded, Bound::Unbounded) => {}
};
use rustc::mir::{
read_only, AggregateKind, BasicBlock, BinOp, Body, BodyAndCache, ClearCrossCrate, Constant,
- Local, LocalDecl, LocalKind, Location, Operand, Place, PlaceBase, ReadOnlyBodyAndCache, Rvalue,
+ Local, LocalDecl, LocalKind, Location, Operand, Place, ReadOnlyBodyAndCache, Rvalue,
SourceInfo, SourceScope, SourceScopeData, Statement, StatementKind, Terminator, TerminatorKind,
UnOp, RETURN_PLACE,
};
// doesn't use the invalid value
match cond {
Operand::Move(ref place) | Operand::Copy(ref place) => {
- match place.base {
- PlaceBase::Local(local) => self.remove_const(local),
- }
+ self.remove_const(place.local);
}
Operand::Constant(_) => {}
}
}
fn visit_place(&mut self, place: &mut Place<'tcx>, context: PlaceContext, location: Location) {
- if place.base == PlaceBase::Local(self_arg()) {
+ if place.local == self_arg() {
replace_base(
place,
Place {
- base: PlaceBase::Local(self_arg()),
+ local: self_arg(),
projection: self.tcx().intern_place_elems(&vec![ProjectionElem::Deref]),
},
self.tcx,
);
} else {
- self.visit_place_base(&mut place.base, context, location);
+ self.visit_place_base(&mut place.local, context, location);
for elem in place.projection.iter() {
if let PlaceElem::Index(local) = elem {
}
fn visit_place(&mut self, place: &mut Place<'tcx>, context: PlaceContext, location: Location) {
- if place.base == PlaceBase::Local(self_arg()) {
+ if place.local == self_arg() {
replace_base(
place,
Place {
- base: PlaceBase::Local(self_arg()),
+ local: self_arg(),
projection: self.tcx().intern_place_elems(&vec![ProjectionElem::Field(
Field::new(0),
self.ref_gen_ty,
self.tcx,
);
} else {
- self.visit_place_base(&mut place.base, context, location);
+ self.visit_place_base(&mut place.local, context, location);
for elem in place.projection.iter() {
if let PlaceElem::Index(local) = elem {
}
fn replace_base<'tcx>(place: &mut Place<'tcx>, new_base: Place<'tcx>, tcx: TyCtxt<'tcx>) {
- place.base = new_base.base;
+ place.local = new_base.local;
let mut new_projection = new_base.projection.to_vec();
new_projection.append(&mut place.projection.to_vec());
let mut projection = base.projection.to_vec();
projection.push(ProjectionElem::Field(Field::new(idx), ty));
- Place { base: base.base, projection: self.tcx.intern_place_elems(&projection) }
+ Place { local: base.local, projection: self.tcx.intern_place_elems(&projection) }
}
// Create a statement which changes the discriminant
_context: PlaceContext,
_location: Location,
) {
- match place.base {
- PlaceBase::Local(l) =>
- // Replace an Local in the remap with a generator struct access
- {
- if let Some(&(ty, variant_index, idx)) = self.remap.get(&l) {
- replace_base(place, self.make_field(variant_index, idx, ty), self.tcx);
- }
- }
+ // Replace an Local in the remap with a generator struct access
+ if let Some(&(ty, variant_index, idx)) = self.remap.get(&place.local) {
+ replace_base(place, self.make_field(variant_index, idx, ty), self.tcx);
}
}
}
}
- match place.base {
- _ => false,
- }
+ false
}
let dest = if dest_needs_borrow(&destination.0) {
fn make_integrate_local(&self, local: &Local) -> Local {
if *local == RETURN_PLACE {
- match self.destination.base {
- PlaceBase::Local(l) => return l,
- }
+ return self.destination.local;
}
let idx = local.index() - 1;
}
fn visit_place(&mut self, place: &mut Place<'tcx>, context: PlaceContext, location: Location) {
- match &mut place.base {
- PlaceBase::Local(l) => {
- // If this is the `RETURN_PLACE`, we need to rebase any projections onto it.
- let dest_proj_len = self.destination.projection.len();
- if *l == RETURN_PLACE && dest_proj_len > 0 {
- let mut projs = Vec::with_capacity(dest_proj_len + place.projection.len());
- projs.extend(self.destination.projection);
- projs.extend(place.projection);
-
- place.projection = self.tcx.intern_place_elems(&*projs);
- }
- }
+ // If this is the `RETURN_PLACE`, we need to rebase any projections onto it.
+ let dest_proj_len = self.destination.projection.len();
+ if place.local == RETURN_PLACE && dest_proj_len > 0 {
+ let mut projs = Vec::with_capacity(dest_proj_len + place.projection.len());
+ projs.extend(self.destination.projection);
+ projs.extend(place.projection);
+
+ place.projection = self.tcx.intern_place_elems(&*projs);
}
// Handles integrating any locals that occur in the base
// or projections
use crate::transform::{MirPass, MirSource};
use rustc::mir::visit::{MutVisitor, Visitor};
use rustc::mir::{
- read_only, Body, BodyAndCache, Constant, Local, Location, Operand, Place, PlaceBase, PlaceRef,
+ read_only, Body, BodyAndCache, Constant, Local, Location, Operand, Place, PlaceRef,
ProjectionElem, Rvalue,
};
use rustc::ty::{self, TyCtxt};
Place {
// Replace with dummy
- base: mem::replace(&mut place.base, PlaceBase::Local(Local::new(0))),
+ local: mem::replace(&mut place.local, Local::new(0)),
projection: self.tcx().intern_place_elems(proj_l),
}
} else {
impl Visitor<'tcx> for OptimizationFinder<'b, 'tcx> {
fn visit_rvalue(&mut self, rvalue: &Rvalue<'tcx>, location: Location) {
if let Rvalue::Ref(_, _, place) = rvalue {
- if let PlaceRef { base, projection: &[ref proj_base @ .., ProjectionElem::Deref] } =
+ if let PlaceRef { local, projection: &[ref proj_base @ .., ProjectionElem::Deref] } =
place.as_ref()
{
- if Place::ty_from(base, proj_base, self.body, self.tcx).ty.is_region_ptr() {
+ if Place::ty_from(local, proj_base, self.body, self.tcx).ty.is_region_ptr() {
self.optimizations.and_stars.insert(location);
}
}
// We can only promote interior borrows of promotable temps (non-temps
// don't get promoted anyway).
- let base = match place.base {
- PlaceBase::Local(local) => local,
- };
- self.validate_local(base)?;
+ self.validate_local(place.local)?;
if place.projection.contains(&ProjectionElem::Deref) {
return Err(Unpromotable);
}
let mut has_mut_interior =
- self.qualif_local::<qualifs::HasMutInterior>(base);
+ self.qualif_local::<qualifs::HasMutInterior>(place.local);
// HACK(eddyb) this should compute the same thing as
// `<HasMutInterior as Qualif>::in_projection` from
// `check_consts::qualifs` but without recursion.
// FIXME(eddyb) this is probably excessive, with
// the exception of `union` member accesses.
let ty =
- Place::ty_from(&place.base, proj_base, *self.body, self.tcx)
+ Place::ty_from(&place.local, proj_base, *self.body, self.tcx)
.projection_ty(self.tcx, elem)
.ty;
if ty.is_freeze(self.tcx, self.param_env, DUMMY_SP) {
if has_mut_interior {
return Err(Unpromotable);
}
- if self.qualif_local::<qualifs::NeedsDrop>(base) {
+ if self.qualif_local::<qualifs::NeedsDrop>(place.local) {
return Err(Unpromotable);
}
fn validate_place(&self, place: PlaceRef<'_, 'tcx>) -> Result<(), Unpromotable> {
match place {
- PlaceRef { base: PlaceBase::Local(local), projection: [] } => {
- self.validate_local(*local)
- }
- PlaceRef { base: _, projection: [proj_base @ .., elem] } => {
+ PlaceRef { local, projection: [] } => self.validate_local(*local),
+ PlaceRef { local: _, projection: [proj_base @ .., elem] } => {
match *elem {
ProjectionElem::Deref | ProjectionElem::Downcast(..) => {
return Err(Unpromotable);
ProjectionElem::Field(..) => {
if self.const_kind.is_none() {
let base_ty =
- Place::ty_from(place.base, proj_base, *self.body, self.tcx).ty;
+ Place::ty_from(place.local, proj_base, *self.body, self.tcx).ty;
if let Some(def) = base_ty.ty_adt_def() {
// No promotion of union field accesses.
if def.is_union() {
}
}
- self.validate_place(PlaceRef { base: place.base, projection: proj_base })
+ self.validate_place(PlaceRef { local: place.local, projection: proj_base })
}
}
}
// 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;
+ let base_ty = Place::ty_from(&place.local, 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 });
+ return self.validate_place(PlaceRef {
+ local: &place.local,
+ projection: proj_base,
+ });
}
}
Err(Unpromotable)
// Special-case reborrows to be more like a copy of the reference.
let mut place = place.as_ref();
if let [proj_base @ .., ProjectionElem::Deref] = &place.projection {
- let base_ty = Place::ty_from(&place.base, proj_base, *self.body, self.tcx).ty;
+ let base_ty = Place::ty_from(&place.local, proj_base, *self.body, self.tcx).ty;
if let ty::Ref(..) = base_ty.kind {
- place = PlaceRef { base: &place.base, projection: proj_base };
+ place = PlaceRef { local: &place.local, projection: proj_base };
}
}
// HACK(eddyb) this should compute the same thing as
// `<HasMutInterior as Qualif>::in_projection` from
// `check_consts::qualifs` but without recursion.
- let mut has_mut_interior = match place.base {
- PlaceBase::Local(local) => self.qualif_local::<qualifs::HasMutInterior>(*local),
- };
+ let mut has_mut_interior =
+ self.qualif_local::<qualifs::HasMutInterior>(*place.local);
if has_mut_interior {
let mut place_projection = place.projection;
// FIXME(eddyb) use a forward loop instead of a reverse one.
while let [proj_base @ .., elem] = place_projection {
// FIXME(eddyb) this is probably excessive, with
// the exception of `union` member accesses.
- let ty = Place::ty_from(place.base, proj_base, *self.body, self.tcx)
+ let ty = Place::ty_from(place.local, proj_base, *self.body, self.tcx)
.projection_ty(self.tcx, elem)
.ty;
if ty.is_freeze(self.tcx, self.param_env, DUMMY_SP) {
Rvalue::Ref(ref mut region, borrow_kind, ref mut place),
)) => {
// Use the underlying local for this (necessarily interior) borrow.
- let ty = place.base.ty(local_decls).ty;
+ let ty = local_decls.local_decls()[place.local].ty;
let span = statement.source_info.span;
let ref_ty = tcx.mk_ref(
tcx.lifetimes.re_static,
borrow_kind,
Place {
- base: mem::replace(
- &mut place.base,
- PlaceBase::Local(promoted_ref),
- ),
+ local: mem::replace(&mut place.local, promoted_ref),
projection: List::empty(),
},
)
ProjectionElem::Downcast(_symbol, _variant_index) => {}
ProjectionElem::Field(..) => {
- let base_ty = Place::ty_from(&place.base, &proj_base, body, tcx).ty;
+ let base_ty = Place::ty_from(&place.local, &proj_base, body, tcx).ty;
if let Some(def) = base_ty.ty_adt_def() {
// No union field accesses in `const fn`
if def.is_union() {
// Remove unnecessary StorageLive and StorageDead annotations.
data.statements.retain(|stmt| match &stmt.kind {
StatementKind::StorageLive(l) | StatementKind::StorageDead(l) => self.map[*l].is_some(),
- StatementKind::Assign(box (place, _)) => match place.base {
- PlaceBase::Local(local) => self.map[local].is_some(),
- },
+ StatementKind::Assign(box (place, _)) => self.map[place.local].is_some(),
_ => true,
});
self.super_basic_block_data(block, data);
fn match_variant_field_place<'tcx>(place: &Place<'tcx>) -> Option<(Local, VarField<'tcx>)> {
match place.as_ref() {
PlaceRef {
- base: &PlaceBase::Local(local),
+ local,
projection: &[ProjectionElem::Downcast(_, var_idx), ProjectionElem::Field(field, ty)],
- } => Some((local, VarField { field, field_ty: ty, var_idx })),
+ } => Some((*local, VarField { field, field_ty: ty, var_idx })),
_ => None,
}
}
// encountered a Deref, which is ABI-aligned
ProjectionElem::Deref => break,
ProjectionElem::Field(..) => {
- let ty = Place::ty_from(&place.base, proj_base, local_decls, tcx).ty;
+ let ty = Place::ty_from(&place.local, proj_base, local_decls, tcx).ty;
match ty.kind {
ty::Adt(def, _) if def.repr.packed() => return true,
_ => {}