1
Fork 0

Introduce opaque type to hidden type projection

This commit is contained in:
Oli Scherer 2022-06-22 15:28:28 +00:00
parent 116819f54f
commit 84a444a1f4
23 changed files with 97 additions and 6 deletions

View file

@ -2093,7 +2093,9 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
} }
StorageDeadOrDrop::Destructor(_) => kind, StorageDeadOrDrop::Destructor(_) => kind,
}, },
ProjectionElem::Field(..) | ProjectionElem::Downcast(..) => { ProjectionElem::OpaqueCast { .. }
| ProjectionElem::Field(..)
| ProjectionElem::Downcast(..) => {
match place_ty.ty.kind() { match place_ty.ty.kind() {
ty::Adt(def, _) if def.has_dtor(tcx) => { ty::Adt(def, _) if def.has_dtor(tcx) => {
// Report the outermost adt with a destructor // Report the outermost adt with a destructor

View file

@ -226,6 +226,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
} }
ProjectionElem::Downcast(..) if including_downcast.0 => return None, ProjectionElem::Downcast(..) if including_downcast.0 => return None,
ProjectionElem::Downcast(..) => (), ProjectionElem::Downcast(..) => (),
ProjectionElem::OpaqueCast(..) => (),
ProjectionElem::Field(field, _ty) => { ProjectionElem::Field(field, _ty) => {
// FIXME(project-rfc_2229#36): print capture precisely here. // FIXME(project-rfc_2229#36): print capture precisely here.
if let Some(field) = self.is_upvar_field_projection(PlaceRef { if let Some(field) = self.is_upvar_field_projection(PlaceRef {
@ -286,6 +287,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
PlaceRef { local, projection: proj_base }.ty(self.body, self.infcx.tcx) PlaceRef { local, projection: proj_base }.ty(self.body, self.infcx.tcx)
} }
ProjectionElem::Downcast(..) => place.ty(self.body, self.infcx.tcx), ProjectionElem::Downcast(..) => place.ty(self.body, self.infcx.tcx),
ProjectionElem::OpaqueCast(ty) => PlaceTy::from_ty(*ty),
ProjectionElem::Field(_, field_type) => PlaceTy::from_ty(*field_type), ProjectionElem::Field(_, field_type) => PlaceTy::from_ty(*field_type),
}, },
}; };

View file

@ -169,6 +169,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
.., ..,
ProjectionElem::Index(_) ProjectionElem::Index(_)
| ProjectionElem::ConstantIndex { .. } | ProjectionElem::ConstantIndex { .. }
| ProjectionElem::OpaqueCast { .. }
| ProjectionElem::Subslice { .. } | ProjectionElem::Subslice { .. }
| ProjectionElem::Downcast(..), | ProjectionElem::Downcast(..),
], ],

View file

@ -1788,6 +1788,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
for (place_base, elem) in place.iter_projections().rev() { for (place_base, elem) in place.iter_projections().rev() {
match elem { match elem {
ProjectionElem::Index(_/*operand*/) | ProjectionElem::Index(_/*operand*/) |
ProjectionElem::OpaqueCast(_) |
ProjectionElem::ConstantIndex { .. } | ProjectionElem::ConstantIndex { .. } |
// assigning to P[i] requires P to be valid. // assigning to P[i] requires P to be valid.
ProjectionElem::Downcast(_/*adt_def*/, _/*variant_idx*/) => ProjectionElem::Downcast(_/*adt_def*/, _/*variant_idx*/) =>
@ -2179,6 +2180,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
| ProjectionElem::Index(..) | ProjectionElem::Index(..)
| ProjectionElem::ConstantIndex { .. } | ProjectionElem::ConstantIndex { .. }
| ProjectionElem::Subslice { .. } | ProjectionElem::Subslice { .. }
| ProjectionElem::OpaqueCast { .. }
| ProjectionElem::Downcast(..) => { | ProjectionElem::Downcast(..) => {
let upvar_field_projection = self.is_upvar_field_projection(place); let upvar_field_projection = self.is_upvar_field_projection(place);
if let Some(field) = upvar_field_projection { if let Some(field) = upvar_field_projection {

View file

@ -255,6 +255,7 @@ fn place_components_conflict<'tcx>(
| (ProjectionElem::Index { .. }, _, _) | (ProjectionElem::Index { .. }, _, _)
| (ProjectionElem::ConstantIndex { .. }, _, _) | (ProjectionElem::ConstantIndex { .. }, _, _)
| (ProjectionElem::Subslice { .. }, _, _) | (ProjectionElem::Subslice { .. }, _, _)
| (ProjectionElem::OpaqueCast { .. }, _, _)
| (ProjectionElem::Downcast { .. }, _, _) => { | (ProjectionElem::Downcast { .. }, _, _) => {
// Recursive case. This can still be disjoint on a // Recursive case. This can still be disjoint on a
// further iteration if this a shallow access and // further iteration if this a shallow access and
@ -322,6 +323,17 @@ fn place_projection_conflict<'tcx>(
debug!("place_element_conflict: DISJOINT-OR-EQ-DEREF"); debug!("place_element_conflict: DISJOINT-OR-EQ-DEREF");
Overlap::EqualOrDisjoint Overlap::EqualOrDisjoint
} }
(ProjectionElem::OpaqueCast(v1), ProjectionElem::OpaqueCast(v2)) => {
if v1 == v2 {
// same type - recur.
debug!("place_element_conflict: DISJOINT-OR-EQ-OPAQUE");
Overlap::EqualOrDisjoint
} else {
// Different types. Disjoint!
debug!("place_element_conflict: DISJOINT-OPAQUE");
Overlap::Disjoint
}
}
(ProjectionElem::Field(f1, _), ProjectionElem::Field(f2, _)) => { (ProjectionElem::Field(f1, _), ProjectionElem::Field(f2, _)) => {
if f1 == f2 { if f1 == f2 {
// same field (e.g., `a.y` vs. `a.y`) - recur. // same field (e.g., `a.y` vs. `a.y`) - recur.
@ -525,6 +537,7 @@ fn place_projection_conflict<'tcx>(
| ProjectionElem::Field(..) | ProjectionElem::Field(..)
| ProjectionElem::Index(..) | ProjectionElem::Index(..)
| ProjectionElem::ConstantIndex { .. } | ProjectionElem::ConstantIndex { .. }
| ProjectionElem::OpaqueCast { .. }
| ProjectionElem::Subslice { .. } | ProjectionElem::Subslice { .. }
| ProjectionElem::Downcast(..), | ProjectionElem::Downcast(..),
_, _,

View file

@ -81,6 +81,7 @@ impl<'cx, 'tcx> Iterator for Prefixes<'cx, 'tcx> {
} }
ProjectionElem::Downcast(..) ProjectionElem::Downcast(..)
| ProjectionElem::Subslice { .. } | ProjectionElem::Subslice { .. }
| ProjectionElem::OpaqueCast { .. }
| ProjectionElem::ConstantIndex { .. } | ProjectionElem::ConstantIndex { .. }
| ProjectionElem::Index(_) => { | ProjectionElem::Index(_) => {
cursor = cursor_base; cursor = cursor_base;

View file

@ -790,6 +790,11 @@ impl<'a, 'b, 'tcx> TypeVerifier<'a, 'b, 'tcx> {
} }
PlaceTy::from_ty(fty) PlaceTy::from_ty(fty)
} }
ProjectionElem::OpaqueCast(ty) => {
let ty = self.sanitize_type(place, ty);
let ty = self.cx.normalize(ty, location);
PlaceTy::from_ty(ty)
}
} }
} }
@ -1195,10 +1200,11 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
tcx, tcx,
self.param_env, self.param_env,
proj, proj,
|this, field, ()| { |this, field, _| {
let ty = this.field_ty(tcx, field); let ty = this.field_ty(tcx, field);
self.normalize(ty, locations) self.normalize(ty, locations)
}, },
|_, _| unreachable!(),
); );
curr_projected_ty = projected_ty; curr_projected_ty = projected_ty;
} }
@ -2493,6 +2499,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
} }
ProjectionElem::Field(..) ProjectionElem::Field(..)
| ProjectionElem::Downcast(..) | ProjectionElem::Downcast(..)
| ProjectionElem::OpaqueCast(..)
| ProjectionElem::Index(..) | ProjectionElem::Index(..)
| ProjectionElem::ConstantIndex { .. } | ProjectionElem::ConstantIndex { .. }
| ProjectionElem::Subslice { .. } => { | ProjectionElem::Subslice { .. } => {

View file

@ -825,6 +825,7 @@ pub(crate) fn codegen_place<'tcx>(
cplace = cplace.place_deref(fx); cplace = cplace.place_deref(fx);
} }
} }
PlaceElem::OpaqueCast(ty) => cplace = cplace.place_opaque_cast(fx, ty),
PlaceElem::Field(field, _ty) => { PlaceElem::Field(field, _ty) => {
cplace = cplace.place_field(fx, field); cplace = cplace.place_field(fx, field);
} }

View file

@ -615,6 +615,14 @@ impl<'tcx> CPlace<'tcx> {
} }
} }
pub(crate) fn place_opaque_cast(
self,
fx: &mut FunctionCx<'_, '_, 'tcx>,
ty: Ty<'tcx>,
) -> CPlace<'tcx> {
CPlace { inner: self.inner, layout: fx.layout_of(ty) }
}
pub(crate) fn place_field( pub(crate) fn place_field(
self, self,
fx: &mut FunctionCx<'_, '_, 'tcx>, fx: &mut FunctionCx<'_, '_, 'tcx>,

View file

@ -411,6 +411,21 @@ impl<'a, 'tcx, V: CodegenObject> PlaceRef<'tcx, V> {
downcast downcast
} }
pub fn project_type<Bx: BuilderMethods<'a, 'tcx, Value = V>>(
&self,
bx: &mut Bx,
ty: Ty<'tcx>,
) -> Self {
let mut downcast = *self;
downcast.layout = bx.cx().layout_of(ty);
// Cast to the appropriate type.
let variant_ty = bx.cx().backend_type(downcast.layout);
downcast.llval = bx.pointercast(downcast.llval, bx.cx().type_ptr_to(variant_ty));
downcast
}
pub fn storage_live<Bx: BuilderMethods<'a, 'tcx, Value = V>>(&self, bx: &mut Bx) { pub fn storage_live<Bx: BuilderMethods<'a, 'tcx, Value = V>>(&self, bx: &mut Bx) {
bx.lifetime_start(self.llval, self.layout.size); bx.lifetime_start(self.llval, self.layout.size);
} }
@ -459,6 +474,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
mir::ProjectionElem::Field(ref field, _) => { mir::ProjectionElem::Field(ref field, _) => {
cg_base.project_field(bx, field.index()) cg_base.project_field(bx, field.index())
} }
mir::ProjectionElem::OpaqueCast(ty) => cg_base.project_type(bx, ty),
mir::ProjectionElem::Index(index) => { mir::ProjectionElem::Index(index) => {
let index = &mir::Operand::Copy(mir::Place::from(index)); let index = &mir::Operand::Copy(mir::Place::from(index));
let index = self.codegen_operand(bx, index); let index = self.codegen_operand(bx, index);

View file

@ -351,6 +351,11 @@ where
) -> InterpResult<'tcx, PlaceTy<'tcx, M::PointerTag>> { ) -> InterpResult<'tcx, PlaceTy<'tcx, M::PointerTag>> {
use rustc_middle::mir::ProjectionElem::*; use rustc_middle::mir::ProjectionElem::*;
Ok(match proj_elem { Ok(match proj_elem {
OpaqueCast(ty) => {
let mut place = *base;
place.layout = self.layout_of(ty)?;
place
}
Field(field, _) => self.place_field(base, field.index())?, Field(field, _) => self.place_field(base, field.index())?,
Downcast(_, variant) => self.place_downcast(base, variant)?, Downcast(_, variant) => self.place_downcast(base, variant)?,
Deref => self.deref_operand(&self.place_to_op(base)?)?.into(), Deref => self.deref_operand(&self.place_to_op(base)?)?.into(),
@ -375,6 +380,11 @@ where
) -> InterpResult<'tcx, OpTy<'tcx, M::PointerTag>> { ) -> InterpResult<'tcx, OpTy<'tcx, M::PointerTag>> {
use rustc_middle::mir::ProjectionElem::*; use rustc_middle::mir::ProjectionElem::*;
Ok(match proj_elem { Ok(match proj_elem {
OpaqueCast(ty) => {
let mut op = *base;
op.layout = self.layout_of(ty)?;
op
}
Field(field, _) => self.operand_field(base, field.index())?, Field(field, _) => self.operand_field(base, field.index())?,
Downcast(_, variant) => self.operand_downcast(base, variant)?, Downcast(_, variant) => self.operand_downcast(base, variant)?,
Deref => self.deref_operand(base)?.into(), Deref => self.deref_operand(base)?.into(),

View file

@ -652,6 +652,7 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> {
ProjectionElem::ConstantIndex { .. } ProjectionElem::ConstantIndex { .. }
| ProjectionElem::Downcast(..) | ProjectionElem::Downcast(..)
| ProjectionElem::OpaqueCast(..)
| ProjectionElem::Subslice { .. } | ProjectionElem::Subslice { .. }
| ProjectionElem::Field(..) | ProjectionElem::Field(..)
| ProjectionElem::Index(_) => {} | ProjectionElem::Index(_) => {}

View file

@ -316,6 +316,7 @@ where
ProjectionElem::Deref ProjectionElem::Deref
| ProjectionElem::Field(_, _) | ProjectionElem::Field(_, _)
| ProjectionElem::OpaqueCast(_)
| ProjectionElem::ConstantIndex { .. } | ProjectionElem::ConstantIndex { .. }
| ProjectionElem::Subslice { .. } | ProjectionElem::Subslice { .. }
| ProjectionElem::Downcast(_, _) | ProjectionElem::Downcast(_, _)

View file

@ -361,7 +361,7 @@ impl<'tcx> Validator<'_, 'tcx> {
return Err(Unpromotable); return Err(Unpromotable);
} }
} }
ProjectionElem::Downcast(..) => { ProjectionElem::OpaqueCast(..) | ProjectionElem::Downcast(..) => {
return Err(Unpromotable); return Err(Unpromotable);
} }

View file

@ -1397,6 +1397,7 @@ impl<V, T> ProjectionElem<V, T> {
Self::Field(_, _) Self::Field(_, _)
| Self::Index(_) | Self::Index(_)
| Self::OpaqueCast(_)
| Self::ConstantIndex { .. } | Self::ConstantIndex { .. }
| Self::Subslice { .. } | Self::Subslice { .. }
| Self::Downcast(_, _) => false, | Self::Downcast(_, _) => false,
@ -1574,7 +1575,9 @@ impl Debug for Place<'_> {
fn fmt(&self, fmt: &mut Formatter<'_>) -> fmt::Result { fn fmt(&self, fmt: &mut Formatter<'_>) -> fmt::Result {
for elem in self.projection.iter().rev() { for elem in self.projection.iter().rev() {
match elem { match elem {
ProjectionElem::Downcast(_, _) | ProjectionElem::Field(_, _) => { ProjectionElem::OpaqueCast(_)
| ProjectionElem::Downcast(_, _)
| ProjectionElem::Field(_, _) => {
write!(fmt, "(").unwrap(); write!(fmt, "(").unwrap();
} }
ProjectionElem::Deref => { ProjectionElem::Deref => {
@ -1590,6 +1593,9 @@ impl Debug for Place<'_> {
for elem in self.projection.iter() { for elem in self.projection.iter() {
match elem { match elem {
ProjectionElem::OpaqueCast(ty) => {
write!(fmt, " as {})", ty)?;
}
ProjectionElem::Downcast(Some(name), _index) => { ProjectionElem::Downcast(Some(name), _index) => {
write!(fmt, " as {})", name)?; write!(fmt, " as {})", name)?;
} }

View file

@ -754,6 +754,9 @@ pub type AssertMessage<'tcx> = AssertKind<Operand<'tcx>>;
/// generator has more than one variant, the parent place's variant index must be set, indicating /// generator has more than one variant, the parent place's variant index must be set, indicating
/// which variant is being used. If it has just one variant, the variant index may or may not be /// which variant is being used. If it has just one variant, the variant index may or may not be
/// included - the single possible variant is inferred if it is not included. /// included - the single possible variant is inferred if it is not included.
/// - [`OpaqueCast`](ProjectionElem::OpaqueCast): This projection changes the place's type to the
/// given one, and makes no other changes. A `OpaqueCast` projection on any type other than an
/// opaque type from the current crate is not well-formed.
/// - [`ConstantIndex`](ProjectionElem::ConstantIndex): Computes an offset in units of `T` into the /// - [`ConstantIndex`](ProjectionElem::ConstantIndex): Computes an offset in units of `T` into the
/// place as described in the documentation for the `ProjectionElem`. The resulting address is /// place as described in the documentation for the `ProjectionElem`. The resulting address is
/// the parent's address plus that offset, and the type is `T`. This is only legal if the parent /// the parent's address plus that offset, and the type is `T`. This is only legal if the parent
@ -856,6 +859,10 @@ pub enum ProjectionElem<V, T> {
/// ///
/// The included Symbol is the name of the variant, used for printing MIR. /// The included Symbol is the name of the variant, used for printing MIR.
Downcast(Option<Symbol>, VariantIdx), Downcast(Option<Symbol>, VariantIdx),
/// Like an explicit cast from an opaque type to a concrete type, but without
/// requiring an intermediate variable.
OpaqueCast(T),
} }
/// Alias for projections as they appear in places, where the base is a place /// Alias for projections as they appear in places, where the base is a place

View file

@ -57,7 +57,7 @@ impl<'tcx> PlaceTy<'tcx> {
/// `PlaceElem`, where we can just use the `Ty` that is already /// `PlaceElem`, where we can just use the `Ty` that is already
/// stored inline on field projection elems. /// stored inline on field projection elems.
pub fn projection_ty(self, tcx: TyCtxt<'tcx>, elem: PlaceElem<'tcx>) -> PlaceTy<'tcx> { pub fn projection_ty(self, tcx: TyCtxt<'tcx>, elem: PlaceElem<'tcx>) -> PlaceTy<'tcx> {
self.projection_ty_core(tcx, ty::ParamEnv::empty(), &elem, |_, _, ty| ty) self.projection_ty_core(tcx, ty::ParamEnv::empty(), &elem, |_, _, ty| ty, |_, ty| ty)
} }
/// `place_ty.projection_ty_core(tcx, elem, |...| { ... })` /// `place_ty.projection_ty_core(tcx, elem, |...| { ... })`
@ -71,6 +71,7 @@ impl<'tcx> PlaceTy<'tcx> {
param_env: ty::ParamEnv<'tcx>, param_env: ty::ParamEnv<'tcx>,
elem: &ProjectionElem<V, T>, elem: &ProjectionElem<V, T>,
mut handle_field: impl FnMut(&Self, Field, T) -> Ty<'tcx>, mut handle_field: impl FnMut(&Self, Field, T) -> Ty<'tcx>,
mut handle_opaque_cast: impl FnMut(&Self, T) -> Ty<'tcx>,
) -> PlaceTy<'tcx> ) -> PlaceTy<'tcx>
where where
V: ::std::fmt::Debug, V: ::std::fmt::Debug,
@ -109,6 +110,7 @@ impl<'tcx> PlaceTy<'tcx> {
PlaceTy { ty: self.ty, variant_index: Some(index) } PlaceTy { ty: self.ty, variant_index: Some(index) }
} }
ProjectionElem::Field(f, fty) => PlaceTy::from_ty(handle_field(&self, f, fty)), ProjectionElem::Field(f, fty) => PlaceTy::from_ty(handle_field(&self, f, fty)),
ProjectionElem::OpaqueCast(ty) => PlaceTy::from_ty(handle_opaque_cast(&self, ty)),
}; };
debug!("projection_ty self: {:?} elem: {:?} yields: {:?}", self, elem, answer); debug!("projection_ty self: {:?} elem: {:?} yields: {:?}", self, elem, answer);
answer answer

View file

@ -182,6 +182,7 @@ impl<'tcx> TypeFoldable<'tcx> for PlaceElem<'tcx> {
Ok(match self { Ok(match self {
Deref => Deref, Deref => Deref,
Field(f, ty) => Field(f, ty.try_fold_with(folder)?), Field(f, ty) => Field(f, ty.try_fold_with(folder)?),
OpaqueCast(ty) => OpaqueCast(ty.try_fold_with(folder)?),
Index(v) => Index(v.try_fold_with(folder)?), Index(v) => Index(v.try_fold_with(folder)?),
Downcast(symbol, variantidx) => Downcast(symbol, variantidx), Downcast(symbol, variantidx) => Downcast(symbol, variantidx),
ConstantIndex { offset, min_length, from_end } => { ConstantIndex { offset, min_length, from_end } => {

View file

@ -1064,6 +1064,11 @@ macro_rules! visit_place_fns {
self.visit_ty(&mut new_ty, TyContext::Location(location)); self.visit_ty(&mut new_ty, TyContext::Location(location));
if ty != new_ty { Some(PlaceElem::Field(field, new_ty)) } else { None } if ty != new_ty { Some(PlaceElem::Field(field, new_ty)) } else { None }
} }
PlaceElem::OpaqueCast(ty) => {
let mut new_ty = ty;
self.visit_ty(&mut new_ty, TyContext::Location(location));
if ty != new_ty { Some(PlaceElem::OpaqueCast(new_ty)) } else { None }
}
PlaceElem::Deref PlaceElem::Deref
| PlaceElem::ConstantIndex { .. } | PlaceElem::ConstantIndex { .. }
| PlaceElem::Subslice { .. } | PlaceElem::Subslice { .. }
@ -1133,7 +1138,7 @@ macro_rules! visit_place_fns {
location: Location, location: Location,
) { ) {
match elem { match elem {
ProjectionElem::Field(_field, ty) => { ProjectionElem::OpaqueCast(ty) | ProjectionElem::Field(_, ty) => {
self.visit_ty(ty, TyContext::Location(location)); self.visit_ty(ty, TyContext::Location(location));
} }
ProjectionElem::Index(local) => { ProjectionElem::Index(local) => {

View file

@ -105,6 +105,7 @@ fn convert_to_hir_projections_and_truncate_for_capture<'tcx>(
continue; continue;
} }
ProjectionElem::Index(..) ProjectionElem::Index(..)
| ProjectionElem::OpaqueCast(_)
| ProjectionElem::ConstantIndex { .. } | ProjectionElem::ConstantIndex { .. }
| ProjectionElem::Subslice { .. } => { | ProjectionElem::Subslice { .. } => {
// We don't capture array-access projections. // We don't capture array-access projections.
@ -795,6 +796,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
} }
ProjectionElem::Field(..) ProjectionElem::Field(..)
| ProjectionElem::Downcast(..) | ProjectionElem::Downcast(..)
| ProjectionElem::OpaqueCast(..)
| ProjectionElem::ConstantIndex { .. } | ProjectionElem::ConstantIndex { .. }
| ProjectionElem::Subslice { .. } => (), | ProjectionElem::Subslice { .. } => (),
} }

View file

@ -48,6 +48,7 @@ impl<'tcx> Lift for PlaceElem<'tcx> {
match *self { match *self {
ProjectionElem::Deref => ProjectionElem::Deref, ProjectionElem::Deref => ProjectionElem::Deref,
ProjectionElem::Field(f, ty) => ProjectionElem::Field(f, ty.lift()), ProjectionElem::Field(f, ty) => ProjectionElem::Field(f, ty.lift()),
ProjectionElem::OpaqueCast(ty) => ProjectionElem::OpaqueCast(ty.lift()),
ProjectionElem::Index(ref i) => ProjectionElem::Index(i.lift()), ProjectionElem::Index(ref i) => ProjectionElem::Index(i.lift()),
ProjectionElem::Subslice { from, to, from_end } => { ProjectionElem::Subslice { from, to, from_end } => {
ProjectionElem::Subslice { from, to, from_end } ProjectionElem::Subslice { from, to, from_end }

View file

@ -28,6 +28,7 @@ fn is_stable(place: PlaceRef<'_>) -> bool {
ProjectionElem::Field { .. } | ProjectionElem::Field { .. } |
ProjectionElem::ConstantIndex { .. } | ProjectionElem::ConstantIndex { .. } |
ProjectionElem::Subslice { .. } | ProjectionElem::Subslice { .. } |
ProjectionElem::OpaqueCast { .. } |
ProjectionElem::Downcast { .. } => true, ProjectionElem::Downcast { .. } => true,
} }
}) })

View file

@ -252,6 +252,7 @@ fn check_place<'tcx>(tcx: TyCtxt<'tcx>, place: Place<'tcx>, span: Span, body: &B
} }
}, },
ProjectionElem::ConstantIndex { .. } ProjectionElem::ConstantIndex { .. }
| ProjectionElem::OpaqueCast(..)
| ProjectionElem::Downcast(..) | ProjectionElem::Downcast(..)
| ProjectionElem::Subslice { .. } | ProjectionElem::Subslice { .. }
| ProjectionElem::Deref | ProjectionElem::Deref