Remove PlaceBase enum and make Place base field be local: Local
This commit is contained in:
parent
fd5aa32c35
commit
5d9b399044
50 changed files with 456 additions and 656 deletions
|
|
@ -1655,7 +1655,7 @@ impl Debug for Statement<'_> {
|
|||
/// 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>>,
|
||||
|
|
@ -1663,12 +1663,6 @@ pub struct Place<'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> {
|
||||
|
|
@ -1756,14 +1750,14 @@ rustc_index::newtype_index! {
|
|||
|
||||
#[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.
|
||||
|
|
@ -1780,10 +1774,8 @@ impl<'tcx> Place<'tcx> {
|
|||
// 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,
|
||||
}
|
||||
}
|
||||
|
|
@ -1795,19 +1787,13 @@ impl<'tcx> Place<'tcx> {
|
|||
}
|
||||
|
||||
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() }
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1818,10 +1804,8 @@ impl<'a, 'tcx> PlaceRef<'a, 'tcx> {
|
|||
// 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,
|
||||
}
|
||||
}
|
||||
|
|
@ -1830,7 +1814,7 @@ impl<'a, 'tcx> PlaceRef<'a, 'tcx> {
|
|||
/// 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,
|
||||
}
|
||||
}
|
||||
|
|
@ -1852,7 +1836,7 @@ impl Debug for Place<'_> {
|
|||
}
|
||||
}
|
||||
|
||||
write!(fmt, "{:?}", self.base)?;
|
||||
write!(fmt, "{:?}", self.local)?;
|
||||
|
||||
for elem in self.projection.iter() {
|
||||
match elem {
|
||||
|
|
@ -1896,14 +1880,6 @@ impl Debug for Place<'_> {
|
|||
}
|
||||
}
|
||||
|
||||
impl Debug for PlaceBase {
|
||||
fn fmt(&self, fmt: &mut Formatter<'_>) -> fmt::Result {
|
||||
match *self {
|
||||
PlaceBase::Local(id) => write!(fmt, "{:?}", id),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
// Scopes
|
||||
|
||||
|
|
@ -2964,25 +2940,11 @@ impl<'tcx> TypeFoldable<'tcx> for GeneratorKind {
|
|||
|
||||
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)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -114,7 +114,7 @@ impl<'tcx> PlaceTy<'tcx> {
|
|||
|
||||
impl<'tcx> Place<'tcx> {
|
||||
pub fn ty_from<D>(
|
||||
base: &PlaceBase,
|
||||
local: &Local,
|
||||
projection: &[PlaceElem<'tcx>],
|
||||
local_decls: &D,
|
||||
tcx: TyCtxt<'tcx>,
|
||||
|
|
@ -124,25 +124,16 @@ impl<'tcx> Place<'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)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -164,10 +164,10 @@ macro_rules! make_mir_visitor {
|
|||
}
|
||||
|
||||
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)?);
|
||||
|
|
@ -705,14 +705,10 @@ macro_rules! make_mir_visitor {
|
|||
}
|
||||
|
||||
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,
|
||||
|
|
@ -845,7 +841,7 @@ macro_rules! visit_place_fns {
|
|||
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);
|
||||
|
|
@ -886,23 +882,23 @@ macro_rules! visit_place_fns {
|
|||
() => (
|
||||
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(
|
||||
|
|
@ -921,9 +917,9 @@ macro_rules! visit_place_fns {
|
|||
};
|
||||
}
|
||||
|
||||
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);
|
||||
|
|
@ -931,7 +927,7 @@ macro_rules! visit_place_fns {
|
|||
|
||||
fn super_projection(
|
||||
&mut self,
|
||||
base: &PlaceBase,
|
||||
local: &Local,
|
||||
projection: &[PlaceElem<'tcx>],
|
||||
context: PlaceContext,
|
||||
location: Location,
|
||||
|
|
@ -939,13 +935,13 @@ macro_rules! visit_place_fns {
|
|||
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,
|
||||
|
|
|
|||
|
|
@ -226,11 +226,11 @@ pub fn decode_place<D>(decoder: &mut D) -> Result<mir::Place<'tcx>, D::Error>
|
|||
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]
|
||||
|
|
|
|||
|
|
@ -2434,7 +2434,7 @@ impl<'tcx> TyCtxt<'tcx> {
|
|||
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(
|
||||
|
|
|
|||
|
|
@ -1286,9 +1286,9 @@ fn generator_layout_and_saved_local_names(
|
|||
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[..] {
|
||||
|
|
|
|||
|
|
@ -128,17 +128,13 @@ impl<Bx: BuilderMethods<'a, 'tcx>> LocalAnalyzer<'mir, 'a, 'tcx, Bx> {
|
|||
};
|
||||
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;
|
||||
}
|
||||
|
|
@ -178,9 +174,7 @@ impl<Bx: BuilderMethods<'a, 'tcx>> LocalAnalyzer<'mir, 'a, 'tcx, Bx> {
|
|||
// 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);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -191,7 +185,7 @@ impl<Bx: BuilderMethods<'a, 'tcx>> LocalAnalyzer<'mir, 'a, 'tcx, Bx> {
|
|||
}
|
||||
|
||||
self.process_place(
|
||||
&mir::PlaceRef { base: place_ref.base, projection: proj_base },
|
||||
&mir::PlaceRef { local: place_ref.local, projection: proj_base },
|
||||
base_context,
|
||||
location,
|
||||
);
|
||||
|
|
@ -218,8 +212,8 @@ impl<Bx: BuilderMethods<'a, 'tcx>> LocalAnalyzer<'mir, 'a, 'tcx, Bx> {
|
|||
};
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1109,7 +1109,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
|
|||
} 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() {
|
||||
|
|
|
|||
|
|
@ -258,9 +258,7 @@ pub fn per_local_var_debug_info(
|
|||
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 {
|
||||
|
|
|
|||
|
|
@ -373,43 +373,39 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
|
|||
) -> 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
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -415,28 +415,26 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
|
|||
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!(),
|
||||
|
|
@ -501,7 +499,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
|
|||
|
||||
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)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -208,11 +208,7 @@ impl<'a, 'tcx> Visitor<'tcx> for GatherBorrows<'a, 'tcx> {
|
|||
|
||||
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)
|
||||
|
|
|
|||
|
|
@ -2,8 +2,8 @@ use rustc::infer::InferCtxt;
|
|||
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;
|
||||
|
|
@ -188,11 +188,8 @@ impl<'cx, 'cg, 'tcx> ConstraintGeneration<'cx, 'cg, 'tcx> {
|
|||
// 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
|
||||
|
|
@ -202,12 +199,12 @@ impl<'cx, 'cg, 'tcx> ConstraintGeneration<'cx, 'cg, 'tcx> {
|
|||
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 \
|
||||
|
|
@ -215,7 +212,7 @@ impl<'cx, 'cg, 'tcx> ConstraintGeneration<'cx, 'cg, 'tcx> {
|
|||
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,
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
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};
|
||||
|
|
@ -186,7 +186,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
|||
}
|
||||
|
||||
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, _) => {
|
||||
|
|
@ -597,15 +597,15 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
|||
// 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));
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
|
|
@ -615,21 +615,21 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
|||
.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((
|
||||
|
|
@ -686,14 +686,12 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
|||
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!(
|
||||
|
|
@ -704,22 +702,17 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
|||
}
|
||||
|
||||
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())
|
||||
|
|
@ -1145,12 +1138,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
|||
} 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())
|
||||
|
|
@ -1517,7 +1505,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
|||
[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 {
|
||||
|
|
@ -1525,7 +1513,9 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
|||
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
|
||||
|
|
@ -1533,7 +1523,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
|||
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
|
||||
|
|
|
|||
|
|
@ -2,8 +2,7 @@
|
|||
|
||||
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;
|
||||
|
|
@ -169,30 +168,30 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
|||
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);
|
||||
|
|
@ -208,29 +207,25 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
|||
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,
|
||||
|
|
@ -249,9 +244,9 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
|||
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,
|
||||
|
|
@ -263,7 +258,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
|||
autoderef = true;
|
||||
|
||||
self.append_place_to_string(
|
||||
PlaceRef { base, projection: proj_base },
|
||||
PlaceRef { local, projection: proj_base },
|
||||
buf,
|
||||
autoderef,
|
||||
&including_downcast,
|
||||
|
|
@ -280,7 +275,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
|||
// 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,
|
||||
|
|
@ -311,17 +306,18 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
|||
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) => {
|
||||
|
|
@ -330,7 +326,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
|||
ProjectionElem::Index(..)
|
||||
| ProjectionElem::ConstantIndex { .. }
|
||||
| ProjectionElem::Subslice { .. } => {
|
||||
self.describe_field(PlaceRef { base, projection: proj_base }, field)
|
||||
self.describe_field(PlaceRef { local, projection: proj_base }, field)
|
||||
}
|
||||
},
|
||||
}
|
||||
|
|
@ -451,7 +447,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
|||
|
||||
// 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() {
|
||||
|
|
|
|||
|
|
@ -273,7 +273,8 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
|
|||
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",
|
||||
|
|
@ -302,12 +303,12 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
|
|||
|
||||
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(
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
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;
|
||||
|
|
@ -42,7 +42,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
|
|||
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();
|
||||
|
|
@ -53,11 +53,11 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
|
|||
}
|
||||
|
||||
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());
|
||||
|
|
@ -69,21 +69,21 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
|
|||
}
|
||||
}
|
||||
|
||||
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);
|
||||
|
|
@ -92,8 +92,8 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
|
|||
}
|
||||
}
|
||||
}
|
||||
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()
|
||||
{
|
||||
|
|
@ -101,7 +101,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
|
|||
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
|
||||
|
|
@ -116,7 +116,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, '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();
|
||||
|
|
@ -136,10 +136,10 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
|
|||
}
|
||||
}
|
||||
|
||||
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.")
|
||||
}
|
||||
}
|
||||
|
|
@ -187,7 +187,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
|
|||
// 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],
|
||||
} => {
|
||||
|
|
@ -195,7 +195,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
|
|||
|
||||
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(
|
||||
|
|
@ -208,7 +208,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
|
|||
}
|
||||
|
||||
// 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
|
||||
|
|
@ -246,7 +246,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
|
|||
|
||||
// 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
|
||||
|
|
@ -267,11 +267,11 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
|
|||
|
||||
// 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));
|
||||
|
|
@ -298,7 +298,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
|
|||
// 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 ")
|
||||
|
|
@ -311,7 +311,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
|
|||
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));
|
||||
|
|
@ -325,7 +325,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
|
|||
//
|
||||
// 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];
|
||||
|
|
@ -408,10 +408,10 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
|
|||
}
|
||||
|
||||
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,
|
||||
|
|
@ -419,7 +419,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
|
|||
);
|
||||
}
|
||||
|
||||
PlaceRef { base: _, projection: [.., ProjectionElem::Deref] } => {
|
||||
PlaceRef { local: _, projection: [.., ProjectionElem::Deref] } => {
|
||||
err.span_label(span, format!("cannot {ACT}", ACT = act));
|
||||
|
||||
match opt_source {
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@ use rustc::lint::builtin::MUTABLE_BORROW_RESERVATION_CONFLICT;
|
|||
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};
|
||||
|
|
@ -815,7 +815,7 @@ enum InitializationRequiringAction {
|
|||
}
|
||||
|
||||
struct RootPlace<'d, 'tcx> {
|
||||
place_base: &'d PlaceBase,
|
||||
place_local: &'d Local,
|
||||
place_projection: &'d [PlaceElem<'tcx>],
|
||||
is_local_mutation_allowed: LocalMutationIsAllowed,
|
||||
}
|
||||
|
|
@ -1252,11 +1252,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
|||
this.used_mut_upvars.push(field);
|
||||
}
|
||||
} else {
|
||||
match place.base {
|
||||
PlaceBase::Local(local) => {
|
||||
this.used_mut.insert(local);
|
||||
}
|
||||
}
|
||||
this.used_mut.insert(place.local);
|
||||
}
|
||||
};
|
||||
|
||||
|
|
@ -1380,7 +1376,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
|||
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
|
||||
|
|
@ -1388,19 +1384,16 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
|||
//
|
||||
// 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);
|
||||
|
|
@ -1738,9 +1731,9 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
|||
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,
|
||||
|
|
@ -1837,7 +1830,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
|||
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
|
||||
|
|
@ -1855,13 +1848,13 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
|||
// 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);
|
||||
|
||||
|
|
@ -1874,23 +1867,14 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
|||
// 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);
|
||||
}
|
||||
|
||||
_ => {}
|
||||
|
|
@ -1968,7 +1952,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
|||
// 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| {
|
||||
|
|
@ -2087,9 +2071,8 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
|||
// 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 {
|
||||
|
|
@ -2118,11 +2101,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
|||
/// 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.
|
||||
|
|
@ -2133,18 +2112,18 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
|||
}
|
||||
}
|
||||
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);
|
||||
}
|
||||
|
|
@ -2160,34 +2139,34 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
|||
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 {
|
||||
|
|
@ -2206,7 +2185,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
|||
};
|
||||
|
||||
self.is_mutable(
|
||||
PlaceRef { base: place.base, projection: proj_base },
|
||||
PlaceRef { local: place.local, projection: proj_base },
|
||||
mode,
|
||||
)
|
||||
}
|
||||
|
|
@ -2219,7 +2198,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
|||
// `*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,
|
||||
}),
|
||||
|
|
@ -2227,7 +2206,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
|||
}
|
||||
// `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
|
||||
|
|
@ -2283,11 +2262,11 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
|||
// }
|
||||
// ```
|
||||
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,
|
||||
})
|
||||
|
|
@ -2295,7 +2274,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
|||
}
|
||||
} else {
|
||||
self.is_mutable(
|
||||
PlaceRef { base: place.base, projection: proj_base },
|
||||
PlaceRef { local: place.local, projection: proj_base },
|
||||
is_local_mutation_allowed,
|
||||
)
|
||||
}
|
||||
|
|
@ -2321,7 +2300,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
|||
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)
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@ use crate::borrow_check::places_conflict;
|
|||
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;
|
||||
|
||||
|
|
@ -131,9 +131,7 @@ pub(super) fn is_active<'tcx>(
|
|||
/// 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()
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
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;
|
||||
|
||||
|
|
@ -25,40 +25,35 @@ impl<'tcx> PlaceExt<'tcx> for Place<'tcx> {
|
|||
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;
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
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;
|
||||
|
|
@ -119,10 +119,10 @@ fn place_components_conflict<'tcx>(
|
|||
// 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");
|
||||
}
|
||||
|
|
@ -161,7 +161,7 @@ fn place_components_conflict<'tcx>(
|
|||
match place_projection_conflict(
|
||||
tcx,
|
||||
body,
|
||||
borrow_base,
|
||||
borrow_local,
|
||||
borrow_proj_base,
|
||||
borrow_c,
|
||||
access_c,
|
||||
|
|
@ -208,7 +208,7 @@ fn place_components_conflict<'tcx>(
|
|||
// 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)))
|
||||
|
|
@ -293,19 +293,15 @@ fn place_components_conflict<'tcx>(
|
|||
// 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
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -315,7 +311,7 @@ fn place_base_conflict(elem1: &PlaceBase, elem2: &PlaceBase) -> Overlap {
|
|||
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>,
|
||||
|
|
@ -333,7 +329,7 @@ fn place_projection_conflict<'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.
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@
|
|||
|
||||
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;
|
||||
|
||||
|
|
@ -19,7 +19,7 @@ pub trait IsPrefixOf<'cx, 'tcx> {
|
|||
|
||||
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()]
|
||||
}
|
||||
|
|
@ -69,22 +69,23 @@ impl<'cx, 'tcx> Iterator for Prefixes<'cx, 'tcx> {
|
|||
|
||||
'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 => {
|
||||
|
|
@ -105,7 +106,8 @@ impl<'cx, 'tcx> Iterator for Prefixes<'cx, 'tcx> {
|
|||
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 => {
|
||||
|
|
@ -118,7 +120,7 @@ impl<'cx, 'tcx> Iterator for Prefixes<'cx, 'tcx> {
|
|||
// 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
|
||||
|
|
@ -128,12 +130,14 @@ impl<'cx, 'tcx> Iterator for Prefixes<'cx, 'tcx> {
|
|||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -465,9 +465,7 @@ impl<'a, 'b, 'tcx> TypeVerifier<'a, 'b, 'tcx> {
|
|||
) -> 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 {
|
||||
|
|
@ -2389,7 +2387,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
|
|||
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 {
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
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;
|
||||
|
||||
|
|
@ -57,11 +57,7 @@ impl GatherUsedMutsVisitor<'_, '_, '_> {
|
|||
// 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);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -82,13 +78,11 @@ impl<'visit, 'cx, 'tcx> Visitor<'tcx> for GatherUsedMutsVisitor<'visit, 'cx, 'tc
|
|||
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);
|
||||
}
|
||||
_ => {}
|
||||
|
|
|
|||
|
|
@ -20,13 +20,13 @@ use rustc_index::vec::Idx;
|
|||
/// 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 {
|
||||
|
|
@ -49,13 +49,7 @@ impl PlaceBuilder<'tcx> {
|
|||
|
||||
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() }
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -370,7 +364,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
|||
) {
|
||||
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
|
||||
|
|
@ -380,7 +374,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
|||
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,
|
||||
|
|
@ -398,14 +392,14 @@ impl<'a, 'tcx> Builder<'a, '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,
|
||||
|
|
|
|||
|
|
@ -393,26 +393,24 @@ impl<'a, 'tcx> Builder<'a, '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!(
|
||||
|
|
|
|||
|
|
@ -890,7 +890,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
|||
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),
|
||||
});
|
||||
}
|
||||
|
|
@ -1241,7 +1241,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
|||
// 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 });
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1258,7 +1258,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
|||
.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;
|
||||
|
|
|
|||
|
|
@ -834,7 +834,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
|||
span: tcx_hir.span(var_id),
|
||||
},
|
||||
place: Place {
|
||||
base: closure_env_arg.into(),
|
||||
local: closure_env_arg.into(),
|
||||
projection: tcx.intern_place_elems(&projs),
|
||||
},
|
||||
});
|
||||
|
|
|
|||
|
|
@ -86,10 +86,7 @@ struct BorrowedLocalsVisitor<'gk> {
|
|||
}
|
||||
|
||||
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<'_> {
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
use rustc::mir::{self, Body, Location, Place, PlaceBase};
|
||||
use rustc::mir::{self, Body, Location, Place};
|
||||
use rustc::ty::RegionVid;
|
||||
use rustc::ty::TyCtxt;
|
||||
|
||||
|
|
@ -195,38 +195,34 @@ impl<'a, 'tcx> Borrows<'a, 'tcx> {
|
|||
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());
|
||||
let other_borrows_of_local =
|
||||
self.borrow_set.local_map.get(&place.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,
|
||||
)
|
||||
});
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -111,12 +111,8 @@ impl<'tcx> Visitor<'tcx> for TransferFunction<'_, '_, 'tcx> {
|
|||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -115,14 +115,12 @@ impl<'mir, 'tcx> BitDenotation<'tcx> for RequiresStorage<'mir, 'tcx> {
|
|||
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);
|
||||
}
|
||||
}
|
||||
_ => (),
|
||||
|
|
@ -138,10 +136,8 @@ impl<'mir, 'tcx> BitDenotation<'tcx> for RequiresStorage<'mir, 'tcx> {
|
|||
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);
|
||||
}
|
||||
|
|
@ -169,11 +165,7 @@ impl<'mir, 'tcx> BitDenotation<'tcx> for RequiresStorage<'mir, 'tcx> {
|
|||
_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);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -96,9 +96,7 @@ impl<'b, 'a, 'tcx> Gatherer<'b, 'a, 'tcx> {
|
|||
/// 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
|
||||
|
|
@ -111,7 +109,7 @@ impl<'b, 'a, 'tcx> Gatherer<'b, 'a, 'tcx> {
|
|||
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];
|
||||
|
|
@ -119,7 +117,7 @@ impl<'b, 'a, 'tcx> Gatherer<'b, 'a, 'tcx> {
|
|||
self.loc,
|
||||
BorrowedContent {
|
||||
target_place: Place {
|
||||
base: place.base.clone(),
|
||||
local: place.local,
|
||||
projection: tcx.intern_place_elems(proj),
|
||||
},
|
||||
},
|
||||
|
|
@ -160,7 +158,7 @@ impl<'b, 'a, 'tcx> Gatherer<'b, 'a, 'tcx> {
|
|||
|
||||
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]),
|
||||
});
|
||||
}
|
||||
|
|
@ -433,7 +431,7 @@ impl<'b, 'a, 'tcx> Gatherer<'b, 'a, 'tcx> {
|
|||
// `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) {
|
||||
|
|
@ -494,10 +492,10 @@ impl<'b, 'a, 'tcx> Gatherer<'b, 'a, 'tcx> {
|
|||
// 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 }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -246,9 +246,7 @@ impl MovePathLookup {
|
|||
// 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())) {
|
||||
|
|
|
|||
|
|
@ -462,17 +462,15 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
|
|||
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)?
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -624,10 +624,8 @@ where
|
|||
&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.
|
||||
|
|
@ -648,10 +646,10 @@ where
|
|||
))?,
|
||||
}
|
||||
}
|
||||
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)?,
|
||||
},
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -182,7 +182,7 @@ use rustc::mir::interpret::{AllocId, ConstValue};
|
|||
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;
|
||||
|
|
@ -642,15 +642,10 @@ impl<'a, 'tcx> MirVisitor<'tcx> for MirNeighborCollector<'a, 'tcx> {
|
|||
|
||||
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.
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -38,12 +38,15 @@ pub trait Qualif {
|
|||
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,
|
||||
);
|
||||
|
|
@ -75,8 +78,8 @@ pub trait Qualif {
|
|||
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),
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -146,12 +149,12 @@ pub trait Qualif {
|
|||
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 },
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -47,15 +47,15 @@ where
|
|||
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);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -304,8 +304,8 @@ impl Visitor<'tcx> for Validator<'_, 'mir, 'tcx> {
|
|||
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;
|
||||
}
|
||||
}
|
||||
|
|
@ -317,8 +317,8 @@ impl Visitor<'tcx> for Validator<'_, 'mir, 'tcx> {
|
|||
}
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
|
@ -412,23 +412,14 @@ impl Visitor<'tcx> for Validator<'_, 'mir, 'tcx> {
|
|||
}
|
||||
}
|
||||
|
||||
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) {
|
||||
|
|
@ -441,30 +432,30 @@ impl Visitor<'tcx> for Validator<'_, 'mir, 'tcx> {
|
|||
}
|
||||
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;
|
||||
|
|
@ -485,7 +476,7 @@ impl Visitor<'tcx> for Validator<'_, 'mir, 'tcx> {
|
|||
| 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);
|
||||
|
|
@ -669,19 +660,15 @@ fn place_as_reborrow(
|
|||
|
||||
// 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,
|
||||
|
|
|
|||
|
|
@ -190,12 +190,6 @@ impl<'a, 'tcx> Visitor<'tcx> for UnsafetyChecker<'a, 'tcx> {
|
|||
}
|
||||
|
||||
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];
|
||||
|
||||
|
|
@ -223,7 +217,7 @@ impl<'a, 'tcx> Visitor<'tcx> for UnsafetyChecker<'a, 'tcx> {
|
|||
}
|
||||
}
|
||||
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,
|
||||
|
|
@ -238,7 +232,7 @@ impl<'a, 'tcx> Visitor<'tcx> for UnsafetyChecker<'a, 'tcx> {
|
|||
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.
|
||||
|
|
@ -266,7 +260,7 @@ impl<'a, 'tcx> Visitor<'tcx> for UnsafetyChecker<'a, 'tcx> {
|
|||
}
|
||||
}
|
||||
}
|
||||
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",
|
||||
|
|
@ -420,7 +414,8 @@ impl<'a, 'tcx> UnsafetyChecker<'a, 'tcx> {
|
|||
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) => {}
|
||||
|
|
|
|||
|
|
@ -10,7 +10,7 @@ use rustc::mir::visit::{
|
|||
};
|
||||
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,
|
||||
};
|
||||
|
|
@ -872,9 +872,7 @@ impl<'mir, 'tcx> MutVisitor<'tcx> for ConstPropagator<'mir, 'tcx> {
|
|||
// 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(_) => {}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -112,17 +112,17 @@ impl<'tcx> MutVisitor<'tcx> for DerefArgVisitor<'tcx> {
|
|||
}
|
||||
|
||||
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 {
|
||||
|
|
@ -148,11 +148,11 @@ impl<'tcx> MutVisitor<'tcx> for PinArgVisitor<'tcx> {
|
|||
}
|
||||
|
||||
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,
|
||||
|
|
@ -161,7 +161,7 @@ impl<'tcx> MutVisitor<'tcx> for PinArgVisitor<'tcx> {
|
|||
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 {
|
||||
|
|
@ -173,7 +173,7 @@ impl<'tcx> MutVisitor<'tcx> for PinArgVisitor<'tcx> {
|
|||
}
|
||||
|
||||
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());
|
||||
|
|
@ -236,7 +236,7 @@ impl TransformVisitor<'tcx> {
|
|||
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
|
||||
|
|
@ -281,14 +281,9 @@ impl MutVisitor<'tcx> for TransformVisitor<'tcx> {
|
|||
_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);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -430,9 +430,7 @@ impl Inliner<'tcx> {
|
|||
}
|
||||
}
|
||||
|
||||
match place.base {
|
||||
_ => false,
|
||||
}
|
||||
false
|
||||
}
|
||||
|
||||
let dest = if dest_needs_borrow(&destination.0) {
|
||||
|
|
@ -644,9 +642,7 @@ impl<'a, 'tcx> Integrator<'a, 'tcx> {
|
|||
|
||||
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;
|
||||
|
|
@ -668,18 +664,14 @@ impl<'a, 'tcx> MutVisitor<'tcx> for Integrator<'a, 'tcx> {
|
|||
}
|
||||
|
||||
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);
|
||||
// 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);
|
||||
}
|
||||
}
|
||||
place.projection = self.tcx.intern_place_elems(&*projs);
|
||||
}
|
||||
// Handles integrating any locals that occur in the base
|
||||
// or projections
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@
|
|||
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};
|
||||
|
|
@ -55,7 +55,7 @@ impl<'tcx> MutVisitor<'tcx> for InstCombineVisitor<'tcx> {
|
|||
|
||||
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 {
|
||||
|
|
@ -92,10 +92,10 @@ impl OptimizationFinder<'b, 'tcx> {
|
|||
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);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -308,17 +308,14 @@ impl<'tcx> Validator<'_, 'tcx> {
|
|||
|
||||
// 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.
|
||||
|
|
@ -332,7 +329,7 @@ impl<'tcx> Validator<'_, 'tcx> {
|
|||
// 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) {
|
||||
|
|
@ -348,7 +345,7 @@ impl<'tcx> Validator<'_, 'tcx> {
|
|||
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);
|
||||
}
|
||||
|
||||
|
|
@ -478,10 +475,8 @@ impl<'tcx> Validator<'_, 'tcx> {
|
|||
|
||||
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);
|
||||
|
|
@ -496,7 +491,7 @@ impl<'tcx> Validator<'_, 'tcx> {
|
|||
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() {
|
||||
|
|
@ -507,7 +502,7 @@ impl<'tcx> Validator<'_, 'tcx> {
|
|||
}
|
||||
}
|
||||
|
||||
self.validate_place(PlaceRef { base: place.base, projection: proj_base })
|
||||
self.validate_place(PlaceRef { local: place.local, projection: proj_base })
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -594,10 +589,12 @@ impl<'tcx> Validator<'_, 'tcx> {
|
|||
// 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)
|
||||
|
|
@ -631,9 +628,9 @@ impl<'tcx> Validator<'_, 'tcx> {
|
|||
// 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 };
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -642,16 +639,15 @@ impl<'tcx> Validator<'_, 'tcx> {
|
|||
// 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) {
|
||||
|
|
@ -930,7 +926,7 @@ impl<'a, 'tcx> Promoter<'a, 'tcx> {
|
|||
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(
|
||||
|
|
@ -965,10 +961,7 @@ impl<'a, 'tcx> Promoter<'a, 'tcx> {
|
|||
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(),
|
||||
},
|
||||
)
|
||||
|
|
|
|||
|
|
@ -261,7 +261,7 @@ fn check_place(
|
|||
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() {
|
||||
|
|
|
|||
|
|
@ -388,9 +388,7 @@ impl<'tcx> MutVisitor<'tcx> for LocalUpdater<'tcx> {
|
|||
// 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);
|
||||
|
|
|
|||
|
|
@ -137,9 +137,9 @@ struct VarField<'tcx> {
|
|||
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,
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -46,7 +46,7 @@ where
|
|||
// 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,
|
||||
_ => {}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue