Skip to content

Commit 76b6446

Browse files
committed
visit_compound_place
1 parent 4bb7c02 commit 76b6446

File tree

5 files changed

+165
-26
lines changed

5 files changed

+165
-26
lines changed

compiler/rustc_borrowck/src/type_check/mod.rs

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ use rustc_infer::infer::{
1919
BoundRegionConversionTime, InferCtxt, NllRegionVariableOrigin, RegionVariableOrigin,
2020
};
2121
use rustc_infer::traits::PredicateObligations;
22-
use rustc_middle::mir::visit::{NonMutatingUseContext, PlaceContext, Visitor};
22+
use rustc_middle::mir::visit::{NonMutatingUseContext, PlaceContext, ProjectionBase, Visitor};
2323
use rustc_middle::mir::*;
2424
use rustc_middle::traits::query::NoSolution;
2525
use rustc_middle::ty::adjustment::PointerCoercion;
@@ -1807,13 +1807,15 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> {
18071807
}
18081808
}
18091809

1810-
fn visit_projection_elem(
1810+
fn visit_projection_elem<P>(
18111811
&mut self,
1812-
place: PlaceRef<'tcx>,
1812+
place: P,
18131813
elem: PlaceElem<'tcx>,
18141814
context: PlaceContext,
18151815
location: Location,
1816-
) {
1816+
) where
1817+
P: ProjectionBase<'tcx>,
1818+
{
18171819
let tcx = self.tcx();
18181820
let base_ty = place.ty(self.body(), tcx);
18191821
match elem {

compiler/rustc_middle/src/mir/statement.rs

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -589,14 +589,6 @@ impl<'tcx> CompoundPlace<'tcx> {
589589
CompoundPlaceRef { local: self.local, projection_chain_base: base, last_projection: last }
590590
}
591591

592-
pub fn ty<D: ?Sized>(&self, local_decls: &D, tcx: TyCtxt<'tcx>) -> PlaceTy<'tcx>
593-
where
594-
D: HasLocalDecls<'tcx>,
595-
{
596-
PlaceTy::from_ty(local_decls.local_decls()[self.local].ty)
597-
.projection_chain_ty(tcx, self.projection_chain)
598-
}
599-
600592
pub fn iter_projections(
601593
self,
602594
) -> impl Iterator<Item = (CompoundPlaceRef<'tcx>, PlaceElem<'tcx>)> + DoubleEndedIterator {
@@ -624,6 +616,14 @@ impl<'tcx> CompoundPlace<'tcx> {
624616
})
625617
})
626618
}
619+
620+
pub fn ty<D: ?Sized>(&self, local_decls: &D, tcx: TyCtxt<'tcx>) -> PlaceTy<'tcx>
621+
where
622+
D: HasLocalDecls<'tcx>,
623+
{
624+
PlaceTy::from_ty(local_decls.local_decls()[self.local].ty)
625+
.projection_chain_ty(tcx, self.projection_chain)
626+
}
627627
}
628628

629629
impl<'tcx> CompoundPlaceRef<'tcx> {

compiler/rustc_middle/src/mir/visit.rs

Lines changed: 105 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -180,6 +180,15 @@ macro_rules! make_mir_visitor {
180180
self.super_place(place, context, location);
181181
}
182182

183+
fn visit_compound_place(
184+
&mut self,
185+
place: & $($mutability)? CompoundPlace<'tcx>,
186+
context: PlaceContext,
187+
location: Location,
188+
) {
189+
self.super_compound_place(place, context, location);
190+
}
191+
183192
visit_place_fns!($($mutability)?);
184193

185194
/// This is called for every constant in the MIR body and every `required_consts`
@@ -1182,6 +1191,45 @@ macro_rules! visit_place_fns {
11821191
| PlaceElem::Downcast(..) => None,
11831192
}
11841193
}
1194+
1195+
fn super_compound_place(
1196+
&mut self,
1197+
place: &mut CompoundPlace<'tcx>,
1198+
context: PlaceContext,
1199+
location: Location,
1200+
) {
1201+
self.visit_local(&mut place.local, context, location);
1202+
1203+
if let Some(new_projection_chain) =
1204+
self.process_projection_chain(&place.projection_chain, location)
1205+
{
1206+
place.projection_chain = self.tcx().mk_place_elem_chain(&new_projection_chain);
1207+
}
1208+
}
1209+
1210+
fn process_projection_chain<'a>(
1211+
&mut self,
1212+
projection_chain: &'a [&'tcx List<PlaceElem<'tcx>>],
1213+
location: Location,
1214+
) -> Option<Vec<&'tcx List<PlaceElem<'tcx>>>> {
1215+
let mut projection_chain = Cow::Borrowed(projection_chain);
1216+
1217+
for i in 0..projection_chain.len() {
1218+
if let Some(segment) = projection_chain.get(i) {
1219+
if let Some(segment) = self.process_projection(segment, location) {
1220+
// This converts the borrowed projection chain into `Cow::Owned(_)` and returns a
1221+
// clone of the projection chain so we can mutate and reintern later.
1222+
let vec = projection_chain.to_mut();
1223+
vec[i] = self.tcx().mk_place_elems(&segment);
1224+
}
1225+
}
1226+
}
1227+
1228+
match projection_chain {
1229+
Cow::Borrowed(_) => None,
1230+
Cow::Owned(vec) => Some(vec),
1231+
}
1232+
}
11851233
};
11861234

11871235
() => {
@@ -1194,13 +1242,15 @@ macro_rules! visit_place_fns {
11941242
self.super_projection(place_ref, context, location);
11951243
}
11961244

1197-
fn visit_projection_elem(
1245+
fn visit_projection_elem<P>(
11981246
&mut self,
1199-
place_ref: PlaceRef<'tcx>,
1247+
place_ref: P,
12001248
elem: PlaceElem<'tcx>,
12011249
context: PlaceContext,
12021250
location: Location,
1203-
) {
1251+
) where
1252+
P: ProjectionBase<'tcx>,
1253+
{
12041254
self.super_projection_elem(place_ref, elem, context, location);
12051255
}
12061256

@@ -1235,13 +1285,15 @@ macro_rules! visit_place_fns {
12351285
}
12361286
}
12371287

1238-
fn super_projection_elem(
1288+
fn super_projection_elem<P>(
12391289
&mut self,
1240-
_place_ref: PlaceRef<'tcx>,
1290+
_place_ref: P,
12411291
elem: PlaceElem<'tcx>,
12421292
context: PlaceContext,
12431293
location: Location,
1244-
) {
1294+
) where
1295+
P: ProjectionBase<'tcx>,
1296+
{
12451297
match elem {
12461298
ProjectionElem::OpaqueCast(ty)
12471299
| ProjectionElem::Subtype(ty)
@@ -1267,6 +1319,28 @@ macro_rules! visit_place_fns {
12671319
| ProjectionElem::Downcast(_, _) => {}
12681320
}
12691321
}
1322+
1323+
fn super_compound_place(
1324+
&mut self,
1325+
place: &CompoundPlace<'tcx>,
1326+
mut context: PlaceContext,
1327+
location: Location,
1328+
) {
1329+
if !place.projection_chain.is_empty() && context.is_use() {
1330+
// ^ Only change the context if it is a real use, not a "use" in debuginfo.
1331+
context = if context.is_mutating_use() {
1332+
PlaceContext::MutatingUse(MutatingUseContext::Projection)
1333+
} else {
1334+
PlaceContext::NonMutatingUse(NonMutatingUseContext::Projection)
1335+
};
1336+
}
1337+
1338+
self.visit_local(place.local, context, location);
1339+
1340+
for (base, elem) in place.iter_projections().rev() {
1341+
self.visit_projection_elem(base, elem, context, location);
1342+
}
1343+
}
12701344
};
12711345
}
12721346

@@ -1492,3 +1566,28 @@ where
14921566
self.visit_projection(place.as_ref(), ctxt, location);
14931567
}
14941568
}
1569+
1570+
/// Base of a projection in [`Visitor::visit_projection_elem`].
1571+
pub trait ProjectionBase<'tcx>: Debug + Copy {
1572+
fn ty<D: ?Sized>(&self, local_decls: &D, tcx: TyCtxt<'tcx>) -> PlaceTy<'tcx>
1573+
where
1574+
D: HasLocalDecls<'tcx>;
1575+
}
1576+
1577+
impl<'tcx> ProjectionBase<'tcx> for PlaceRef<'tcx> {
1578+
fn ty<D: ?Sized>(&self, local_decls: &D, tcx: TyCtxt<'tcx>) -> PlaceTy<'tcx>
1579+
where
1580+
D: HasLocalDecls<'tcx>,
1581+
{
1582+
self.ty(local_decls, tcx)
1583+
}
1584+
}
1585+
1586+
impl<'tcx> ProjectionBase<'tcx> for CompoundPlaceRef<'tcx> {
1587+
fn ty<D: ?Sized>(&self, local_decls: &D, tcx: TyCtxt<'tcx>) -> PlaceTy<'tcx>
1588+
where
1589+
D: HasLocalDecls<'tcx>,
1590+
{
1591+
self.ty(local_decls, tcx)
1592+
}
1593+
}

compiler/rustc_mir_transform/src/dataflow_const_prop.rs

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ use rustc_data_structures::fx::FxHashMap;
1414
use rustc_hir::def::DefKind;
1515
use rustc_middle::bug;
1616
use rustc_middle::mir::interpret::{InterpResult, Scalar};
17-
use rustc_middle::mir::visit::{MutVisitor, PlaceContext, Visitor};
17+
use rustc_middle::mir::visit::{MutVisitor, PlaceContext, ProjectionBase, Visitor};
1818
use rustc_middle::mir::*;
1919
use rustc_middle::ty::{self, Ty, TyCtxt};
2020
use rustc_mir_dataflow::fmt::DebugWithContext;
@@ -1069,13 +1069,15 @@ struct OperandCollector<'a, 'b, 'tcx> {
10691069
}
10701070

10711071
impl<'tcx> Visitor<'tcx> for OperandCollector<'_, '_, 'tcx> {
1072-
fn visit_projection_elem(
1072+
fn visit_projection_elem<P>(
10731073
&mut self,
1074-
_: PlaceRef<'tcx>,
1074+
_: P,
10751075
elem: PlaceElem<'tcx>,
10761076
_: PlaceContext,
10771077
location: Location,
1078-
) {
1078+
) where
1079+
P: ProjectionBase<'tcx>,
1080+
{
10791081
if let PlaceElem::Index(local) = elem
10801082
&& let Some(value) =
10811083
self.visitor.try_make_constant(self.ecx, local.into(), self.state, self.map)

compiler/rustc_mir_transform/src/validate.rs

Lines changed: 40 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ use rustc_index::bit_set::DenseBitSet;
99
use rustc_infer::infer::TyCtxtInferExt;
1010
use rustc_infer::traits::{Obligation, ObligationCause};
1111
use rustc_middle::mir::coverage::CoverageKind;
12-
use rustc_middle::mir::visit::{NonUseContext, PlaceContext, Visitor};
12+
use rustc_middle::mir::visit::{NonUseContext, PlaceContext, ProjectionBase, Visitor};
1313
use rustc_middle::mir::*;
1414
use rustc_middle::ty::adjustment::PointerCoercion;
1515
use rustc_middle::ty::print::with_no_trimmed_paths;
@@ -646,13 +646,15 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> {
646646
self.super_operand(operand, location);
647647
}
648648

649-
fn visit_projection_elem(
649+
fn visit_projection_elem<P>(
650650
&mut self,
651-
place_ref: PlaceRef<'tcx>,
651+
place_ref: P,
652652
elem: PlaceElem<'tcx>,
653653
context: PlaceContext,
654654
location: Location,
655-
) {
655+
) where
656+
P: ProjectionBase<'tcx>,
657+
{
656658
match elem {
657659
ProjectionElem::OpaqueCast(ty)
658660
if self.body.phase >= MirPhase::Runtime(RuntimePhase::Initial) =>
@@ -925,6 +927,40 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> {
925927
self.super_place(place, cntxt, location);
926928
}
927929

930+
fn visit_compound_place(
931+
&mut self,
932+
place: &CompoundPlace<'tcx>,
933+
cntxt: PlaceContext,
934+
location: Location,
935+
) {
936+
// Set off any `bug!`s in the type computation code
937+
let _ = place.ty(&self.body.local_decls, self.tcx);
938+
939+
for (i, projection) in place.projection_chain.iter().enumerate() {
940+
if projection.is_empty() {
941+
self.fail(location, format!("compound place {place:?} has empty segment {i}"));
942+
}
943+
944+
if i > 0 && projection.first() != Some(&ProjectionElem::Deref) {
945+
self.fail(
946+
location,
947+
format!(
948+
"compound place {place:?} has later segment without deref (segment {i})"
949+
),
950+
);
951+
}
952+
953+
if projection[1..].contains(&ProjectionElem::Deref) {
954+
self.fail(
955+
location,
956+
format!("compound place {place:?} has deref as a later projection in segment {i} (it is only permitted as the first projection)"),
957+
);
958+
}
959+
}
960+
961+
self.super_compound_place(place, cntxt, location);
962+
}
963+
928964
fn visit_rvalue(&mut self, rvalue: &Rvalue<'tcx>, location: Location) {
929965
macro_rules! check_kinds {
930966
($t:expr, $text:literal, $typat:pat) => {

0 commit comments

Comments
 (0)