提交 afa74080 编写于 作者: R Ralf Jung

use PlaceRef more consistently instead of loosely coupled local+projection

上级 929f66af
...@@ -104,7 +104,7 @@ fn process_place( ...@@ -104,7 +104,7 @@ fn process_place(
) { ) {
let cx = self.fx.cx; let cx = self.fx.cx;
if let &[ref proj_base @ .., elem] = place_ref.projection { if let Some((place_base, elem)) = place_ref.last_projection() {
let mut base_context = if context.is_mutating_use() { let mut base_context = if context.is_mutating_use() {
PlaceContext::MutatingUse(MutatingUseContext::Projection) PlaceContext::MutatingUse(MutatingUseContext::Projection)
} else { } else {
...@@ -119,8 +119,7 @@ fn process_place( ...@@ -119,8 +119,7 @@ fn process_place(
) )
); );
if is_consume { if is_consume {
let base_ty = let base_ty = mir::PlaceRef::ty(&place_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); let base_ty = self.fx.monomorphize(base_ty);
// ZSTs don't require any actual memory access. // ZSTs don't require any actual memory access.
...@@ -175,11 +174,7 @@ fn process_place( ...@@ -175,11 +174,7 @@ fn process_place(
base_context = context; base_context = context;
} }
self.process_place( self.process_place(&place_base, base_context, location);
&mir::PlaceRef { local: place_ref.local, projection: proj_base },
base_context,
location,
);
// HACK(eddyb) this emulates the old `visit_projection_elem`, this // HACK(eddyb) this emulates the old `visit_projection_elem`, this
// entire `visit_place`-like `process_place` method should be rewritten, // entire `visit_place`-like `process_place` method should be rewritten,
// now that we have moved to the "slice of projections" representation. // now that we have moved to the "slice of projections" representation.
......
...@@ -514,7 +514,7 @@ pub fn codegen_place( ...@@ -514,7 +514,7 @@ pub fn codegen_place(
pub fn monomorphized_place_ty(&self, place_ref: mir::PlaceRef<'tcx>) -> Ty<'tcx> { pub fn monomorphized_place_ty(&self, place_ref: mir::PlaceRef<'tcx>) -> Ty<'tcx> {
let tcx = self.cx.tcx(); let tcx = self.cx.tcx();
let place_ty = mir::Place::ty_from(place_ref.local, place_ref.projection, self.mir, tcx); let place_ty = mir::PlaceRef::ty(&place_ref, self.mir, tcx);
self.monomorphize(place_ty.ty) self.monomorphize(place_ty.ty)
} }
} }
...@@ -1745,18 +1745,14 @@ pub fn is_indirect(&self) -> bool { ...@@ -1745,18 +1745,14 @@ pub fn is_indirect(&self) -> bool {
/// Finds the innermost `Local` from this `Place`, *if* it is either a local itself or /// Finds the innermost `Local` from this `Place`, *if* it is either a local itself or
/// a single deref of a local. /// a single deref of a local.
// #[inline(always)]
// FIXME: can we safely swap the semantics of `fn base_local` below in here instead?
pub fn local_or_deref_local(&self) -> Option<Local> { pub fn local_or_deref_local(&self) -> Option<Local> {
match self.as_ref() { self.as_ref().local_or_deref_local()
PlaceRef { local, projection: [] }
| PlaceRef { local, projection: [ProjectionElem::Deref] } => Some(local),
_ => None,
}
} }
/// If this place represents a local variable like `_X` with no /// If this place represents a local variable like `_X` with no
/// projections, return `Some(_X)`. /// projections, return `Some(_X)`.
#[inline(always)]
pub fn as_local(&self) -> Option<Local> { pub fn as_local(&self) -> Option<Local> {
self.as_ref().as_local() self.as_ref().as_local()
} }
...@@ -1770,6 +1766,7 @@ pub fn as_ref(&self) -> PlaceRef<'tcx> { ...@@ -1770,6 +1766,7 @@ pub fn as_ref(&self) -> PlaceRef<'tcx> {
/// As a concrete example, given the place a.b.c, this would yield: /// As a concrete example, given the place a.b.c, this would yield:
/// - (a, .b) /// - (a, .b)
/// - (a.b, .c) /// - (a.b, .c)
///
/// Given a place without projections, the iterator is empty. /// Given a place without projections, the iterator is empty.
pub fn iter_projections( pub fn iter_projections(
self, self,
...@@ -1790,8 +1787,6 @@ fn from(local: Local) -> Self { ...@@ -1790,8 +1787,6 @@ fn from(local: Local) -> Self {
impl<'tcx> PlaceRef<'tcx> { impl<'tcx> PlaceRef<'tcx> {
/// Finds the innermost `Local` from this `Place`, *if* it is either a local itself or /// Finds the innermost `Local` from this `Place`, *if* it is either a local itself or
/// a single deref of a local. /// a single deref of a local.
//
// FIXME: can we safely swap the semantics of `fn base_local` below in here instead?
pub fn local_or_deref_local(&self) -> Option<Local> { pub fn local_or_deref_local(&self) -> Option<Local> {
match *self { match *self {
PlaceRef { local, projection: [] } PlaceRef { local, projection: [] }
...@@ -1808,6 +1803,14 @@ pub fn as_local(&self) -> Option<Local> { ...@@ -1808,6 +1803,14 @@ pub fn as_local(&self) -> Option<Local> {
_ => None, _ => None,
} }
} }
pub fn last_projection(&self) -> Option<(PlaceRef<'tcx>, PlaceElem<'tcx>)> {
if let &[ref proj_base @ .., elem] = self.projection {
Some((PlaceRef { local: self.local, projection: proj_base }, elem))
} else {
None
}
}
} }
impl Debug for Place<'_> { impl Debug for Place<'_> {
......
...@@ -293,9 +293,7 @@ pub(in crate::borrow_check) fn report_use_of_moved_or_uninitialized( ...@@ -293,9 +293,7 @@ pub(in crate::borrow_check) fn report_use_of_moved_or_uninitialized(
); );
} }
let ty = let ty = PlaceRef::ty(&used_place, self.body, self.infcx.tcx).ty;
Place::ty_from(used_place.local, used_place.projection, self.body, self.infcx.tcx)
.ty;
let needs_note = match ty.kind() { let needs_note = match ty.kind() {
ty::Closure(id, _) => { ty::Closure(id, _) => {
let tables = self.infcx.tcx.typeck(id.expect_local()); let tables = self.infcx.tcx.typeck(id.expect_local());
...@@ -732,8 +730,8 @@ pub(in crate::borrow_check) fn describe_place_for_conflicting_borrow( ...@@ -732,8 +730,8 @@ pub(in crate::borrow_check) fn describe_place_for_conflicting_borrow(
) -> (String, String, String, String) { ) -> (String, String, String, String) {
// Define a small closure that we can use to check if the type of a place // Define a small closure that we can use to check if the type of a place
// is a union. // is a union.
let union_ty = |place_base, place_projection| { let union_ty = |place_base| {
let ty = Place::ty_from(place_base, place_projection, self.body, self.infcx.tcx).ty; let ty = PlaceRef::ty(&place_base, self.body, self.infcx.tcx).ty;
ty.ty_adt_def().filter(|adt| adt.is_union()).map(|_| ty) ty.ty_adt_def().filter(|adt| adt.is_union()).map(|_| ty)
}; };
...@@ -751,15 +749,10 @@ pub(in crate::borrow_check) fn describe_place_for_conflicting_borrow( ...@@ -751,15 +749,10 @@ pub(in crate::borrow_check) fn describe_place_for_conflicting_borrow(
// field access to a union. If we find that, then we will keep the place of the // 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 // 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. // second borrowed place for the same union and a access to a different field.
let Place { local, projection } = first_borrowed_place; for (place_base, elem) in first_borrowed_place.iter_projections().rev() {
let mut cursor = projection.as_ref();
while let [proj_base @ .., elem] = cursor {
cursor = proj_base;
match elem { match elem {
ProjectionElem::Field(field, _) if union_ty(local, proj_base).is_some() => { ProjectionElem::Field(field, _) if union_ty(place_base).is_some() => {
return Some((PlaceRef { local, projection: proj_base }, field)); return Some((place_base, field));
} }
_ => {} _ => {}
} }
...@@ -769,23 +762,12 @@ pub(in crate::borrow_check) fn describe_place_for_conflicting_borrow( ...@@ -769,23 +762,12 @@ pub(in crate::borrow_check) fn describe_place_for_conflicting_borrow(
.and_then(|(target_base, target_field)| { .and_then(|(target_base, target_field)| {
// With the place of a union and a field access into it, we traverse the second // 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. // borrowed place and look for a access to a different field of the same union.
let Place { local, ref projection } = second_borrowed_place; for (place_base, elem) in second_borrowed_place.iter_projections().rev() {
let mut cursor = &projection[..];
while let [proj_base @ .., elem] = cursor {
cursor = proj_base;
if let ProjectionElem::Field(field, _) = elem { if let ProjectionElem::Field(field, _) = elem {
if let Some(union_ty) = union_ty(local, proj_base) { if let Some(union_ty) = union_ty(place_base) {
if field != target_field if field != target_field && place_base == target_base {
&& local == target_base.local
&& proj_base == target_base.projection
{
return Some(( return Some((
self.describe_any_place(PlaceRef { self.describe_any_place(place_base),
local,
projection: proj_base,
}),
self.describe_any_place(first_borrowed_place.as_ref()), self.describe_any_place(first_borrowed_place.as_ref()),
self.describe_any_place(second_borrowed_place.as_ref()), self.describe_any_place(second_borrowed_place.as_ref()),
union_ty.to_string(), union_ty.to_string(),
......
...@@ -1740,20 +1740,18 @@ fn check_if_path_or_subpath_is_moved( ...@@ -1740,20 +1740,18 @@ fn check_if_path_or_subpath_is_moved(
self.check_if_full_path_is_moved(location, desired_action, place_span, flow_state); self.check_if_full_path_is_moved(location, desired_action, place_span, flow_state);
if let [base_proj @ .., ProjectionElem::Subslice { from, to, from_end: false }] = if let Some((place_base, ProjectionElem::Subslice { from, to, from_end: false })) =
place_span.0.projection place_span.0.last_projection()
{ {
let place_ty = let place_ty = PlaceRef::ty(&place_base, 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() { if let ty::Array(..) = place_ty.ty.kind() {
let array_place = PlaceRef { local: place_span.0.local, projection: base_proj };
self.check_if_subslice_element_is_moved( self.check_if_subslice_element_is_moved(
location, location,
desired_action, desired_action,
(array_place, place_span.1), (place_base, place_span.1),
maybe_uninits, maybe_uninits,
*from, from,
*to, to,
); );
return; return;
} }
...@@ -1825,10 +1823,7 @@ fn check_if_assigned_path_is_moved( ...@@ -1825,10 +1823,7 @@ fn check_if_assigned_path_is_moved(
debug!("check_if_assigned_path_is_moved place: {:?}", place); debug!("check_if_assigned_path_is_moved place: {:?}", place);
// None case => assigning to `x` does not require `x` be initialized. // None case => assigning to `x` does not require `x` be initialized.
let mut cursor = &*place.projection.as_ref(); for (place_base, elem) in place.iter_projections().rev() {
while let [proj_base @ .., elem] = cursor {
cursor = proj_base;
match elem { match elem {
ProjectionElem::Index(_/*operand*/) | ProjectionElem::Index(_/*operand*/) |
ProjectionElem::ConstantIndex { .. } | ProjectionElem::ConstantIndex { .. } |
...@@ -1843,10 +1838,7 @@ fn check_if_assigned_path_is_moved( ...@@ -1843,10 +1838,7 @@ fn check_if_assigned_path_is_moved(
ProjectionElem::Deref => { ProjectionElem::Deref => {
self.check_if_full_path_is_moved( self.check_if_full_path_is_moved(
location, InitializationRequiringAction::Use, location, InitializationRequiringAction::Use,
(PlaceRef { (place_base, span), flow_state);
local: place.local,
projection: proj_base,
}, span), flow_state);
// (base initialized; no need to // (base initialized; no need to
// recur further) // recur further)
break; break;
...@@ -1862,15 +1854,12 @@ fn check_if_assigned_path_is_moved( ...@@ -1862,15 +1854,12 @@ fn check_if_assigned_path_is_moved(
// assigning to `P.f` requires `P` itself // assigning to `P.f` requires `P` itself
// be already initialized // be already initialized
let tcx = self.infcx.tcx; let tcx = self.infcx.tcx;
let base_ty = Place::ty_from(place.local, proj_base, self.body(), tcx).ty; let base_ty = PlaceRef::ty(&place_base, self.body(), tcx).ty;
match base_ty.kind() { match base_ty.kind() {
ty::Adt(def, _) if def.has_dtor(tcx) => { ty::Adt(def, _) if def.has_dtor(tcx) => {
self.check_if_path_or_subpath_is_moved( self.check_if_path_or_subpath_is_moved(
location, InitializationRequiringAction::Assignment, location, InitializationRequiringAction::Assignment,
(PlaceRef { (place_base, span), flow_state);
local: place.local,
projection: proj_base,
}, span), flow_state);
// (base initialized; no need to // (base initialized; no need to
// recur further) // recur further)
...@@ -1880,10 +1869,7 @@ fn check_if_assigned_path_is_moved( ...@@ -1880,10 +1869,7 @@ fn check_if_assigned_path_is_moved(
// Once `let s; s.x = V; read(s.x);`, // Once `let s; s.x = V; read(s.x);`,
// is allowed, remove this match arm. // is allowed, remove this match arm.
ty::Adt(..) | ty::Tuple(..) => { ty::Adt(..) | ty::Tuple(..) => {
check_parent_of_field(self, location, PlaceRef { check_parent_of_field(self, location, place_base, span, flow_state);
local: place.local,
projection: proj_base,
}, span, flow_state);
// rust-lang/rust#21232, #54499, #54986: during period where we reject // rust-lang/rust#21232, #54499, #54986: during period where we reject
// partial initialization, do not complain about unnecessary `mut` on // partial initialization, do not complain about unnecessary `mut` on
...@@ -1965,9 +1951,7 @@ fn check_parent_of_field<'cx, 'tcx>( ...@@ -1965,9 +1951,7 @@ fn check_parent_of_field<'cx, 'tcx>(
// no move out from an earlier location) then this is an attempt at initialization // no move out from an earlier location) then this is an attempt at initialization
// of the union - we should error in that case. // of the union - we should error in that case.
let tcx = this.infcx.tcx; let tcx = this.infcx.tcx;
if let ty::Adt(def, _) = if let ty::Adt(def, _) = PlaceRef::ty(&base, this.body(), tcx).ty.kind() {
Place::ty_from(base.local, base.projection, this.body(), tcx).ty.kind()
{
if def.is_union() { if def.is_union() {
if this.move_data.path_map[mpi].iter().any(|moi| { if this.move_data.path_map[mpi].iter().any(|moi| {
this.move_data.moves[*moi].source.is_predecessor_of(location, this.body) this.move_data.moves[*moi].source.is_predecessor_of(location, this.body)
...@@ -2162,9 +2146,9 @@ fn is_mutable( ...@@ -2162,9 +2146,9 @@ fn is_mutable(
place: PlaceRef<'tcx>, place: PlaceRef<'tcx>,
is_local_mutation_allowed: LocalMutationIsAllowed, is_local_mutation_allowed: LocalMutationIsAllowed,
) -> Result<RootPlace<'tcx>, PlaceRef<'tcx>> { ) -> Result<RootPlace<'tcx>, PlaceRef<'tcx>> {
match place { match place.last_projection() {
PlaceRef { local, projection: [] } => { None => {
let local = &self.body.local_decls[local]; let local = &self.body.local_decls[place.local];
match local.mutability { match local.mutability {
Mutability::Not => match is_local_mutation_allowed { Mutability::Not => match is_local_mutation_allowed {
LocalMutationIsAllowed::Yes => Ok(RootPlace { LocalMutationIsAllowed::Yes => Ok(RootPlace {
...@@ -2186,11 +2170,10 @@ fn is_mutable( ...@@ -2186,11 +2170,10 @@ fn is_mutable(
}), }),
} }
} }
PlaceRef { local: _, projection: [proj_base @ .., elem] } => { Some((place_base, elem)) => {
match elem { match elem {
ProjectionElem::Deref => { ProjectionElem::Deref => {
let base_ty = let base_ty = PlaceRef::ty(&place_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 // Check the kind of deref to decide
match base_ty.kind() { match base_ty.kind() {
...@@ -2208,10 +2191,7 @@ fn is_mutable( ...@@ -2208,10 +2191,7 @@ fn is_mutable(
_ => LocalMutationIsAllowed::Yes, _ => LocalMutationIsAllowed::Yes,
}; };
self.is_mutable( self.is_mutable(place_base, mode)
PlaceRef { local: place.local, projection: proj_base },
mode,
)
} }
} }
} }
...@@ -2229,10 +2209,9 @@ fn is_mutable( ...@@ -2229,10 +2209,9 @@ fn is_mutable(
} }
} }
// `Box<T>` owns its content, so mutable if its location is mutable // `Box<T>` owns its content, so mutable if its location is mutable
_ if base_ty.is_box() => self.is_mutable( _ if base_ty.is_box() => {
PlaceRef { local: place.local, projection: proj_base }, self.is_mutable(place_base, is_local_mutation_allowed)
is_local_mutation_allowed, }
),
// Deref should only be for reference, pointers or boxes // Deref should only be for reference, pointers or boxes
_ => bug!("Deref of unexpected type: {:?}", base_ty), _ => bug!("Deref of unexpected type: {:?}", base_ty),
} }
...@@ -2286,10 +2265,8 @@ fn is_mutable( ...@@ -2286,10 +2265,8 @@ fn is_mutable(
// }); // });
// } // }
// ``` // ```
let _ = self.is_mutable( let _ =
PlaceRef { local: place.local, projection: proj_base }, self.is_mutable(place_base, is_local_mutation_allowed)?;
is_local_mutation_allowed,
)?;
Ok(RootPlace { Ok(RootPlace {
place_local: place.local, place_local: place.local,
place_projection: place.projection, place_projection: place.projection,
...@@ -2298,10 +2275,7 @@ fn is_mutable( ...@@ -2298,10 +2275,7 @@ fn is_mutable(
} }
} }
} else { } else {
self.is_mutable( self.is_mutable(place_base, is_local_mutation_allowed)
PlaceRef { local: place.local, projection: proj_base },
is_local_mutation_allowed,
)
} }
} }
} }
......
...@@ -10,7 +10,7 @@ ...@@ -10,7 +10,7 @@
use super::MirBorrowckCtxt; use super::MirBorrowckCtxt;
use rustc_hir as hir; use rustc_hir as hir;
use rustc_middle::mir::{Body, Place, PlaceRef, ProjectionElem}; use rustc_middle::mir::{Body, PlaceRef, ProjectionElem};
use rustc_middle::ty::{self, TyCtxt}; use rustc_middle::ty::{self, TyCtxt};
pub trait IsPrefixOf<'tcx> { pub trait IsPrefixOf<'tcx> {
...@@ -67,24 +67,23 @@ fn next(&mut self) -> Option<Self::Item> { ...@@ -67,24 +67,23 @@ fn next(&mut self) -> Option<Self::Item> {
// downcasts here, but may return a base of a downcast). // downcasts here, but may return a base of a downcast).
'cursor: loop { 'cursor: loop {
match &cursor { match cursor.last_projection() {
PlaceRef { local: _, projection: [] } => { None => {
self.next = None; self.next = None;
return Some(cursor); return Some(cursor);
} }
PlaceRef { local: _, projection: [proj_base @ .., elem] } => { Some((cursor_base, elem)) => {
match elem { match elem {
ProjectionElem::Field(_ /*field*/, _ /*ty*/) => { ProjectionElem::Field(_ /*field*/, _ /*ty*/) => {
// FIXME: add union handling // FIXME: add union handling
self.next = self.next = Some(cursor_base);
Some(PlaceRef { local: cursor.local, projection: proj_base });
return Some(cursor); return Some(cursor);
} }
ProjectionElem::Downcast(..) ProjectionElem::Downcast(..)
| ProjectionElem::Subslice { .. } | ProjectionElem::Subslice { .. }
| ProjectionElem::ConstantIndex { .. } | ProjectionElem::ConstantIndex { .. }
| ProjectionElem::Index(_) => { | ProjectionElem::Index(_) => {
cursor = PlaceRef { local: cursor.local, projection: proj_base }; cursor = cursor_base;
continue 'cursor; continue 'cursor;
} }
ProjectionElem::Deref => { ProjectionElem::Deref => {
...@@ -92,7 +91,7 @@ fn next(&mut self) -> Option<Self::Item> { ...@@ -92,7 +91,7 @@ fn next(&mut self) -> Option<Self::Item> {
} }
} }
assert_eq!(*elem, ProjectionElem::Deref); assert_eq!(elem, ProjectionElem::Deref);
match self.kind { match self.kind {
PrefixSet::Shallow => { PrefixSet::Shallow => {
...@@ -105,8 +104,7 @@ fn next(&mut self) -> Option<Self::Item> { ...@@ -105,8 +104,7 @@ fn next(&mut self) -> Option<Self::Item> {
PrefixSet::All => { PrefixSet::All => {
// All prefixes: just blindly enqueue the base // All prefixes: just blindly enqueue the base
// of the projection. // of the projection.
self.next = self.next = Some(cursor_base);
Some(PlaceRef { local: cursor.local, projection: proj_base });
return Some(cursor); return Some(cursor);
} }
PrefixSet::Supporting => { PrefixSet::Supporting => {
...@@ -119,7 +117,7 @@ fn next(&mut self) -> Option<Self::Item> { ...@@ -119,7 +117,7 @@ fn next(&mut self) -> Option<Self::Item> {
// derefs, except we stop at the deref of a shared // derefs, except we stop at the deref of a shared
// reference. // reference.
let ty = Place::ty_from(cursor.local, proj_base, self.body, self.tcx).ty; let ty = PlaceRef::ty(&cursor_base, self.body, self.tcx).ty;
match ty.kind() { match ty.kind() {
ty::RawPtr(_) | ty::Ref(_ /*rgn*/, _ /*ty*/, hir::Mutability::Not) => { ty::RawPtr(_) | ty::Ref(_ /*rgn*/, _ /*ty*/, hir::Mutability::Not) => {
// don't continue traversing over derefs of raw pointers or shared // don't continue traversing over derefs of raw pointers or shared
...@@ -129,14 +127,12 @@ fn next(&mut self) -> Option<Self::Item> { ...@@ -129,14 +127,12 @@ fn next(&mut self) -> Option<Self::Item> {
} }
ty::Ref(_ /*rgn*/, _ /*ty*/, hir::Mutability::Mut) => { ty::Ref(_ /*rgn*/, _ /*ty*/, hir::Mutability::Mut) => {
self.next = self.next = Some(cursor_base);
Some(PlaceRef { local: cursor.local, projection: proj_base });
return Some(cursor); return Some(cursor);
} }
ty::Adt(..) if ty.is_box() => { ty::Adt(..) if ty.is_box() => {
self.next = self.next = Some(cursor_base);
Some(PlaceRef { local: cursor.local, projection: proj_base });
return Some(cursor); return Some(cursor);
} }
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册