Skip to content

Commit 0677d97

Browse files
committed
Auto merge of #80865 - oliviacrain:proj_based, r=RalfJung
Use PlaceRef projection abstractions more consistently in rustc_mir PlaceRef contains abstractions for dealing with the `projections` array. This PR uses these abstractions more consistently within the `rustc_mir` crate. See associated issue: #80647. r? `@RalfJung`
2 parents 93e0aed + 65b5e43 commit 0677d97

File tree

10 files changed

+103
-124
lines changed

10 files changed

+103
-124
lines changed

compiler/rustc_mir/src/borrow_check/diagnostics/conflict_errors.rs

+6-10
Original file line numberDiff line numberDiff line change
@@ -1616,28 +1616,25 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
16161616

16171617
fn classify_drop_access_kind(&self, place: PlaceRef<'tcx>) -> StorageDeadOrDrop<'tcx> {
16181618
let tcx = self.infcx.tcx;
1619-
match place.projection {
1620-
[] => StorageDeadOrDrop::LocalStorageDead,
1621-
[proj_base @ .., elem] => {
1619+
match place.last_projection() {
1620+
None => StorageDeadOrDrop::LocalStorageDead,
1621+
Some((place_base, elem)) => {
16221622
// FIXME(spastorino) make this iterate
1623-
let base_access = self.classify_drop_access_kind(PlaceRef {
1624-
local: place.local,
1625-
projection: proj_base,
1626-
});
1623+
let base_access = self.classify_drop_access_kind(place_base);
16271624
match elem {
16281625
ProjectionElem::Deref => match base_access {
16291626
StorageDeadOrDrop::LocalStorageDead
16301627
| StorageDeadOrDrop::BoxedStorageDead => {
16311628
assert!(
1632-
Place::ty_from(place.local, proj_base, self.body, tcx).ty.is_box(),
1629+
place_base.ty(self.body, tcx).ty.is_box(),
16331630
"Drop of value behind a reference or raw pointer"
16341631
);
16351632
StorageDeadOrDrop::BoxedStorageDead
16361633
}
16371634
StorageDeadOrDrop::Destructor(_) => base_access,
16381635
},
16391636
ProjectionElem::Field(..) | ProjectionElem::Downcast(..) => {
1640-
let base_ty = Place::ty_from(place.local, proj_base, self.body, tcx).ty;
1637+
let base_ty = place_base.ty(self.body, tcx).ty;
16411638
match base_ty.kind() {
16421639
ty::Adt(def, _) if def.has_dtor(tcx) => {
16431640
// Report the outermost adt with a destructor
@@ -1652,7 +1649,6 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
16521649
_ => base_access,
16531650
}
16541651
}
1655-
16561652
ProjectionElem::ConstantIndex { .. }
16571653
| ProjectionElem::Subslice { .. }
16581654
| ProjectionElem::Index(_) => base_access,

compiler/rustc_mir/src/borrow_check/diagnostics/mod.rs

+2-3
Original file line numberDiff line numberDiff line change
@@ -338,8 +338,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
338338
self.describe_field(PlaceRef { local, projection: proj_base }, field)
339339
}
340340
ProjectionElem::Downcast(_, variant_index) => {
341-
let base_ty =
342-
Place::ty_from(place.local, place.projection, self.body, self.infcx.tcx).ty;
341+
let base_ty = place.ty(self.body, self.infcx.tcx).ty;
343342
self.describe_field_from_ty(&base_ty, field, Some(*variant_index))
344343
}
345344
ProjectionElem::Field(_, field_type) => {
@@ -473,7 +472,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
473472

474473
// If we didn't find an overloaded deref or index, then assume it's a
475474
// built in deref and check the type of the base.
476-
let base_ty = Place::ty_from(deref_base.local, deref_base.projection, self.body, tcx).ty;
475+
let base_ty = deref_base.ty(self.body, tcx).ty;
477476
if base_ty.is_unsafe_ptr() {
478477
BorrowedContentSource::DerefRawPointer
479478
} else if base_ty.is_mutable_ptr() {

compiler/rustc_mir/src/borrow_check/path_utils.rs

+7-9
Original file line numberDiff line numberDiff line change
@@ -147,27 +147,25 @@ pub(crate) fn is_upvar_field_projection(
147147
place_ref: PlaceRef<'tcx>,
148148
body: &Body<'tcx>,
149149
) -> Option<Field> {
150-
let mut place_projection = place_ref.projection;
150+
let mut place_ref = place_ref;
151151
let mut by_ref = false;
152152

153-
if let [proj_base @ .., ProjectionElem::Deref] = place_projection {
154-
place_projection = proj_base;
153+
if let Some((place_base, ProjectionElem::Deref)) = place_ref.last_projection() {
154+
place_ref = place_base;
155155
by_ref = true;
156156
}
157157

158-
match place_projection {
159-
[base @ .., ProjectionElem::Field(field, _ty)] => {
160-
let base_ty = Place::ty_from(place_ref.local, base, body, tcx).ty;
161-
158+
match place_ref.last_projection() {
159+
Some((place_base, ProjectionElem::Field(field, _ty))) => {
160+
let base_ty = place_base.ty(body, tcx).ty;
162161
if (base_ty.is_closure() || base_ty.is_generator())
163162
&& (!by_ref || upvars[field.index()].by_ref)
164163
{
165-
Some(*field)
164+
Some(field)
166165
} else {
167166
None
168167
}
169168
}
170-
171169
_ => None,
172170
}
173171
}

compiler/rustc_mir/src/dataflow/move_paths/builder.rs

+3-7
Original file line numberDiff line numberDiff line change
@@ -518,14 +518,10 @@ impl<'b, 'a, 'tcx> Gatherer<'b, 'a, 'tcx> {
518518

519519
// Check if we are assigning into a field of a union, if so, lookup the place
520520
// of the union so it is marked as initialized again.
521-
if let [proj_base @ .., ProjectionElem::Field(_, _)] = place.projection {
522-
if let ty::Adt(def, _) =
523-
Place::ty_from(place.local, proj_base, self.builder.body, self.builder.tcx)
524-
.ty
525-
.kind()
526-
{
521+
if let Some((place_base, ProjectionElem::Field(_, _))) = place.last_projection() {
522+
if let ty::Adt(def, _) = place_base.ty(self.builder.body, self.builder.tcx).ty.kind() {
527523
if def.is_union() {
528-
place = PlaceRef { local: place.local, projection: proj_base }
524+
place = place_base;
529525
}
530526
}
531527
}

compiler/rustc_mir/src/transform/check_consts/qualifs.rs

+10-14
Original file line numberDiff line numberDiff line change
@@ -174,14 +174,10 @@ where
174174

175175
Rvalue::Ref(_, _, place) | Rvalue::AddressOf(_, place) => {
176176
// Special-case reborrows to be more like a copy of the reference.
177-
if let &[ref proj_base @ .., ProjectionElem::Deref] = place.projection.as_ref() {
178-
let base_ty = Place::ty_from(place.local, proj_base, cx.body, cx.tcx).ty;
177+
if let Some((place_base, ProjectionElem::Deref)) = place.as_ref().last_projection() {
178+
let base_ty = place_base.ty(cx.body, cx.tcx).ty;
179179
if let ty::Ref(..) = base_ty.kind() {
180-
return in_place::<Q, _>(
181-
cx,
182-
in_local,
183-
PlaceRef { local: place.local, projection: proj_base },
184-
);
180+
return in_place::<Q, _>(cx, in_local, place_base);
185181
}
186182
}
187183

@@ -209,9 +205,9 @@ where
209205
Q: Qualif,
210206
F: FnMut(Local) -> bool,
211207
{
212-
let mut projection = place.projection;
213-
while let &[ref proj_base @ .., proj_elem] = projection {
214-
match proj_elem {
208+
let mut place = place;
209+
while let Some((place_base, elem)) = place.last_projection() {
210+
match elem {
215211
ProjectionElem::Index(index) if in_local(index) => return true,
216212

217213
ProjectionElem::Deref
@@ -222,16 +218,16 @@ where
222218
| ProjectionElem::Index(_) => {}
223219
}
224220

225-
let base_ty = Place::ty_from(place.local, proj_base, cx.body, cx.tcx);
226-
let proj_ty = base_ty.projection_ty(cx.tcx, proj_elem).ty;
221+
let base_ty = place_base.ty(cx.body, cx.tcx);
222+
let proj_ty = base_ty.projection_ty(cx.tcx, elem).ty;
227223
if !Q::in_any_value_of_ty(cx, proj_ty) {
228224
return false;
229225
}
230226

231-
projection = proj_base;
227+
place = place_base;
232228
}
233229

234-
assert!(projection.is_empty());
230+
assert!(place.projection.is_empty());
235231
in_local(place.local)
236232
}
237233

compiler/rustc_mir/src/transform/check_consts/validation.rs

+19-20
Original file line numberDiff line numberDiff line change
@@ -1007,27 +1007,26 @@ fn place_as_reborrow(
10071007
body: &Body<'tcx>,
10081008
place: Place<'tcx>,
10091009
) -> Option<&'a [PlaceElem<'tcx>]> {
1010-
place.projection.split_last().and_then(|(outermost, inner)| {
1011-
if outermost != &ProjectionElem::Deref {
1012-
return None;
1013-
}
1014-
1015-
// A borrow of a `static` also looks like `&(*_1)` in the MIR, but `_1` is a `const`
1016-
// that points to the allocation for the static. Don't treat these as reborrows.
1017-
if body.local_decls[place.local].is_ref_to_static() {
1018-
return None;
1019-
}
1020-
1021-
// Ensure the type being derefed is a reference and not a raw pointer.
1022-
//
1023-
// This is sufficient to prevent an access to a `static mut` from being marked as a
1024-
// reborrow, even if the check above were to disappear.
1025-
let inner_ty = Place::ty_from(place.local, inner, body, tcx).ty;
1026-
match inner_ty.kind() {
1027-
ty::Ref(..) => Some(inner),
1028-
_ => None,
1010+
match place.as_ref().last_projection() {
1011+
Some((place_base, ProjectionElem::Deref)) => {
1012+
// A borrow of a `static` also looks like `&(*_1)` in the MIR, but `_1` is a `const`
1013+
// that points to the allocation for the static. Don't treat these as reborrows.
1014+
if body.local_decls[place_base.local].is_ref_to_static() {
1015+
None
1016+
} else {
1017+
// Ensure the type being derefed is a reference and not a raw pointer.
1018+
//
1019+
// This is sufficient to prevent an access to a `static mut` from being marked as a
1020+
// reborrow, even if the check above were to disappear.
1021+
let inner_ty = place_base.ty(body, tcx).ty;
1022+
match inner_ty.kind() {
1023+
ty::Ref(..) => Some(place_base.projection),
1024+
_ => None,
1025+
}
1026+
}
10291027
}
1030-
})
1028+
_ => None,
1029+
}
10311030
}
10321031

10331032
fn is_int_bool_or_char(ty: Ty<'_>) -> bool {

compiler/rustc_mir/src/transform/check_unsafety.rs

+2-6
Original file line numberDiff line numberDiff line change
@@ -399,17 +399,13 @@ impl<'a, 'tcx> UnsafetyChecker<'a, 'tcx> {
399399
place: Place<'tcx>,
400400
is_mut_use: bool,
401401
) {
402-
let mut cursor = place.projection.as_ref();
403-
while let &[ref proj_base @ .., elem] = cursor {
404-
cursor = proj_base;
405-
402+
for (place_base, elem) in place.iter_projections().rev() {
406403
match elem {
407404
// Modifications behind a dereference don't affect the value of
408405
// the pointer.
409406
ProjectionElem::Deref => return,
410407
ProjectionElem::Field(..) => {
411-
let ty =
412-
Place::ty_from(place.local, proj_base, &self.body.local_decls, self.tcx).ty;
408+
let ty = place_base.ty(&self.body.local_decls, self.tcx).ty;
413409
if let ty::Adt(def, _) = ty.kind() {
414410
if self.tcx.layout_scalar_valid_range(def.did)
415411
!= (Bound::Unbounded, Bound::Unbounded)

compiler/rustc_mir/src/transform/instcombine.rs

+2-4
Original file line numberDiff line numberDiff line change
@@ -277,11 +277,9 @@ impl OptimizationFinder<'b, 'tcx> {
277277
impl Visitor<'tcx> for OptimizationFinder<'b, 'tcx> {
278278
fn visit_rvalue(&mut self, rvalue: &Rvalue<'tcx>, location: Location) {
279279
if let Rvalue::Ref(_, _, place) = rvalue {
280-
if let PlaceRef { local, projection: &[ref proj_base @ .., ProjectionElem::Deref] } =
281-
place.as_ref()
282-
{
280+
if let Some((place_base, ProjectionElem::Deref)) = place.as_ref().last_projection() {
283281
// The dereferenced place must have type `&_`.
284-
let ty = Place::ty_from(local, proj_base, self.body, self.tcx).ty;
282+
let ty = place_base.ty(self.body, self.tcx).ty;
285283
if let ty::Ref(_, _, Mutability::Not) = ty.kind() {
286284
self.optimizations.and_stars.insert(location);
287285
}

compiler/rustc_mir/src/transform/promote_consts.rs

+50-46
Original file line numberDiff line numberDiff line change
@@ -445,43 +445,50 @@ impl<'tcx> Validator<'_, 'tcx> {
445445
}
446446

447447
fn validate_place(&self, place: PlaceRef<'tcx>) -> Result<(), Unpromotable> {
448-
match place {
449-
PlaceRef { local, projection: [] } => self.validate_local(local),
450-
PlaceRef { local, projection: [proj_base @ .., elem] } => {
448+
match place.last_projection() {
449+
None => self.validate_local(place.local),
450+
Some((place_base, elem)) => {
451451
// Validate topmost projection, then recurse.
452-
match *elem {
452+
match elem {
453453
ProjectionElem::Deref => {
454454
let mut promotable = false;
455-
// This is a special treatment for cases like *&STATIC where STATIC is a
456-
// global static variable.
457-
// This pattern is generated only when global static variables are directly
458-
// accessed and is qualified for promotion safely.
459-
if let TempState::Defined { location, .. } = self.temps[local] {
460-
let def_stmt =
461-
self.body[location.block].statements.get(location.statement_index);
462-
if let Some(Statement {
463-
kind:
464-
StatementKind::Assign(box (_, Rvalue::Use(Operand::Constant(c)))),
465-
..
466-
}) = def_stmt
455+
// The `is_empty` predicate is introduced to exclude the case
456+
// where the projection operations are [ .field, * ].
457+
// The reason is because promotion will be illegal if field
458+
// accesses precede the dereferencing.
459+
// Discussion can be found at
460+
// https://github.com/rust-lang/rust/pull/74945#discussion_r463063247
461+
// There may be opportunity for generalization, but this needs to be
462+
// accounted for.
463+
if place_base.projection.is_empty() {
464+
// This is a special treatment for cases like *&STATIC where STATIC is a
465+
// global static variable.
466+
// This pattern is generated only when global static variables are directly
467+
// accessed and is qualified for promotion safely.
468+
if let TempState::Defined { location, .. } =
469+
self.temps[place_base.local]
467470
{
468-
if let Some(did) = c.check_static_ptr(self.tcx) {
469-
// Evaluating a promoted may not read statics except if it got
470-
// promoted from a static (this is a CTFE check). So we
471-
// can only promote static accesses inside statics.
472-
if let Some(hir::ConstContext::Static(..)) = self.const_kind {
473-
// The `is_empty` predicate is introduced to exclude the case
474-
// where the projection operations are [ .field, * ].
475-
// The reason is because promotion will be illegal if field
476-
// accesses precede the dereferencing.
477-
// Discussion can be found at
478-
// https://github.com/rust-lang/rust/pull/74945#discussion_r463063247
479-
// There may be opportunity for generalization, but this needs to be
480-
// accounted for.
481-
if proj_base.is_empty()
482-
&& !self.tcx.is_thread_local_static(did)
471+
let def_stmt = self.body[location.block]
472+
.statements
473+
.get(location.statement_index);
474+
if let Some(Statement {
475+
kind:
476+
StatementKind::Assign(box (
477+
_,
478+
Rvalue::Use(Operand::Constant(c)),
479+
)),
480+
..
481+
}) = def_stmt
482+
{
483+
if let Some(did) = c.check_static_ptr(self.tcx) {
484+
// Evaluating a promoted may not read statics except if it got
485+
// promoted from a static (this is a CTFE check). So we
486+
// can only promote static accesses inside statics.
487+
if let Some(hir::ConstContext::Static(..)) = self.const_kind
483488
{
484-
promotable = true;
489+
if !self.tcx.is_thread_local_static(did) {
490+
promotable = true;
491+
}
485492
}
486493
}
487494
}
@@ -502,8 +509,7 @@ impl<'tcx> Validator<'_, 'tcx> {
502509
}
503510

504511
ProjectionElem::Field(..) => {
505-
let base_ty =
506-
Place::ty_from(place.local, proj_base, self.body, self.tcx).ty;
512+
let base_ty = place_base.ty(self.body, self.tcx).ty;
507513
if let Some(def) = base_ty.ty_adt_def() {
508514
// No promotion of union field accesses.
509515
if def.is_union() {
@@ -513,7 +519,7 @@ impl<'tcx> Validator<'_, 'tcx> {
513519
}
514520
}
515521

516-
self.validate_place(PlaceRef { local: place.local, projection: proj_base })
522+
self.validate_place(place_base)
517523
}
518524
}
519525
}
@@ -660,13 +666,11 @@ impl<'tcx> Validator<'_, 'tcx> {
660666
Rvalue::AddressOf(_, place) => {
661667
// We accept `&raw *`, i.e., raw reborrows -- creating a raw pointer is
662668
// no problem, only using it is.
663-
if let [proj_base @ .., ProjectionElem::Deref] = place.projection.as_ref() {
664-
let base_ty = Place::ty_from(place.local, proj_base, self.body, self.tcx).ty;
669+
if let Some((place_base, ProjectionElem::Deref)) = place.as_ref().last_projection()
670+
{
671+
let base_ty = place_base.ty(self.body, self.tcx).ty;
665672
if let ty::Ref(..) = base_ty.kind() {
666-
return self.validate_place(PlaceRef {
667-
local: place.local,
668-
projection: proj_base,
669-
});
673+
return self.validate_place(place_base);
670674
}
671675
}
672676
return Err(Unpromotable);
@@ -675,12 +679,12 @@ impl<'tcx> Validator<'_, 'tcx> {
675679
Rvalue::Ref(_, kind, place) => {
676680
// Special-case reborrows to be more like a copy of the reference.
677681
let mut place_simplified = place.as_ref();
678-
if let [proj_base @ .., ProjectionElem::Deref] = &place_simplified.projection {
679-
let base_ty =
680-
Place::ty_from(place_simplified.local, proj_base, self.body, self.tcx).ty;
682+
if let Some((place_base, ProjectionElem::Deref)) =
683+
place_simplified.last_projection()
684+
{
685+
let base_ty = place_base.ty(self.body, self.tcx).ty;
681686
if let ty::Ref(..) = base_ty.kind() {
682-
place_simplified =
683-
PlaceRef { local: place_simplified.local, projection: proj_base };
687+
place_simplified = place_base;
684688
}
685689
}
686690

0 commit comments

Comments
 (0)