diff --git a/compiler/rustc_borrowck/src/diagnostics/mod.rs b/compiler/rustc_borrowck/src/diagnostics/mod.rs index 63b16aa95a6a5..24d11ac718129 100644 --- a/compiler/rustc_borrowck/src/diagnostics/mod.rs +++ b/compiler/rustc_borrowck/src/diagnostics/mod.rs @@ -46,6 +46,7 @@ pub(crate) use region_errors::{ErrorConstraintInfo, RegionErrorKind, RegionError pub(crate) use region_name::{RegionName, RegionNameSource}; pub(crate) use rustc_const_eval::util::CallKind; +#[derive(Copy, Clone)] pub(super) struct DescribePlaceOpt { pub including_downcast: bool, @@ -265,7 +266,9 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { } ProjectionElem::Index(index) => { buf.push('['); - if self.append_local_to_string(*index, &mut buf).is_err() { + if let Some(index) = self.describe_place_with_options(index.as_ref(), opt) { + buf.push_str(&index); + } else { buf.push('_'); } buf.push(']'); diff --git a/compiler/rustc_codegen_cranelift/src/base.rs b/compiler/rustc_codegen_cranelift/src/base.rs index 89d955e8bf2e1..2f313d2e5a6fe 100644 --- a/compiler/rustc_codegen_cranelift/src/base.rs +++ b/compiler/rustc_codegen_cranelift/src/base.rs @@ -851,8 +851,8 @@ pub(crate) fn codegen_place<'tcx>( PlaceElem::Field(field, _ty) => { cplace = cplace.place_field(fx, field); } - PlaceElem::Index(local) => { - let index = fx.get_local_place(local).to_cvalue(fx).load_scalar(fx); + PlaceElem::Index(index) => { + let index = codegen_place(fx, index).to_cvalue(fx).load_scalar(fx); cplace = cplace.place_index(fx, index); } PlaceElem::ConstantIndex { offset, min_length: _, from_end } => { diff --git a/compiler/rustc_codegen_ssa/src/mir/analyze.rs b/compiler/rustc_codegen_ssa/src/mir/analyze.rs index c7617d2e464fa..f685d72139a8d 100644 --- a/compiler/rustc_codegen_ssa/src/mir/analyze.rs +++ b/compiler/rustc_codegen_ssa/src/mir/analyze.rs @@ -141,9 +141,9 @@ impl<'mir, 'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> LocalAnalyzer<'mir, 'a, 'tcx, // HACK(eddyb) this emulates the old `visit_projection_elem`, this // entire `visit_place`-like `process_place` method should be rewritten, // now that we have moved to the "slice of projections" representation. - if let mir::ProjectionElem::Index(local) = elem { - self.visit_local( - local, + if let mir::ProjectionElem::Index(ref index) = elem { + self.visit_place( + index, PlaceContext::NonMutatingUse(NonMutatingUseContext::Copy), location, ); diff --git a/compiler/rustc_const_eval/src/interpret/projection.rs b/compiler/rustc_const_eval/src/interpret/projection.rs index 291464ab58ae2..08bfda487fc86 100644 --- a/compiler/rustc_const_eval/src/interpret/projection.rs +++ b/compiler/rustc_const_eval/src/interpret/projection.rs @@ -360,9 +360,9 @@ where Field(field, _) => self.place_field(base, field.index())?, Downcast(_, variant) => self.place_downcast(base, variant)?, Deref => self.deref_operand(&self.place_to_op(base)?)?.into(), - Index(local) => { + Index(place) => { let layout = self.layout_of(self.tcx.types.usize)?; - let n = self.local_to_op(self.frame(), local, Some(layout))?; + let n = self.eval_place_to_op(place, Some(layout))?; let n = self.read_machine_usize(&n)?; self.place_index(base, n)? } @@ -389,9 +389,9 @@ where Field(field, _) => self.operand_field(base, field.index())?, Downcast(_, variant) => self.operand_downcast(base, variant)?, Deref => self.deref_operand(base)?.into(), - Index(local) => { + Index(place) => { let layout = self.layout_of(self.tcx.types.usize)?; - let n = self.local_to_op(self.frame(), local, Some(layout))?; + let n = self.eval_place_to_op(place, Some(layout))?; let n = self.read_machine_usize(&n)?; self.operand_index(base, n)? } diff --git a/compiler/rustc_const_eval/src/transform/check_consts/qualifs.rs b/compiler/rustc_const_eval/src/transform/check_consts/qualifs.rs index 8ca3fdf400eb3..b1ef3b5fa0ddb 100644 --- a/compiler/rustc_const_eval/src/transform/check_consts/qualifs.rs +++ b/compiler/rustc_const_eval/src/transform/check_consts/qualifs.rs @@ -298,7 +298,9 @@ where let mut place = place; while let Some((place_base, elem)) = place.last_projection() { match elem { - ProjectionElem::Index(index) if in_local(index) => return true, + ProjectionElem::Index(index) if in_place::<Q, _>(cx, in_local, index.as_ref()) => { + return true; + } ProjectionElem::Deref | ProjectionElem::Field(_, _) diff --git a/compiler/rustc_const_eval/src/transform/promote_consts.rs b/compiler/rustc_const_eval/src/transform/promote_consts.rs index 04ce701452b90..67c85098db916 100644 --- a/compiler/rustc_const_eval/src/transform/promote_consts.rs +++ b/compiler/rustc_const_eval/src/transform/promote_consts.rs @@ -361,27 +361,28 @@ impl<'tcx> Validator<'_, 'tcx> { ProjectionElem::ConstantIndex { .. } | ProjectionElem::Subslice { .. } => {} - ProjectionElem::Index(local) => { + ProjectionElem::Index(place) => { let mut promotable = false; // Only accept if we can predict the index and are indexing an array. - let val = - if let TempState::Defined { location: loc, .. } = self.temps[local] { - let block = &self.body[loc.block]; - if loc.statement_index < block.statements.len() { - let statement = &block.statements[loc.statement_index]; - match &statement.kind { - StatementKind::Assign(box ( - _, - Rvalue::Use(Operand::Constant(c)), - )) => c.literal.try_eval_usize(self.tcx, self.param_env), - _ => None, - } - } else { - None + let val = if let Some(local) = place.as_local() + && let TempState::Defined { location: loc, .. } = self.temps[local] + { + let block = &self.body[loc.block]; + if loc.statement_index < block.statements.len() { + let statement = &block.statements[loc.statement_index]; + match &statement.kind { + StatementKind::Assign(box ( + _, + Rvalue::Use(Operand::Constant(c)), + )) => c.literal.try_eval_usize(self.tcx, self.param_env), + _ => None, } } else { None - }; + } + } else { + None + }; if let Some(idx) = val { // Determine the type of the thing we are indexing. let ty = place_base.ty(self.body, self.tcx).ty; @@ -403,7 +404,7 @@ impl<'tcx> Validator<'_, 'tcx> { return Err(Unpromotable); } - self.validate_local(local)?; + self.validate_place(place.as_ref())?; } ProjectionElem::Field(..) => { diff --git a/compiler/rustc_const_eval/src/transform/validate.rs b/compiler/rustc_const_eval/src/transform/validate.rs index 94e1b95a0eb3c..34723b13ec018 100644 --- a/compiler/rustc_const_eval/src/transform/validate.rs +++ b/compiler/rustc_const_eval/src/transform/validate.rs @@ -204,8 +204,8 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> { location: Location, ) { match elem { - ProjectionElem::Index(index) => { - let index_ty = self.body.local_decls[index].ty; + ProjectionElem::Index(ref index) => { + let index_ty = Place::ty(index, &self.body.local_decls, self.tcx).ty; if index_ty != self.tcx.types.usize { self.fail(location, format!("bad index ({:?} != usize)", index_ty)) } diff --git a/compiler/rustc_middle/src/mir/syntax.rs b/compiler/rustc_middle/src/mir/syntax.rs index 6b4489026d3d3..98243c9ded3d2 100644 --- a/compiler/rustc_middle/src/mir/syntax.rs +++ b/compiler/rustc_middle/src/mir/syntax.rs @@ -956,7 +956,7 @@ pub enum ProjectionElem<V, T> { /// Alias for projections as they appear in places, where the base is a place /// and the index is a local. -pub type PlaceElem<'tcx> = ProjectionElem<Local, Ty<'tcx>>; +pub type PlaceElem<'tcx> = ProjectionElem<Place<'tcx>, Ty<'tcx>>; /////////////////////////////////////////////////////////////////////////// // Operands diff --git a/compiler/rustc_middle/src/mir/visit.rs b/compiler/rustc_middle/src/mir/visit.rs index 1a264d2d5af9a..4a1ea5198f6fd 100644 --- a/compiler/rustc_middle/src/mir/visit.rs +++ b/compiler/rustc_middle/src/mir/visit.rs @@ -1078,15 +1078,15 @@ macro_rules! visit_place_fns { location: Location, ) -> Option<PlaceElem<'tcx>> { match elem { - PlaceElem::Index(local) => { - let mut new_local = local; - self.visit_local( - &mut new_local, + PlaceElem::Index(place) => { + let mut new_place = place; + self.visit_place( + &mut new_place, PlaceContext::NonMutatingUse(NonMutatingUseContext::Copy), location, ); - if new_local == local { None } else { Some(PlaceElem::Index(new_local)) } + if new_place == place { None } else { Some(PlaceElem::Index(new_place)) } } PlaceElem::Field(field, ty) => { let mut new_ty = ty; @@ -1170,9 +1170,9 @@ macro_rules! visit_place_fns { ProjectionElem::OpaqueCast(ty) | ProjectionElem::Field(_, ty) => { self.visit_ty(ty, TyContext::Location(location)); } - ProjectionElem::Index(local) => { - self.visit_local( - local, + ProjectionElem::Index(ref place) => { + self.visit_place( + place, PlaceContext::NonMutatingUse(NonMutatingUseContext::Copy), location, ); diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs index 5de414077a2b1..a767bff1eb9bf 100644 --- a/compiler/rustc_middle/src/ty/context.rs +++ b/compiler/rustc_middle/src/ty/context.rs @@ -2048,7 +2048,7 @@ impl<'tcx> TyCtxt<'tcx> { } pub fn mk_place_index(self, place: Place<'tcx>, index: Local) -> Place<'tcx> { - self.mk_place_elem(place, PlaceElem::Index(index)) + self.mk_place_elem(place, PlaceElem::Index(index.into())) } /// This method copies `Place`'s projection, add an element and reintern it. Should not be used diff --git a/compiler/rustc_mir_build/src/build/custom/parse/instruction.rs b/compiler/rustc_mir_build/src/build/custom/parse/instruction.rs index dca4906c07de5..7940697f262eb 100644 --- a/compiler/rustc_mir_build/src/build/custom/parse/instruction.rs +++ b/compiler/rustc_mir_build/src/build/custom/parse/instruction.rs @@ -190,7 +190,7 @@ impl<'tcx, 'body> ParseCtxt<'tcx, 'body> { _ => (*arg, PlaceElem::Deref), ) }, - ExprKind::Index { lhs, index } => (*lhs, PlaceElem::Index(self.parse_local(*index)?)), + ExprKind::Index { lhs, index } => (*lhs, PlaceElem::Index(self.parse_place(*index)?)), ExprKind::Field { lhs, name: field, .. } => (*lhs, PlaceElem::Field(*field, expr.ty)), _ => { let place = self.parse_local(expr_id).map(Place::from)?; diff --git a/compiler/rustc_mir_build/src/build/expr/as_place.rs b/compiler/rustc_mir_build/src/build/expr/as_place.rs index e22fa6365dcb4..e41df49e03fef 100644 --- a/compiler/rustc_mir_build/src/build/expr/as_place.rs +++ b/compiler/rustc_mir_build/src/build/expr/as_place.rs @@ -308,7 +308,7 @@ impl<'tcx> PlaceBuilder<'tcx> { } fn index(self, index: Local) -> Self { - self.project(PlaceElem::Index(index)) + self.project(PlaceElem::Index(index.into())) } pub(crate) fn project(mut self, elem: PlaceElem<'tcx>) -> Self { diff --git a/compiler/rustc_mir_dataflow/src/move_paths/abs_domain.rs b/compiler/rustc_mir_dataflow/src/move_paths/abs_domain.rs index 7806e8f45d3ad..6de8e9122c438 100644 --- a/compiler/rustc_mir_dataflow/src/move_paths/abs_domain.rs +++ b/compiler/rustc_mir_dataflow/src/move_paths/abs_domain.rs @@ -11,7 +11,7 @@ //! `a[x]` would still overlap them both. But that is not this //! representation does today.) -use rustc_middle::mir::{Local, Operand, PlaceElem, ProjectionElem}; +use rustc_middle::mir::{Local, Operand, Place, PlaceElem, ProjectionElem}; use rustc_middle::ty::Ty; #[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)] @@ -36,6 +36,12 @@ impl Lift for Local { AbstractOperand } } +impl<'tcx> Lift for Place<'tcx> { + type Abstract = AbstractOperand; + fn lift(&self) -> Self::Abstract { + AbstractOperand + } +} impl<'tcx> Lift for Ty<'tcx> { type Abstract = AbstractType; fn lift(&self) -> Self::Abstract { diff --git a/compiler/rustc_mir_transform/src/generator.rs b/compiler/rustc_mir_transform/src/generator.rs index c097af6161159..7b8e40f074ad5 100644 --- a/compiler/rustc_mir_transform/src/generator.rs +++ b/compiler/rustc_mir_transform/src/generator.rs @@ -128,13 +128,7 @@ impl<'tcx> MutVisitor<'tcx> for DerefArgVisitor<'tcx> { self.tcx, ); } else { - self.visit_local(&mut place.local, context, location); - - for elem in place.projection.iter() { - if let PlaceElem::Index(local) = elem { - assert_ne!(local, SELF_ARG); - } - } + self.super_place(place, context, location); } } } @@ -167,13 +161,7 @@ impl<'tcx> MutVisitor<'tcx> for PinArgVisitor<'tcx> { self.tcx, ); } else { - self.visit_local(&mut place.local, context, location); - - for elem in place.projection.iter() { - if let PlaceElem::Index(local) = elem { - assert_ne!(local, SELF_ARG); - } - } + self.super_place(place, context, location); } } } diff --git a/compiler/rustc_mir_transform/src/inline.rs b/compiler/rustc_mir_transform/src/inline.rs index 4219e6280ebbc..fc214c0868673 100644 --- a/compiler/rustc_mir_transform/src/inline.rs +++ b/compiler/rustc_mir_transform/src/inline.rs @@ -1054,12 +1054,6 @@ impl<'tcx> MutVisitor<'tcx> for Integrator<'_, 'tcx> { } fn visit_place(&mut self, place: &mut Place<'tcx>, context: PlaceContext, location: Location) { - for elem in place.projection { - // FIXME: Make sure that return place is not used in an indexing projection, since it - // won't be rebased as it is supposed to be. - assert_ne!(ProjectionElem::Index(RETURN_PLACE), elem); - } - // 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 { diff --git a/src/test/mir-opt/inline/issue_106141.rs b/src/test/mir-opt/inline/issue_106141.rs new file mode 100644 index 0000000000000..538d687a47699 --- /dev/null +++ b/src/test/mir-opt/inline/issue_106141.rs @@ -0,0 +1,23 @@ +pub fn outer() -> usize { + inner() +} + +fn index() -> usize { + loop {} +} + +#[inline] +fn inner() -> usize { + let buffer = &[true]; + let index = index(); + // DestProp may unify `index` with `_0`. Check that inlining does not ICE. + if buffer[index] { + index + } else { + 0 + } +} + +fn main() { + let _ = outer(); +}