Skip to content

Commit 122e91c

Browse files
committed
promotion: factor some common code into validate_ref
1 parent 257becb commit 122e91c

File tree

1 file changed

+50
-57
lines changed

1 file changed

+50
-57
lines changed

compiler/rustc_mir/src/transform/promote_consts.rs

Lines changed: 50 additions & 57 deletions
Original file line numberDiff line numberDiff line change
@@ -309,49 +309,26 @@ impl<'tcx> Validator<'_, 'tcx> {
309309
let statement = &self.body[loc.block].statements[loc.statement_index];
310310
match &statement.kind {
311311
StatementKind::Assign(box (_, Rvalue::Ref(_, kind, place))) => {
312-
match kind {
313-
BorrowKind::Shared | BorrowKind::Mut { .. } => {}
314-
315-
// FIXME(eddyb) these aren't promoted here but *could*
316-
// be promoted as part of a larger value because
317-
// `validate_rvalue` doesn't check them, need to
318-
// figure out what is the intended behavior.
319-
BorrowKind::Shallow | BorrowKind::Unique => return Err(Unpromotable),
320-
}
321-
322312
// We can only promote interior borrows of promotable temps (non-temps
323313
// don't get promoted anyway).
324314
self.validate_local(place.local)?;
325315

316+
// The reference operation itself must be promotable.
317+
// (Needs to come after `validate_local` to avoid ICEs.)
318+
self.validate_ref(*kind, place)?;
319+
320+
// We do not check all the projections (they do not get promoted anyway),
321+
// but we do stay away from promoting anything involving a dereference.
326322
if place.projection.contains(&ProjectionElem::Deref) {
327323
return Err(Unpromotable);
328324
}
329-
if self.qualif_local::<qualifs::NeedsDrop>(place.local) {
330-
return Err(Unpromotable);
331-
}
332325

333-
// FIXME(eddyb) this duplicates part of `validate_rvalue`.
334-
let has_mut_interior =
335-
self.qualif_local::<qualifs::HasMutInterior>(place.local);
336-
if has_mut_interior {
326+
// We cannot promote things that need dropping, since the promoted value
327+
// would not get dropped.
328+
if self.qualif_local::<qualifs::NeedsDrop>(place.local) {
337329
return Err(Unpromotable);
338330
}
339331

340-
if let BorrowKind::Mut { .. } = kind {
341-
let ty = place.ty(self.body, self.tcx).ty;
342-
343-
// In theory, any zero-sized value could be borrowed
344-
// mutably without consequences. However, only &mut []
345-
// is allowed right now.
346-
if let ty::Array(_, len) = ty.kind() {
347-
match len.try_eval_usize(self.tcx, self.param_env) {
348-
Some(0) => {}
349-
_ => return Err(Unpromotable),
350-
}
351-
} else {
352-
return Err(Unpromotable);
353-
}
354-
}
355332

356333
Ok(())
357334
}
@@ -572,6 +549,39 @@ impl<'tcx> Validator<'_, 'tcx> {
572549
}
573550
}
574551

552+
fn validate_ref(&self, kind: BorrowKind, place: &Place<'tcx>) -> Result<(), Unpromotable> {
553+
match kind {
554+
// Reject these borrow types just to be safe.
555+
// FIXME(RalfJung): could we allow them? Should we? No point in it until we have a usecase.
556+
BorrowKind::Shallow | BorrowKind::Unique => return Err(Unpromotable),
557+
558+
BorrowKind::Shared => {
559+
let has_mut_interior = self.qualif_local::<qualifs::HasMutInterior>(place.local);
560+
if has_mut_interior {
561+
return Err(Unpromotable);
562+
}
563+
}
564+
565+
BorrowKind::Mut { .. } => {
566+
let ty = place.ty(self.body, self.tcx).ty;
567+
568+
// In theory, any zero-sized value could be borrowed
569+
// mutably without consequences. However, only &mut []
570+
// is allowed right now.
571+
if let ty::Array(_, len) = ty.kind() {
572+
match len.try_eval_usize(self.tcx, self.param_env) {
573+
Some(0) => {}
574+
_ => return Err(Unpromotable),
575+
}
576+
} else {
577+
return Err(Unpromotable);
578+
}
579+
}
580+
}
581+
582+
Ok(())
583+
}
584+
575585
fn validate_rvalue(&self, rvalue: &Rvalue<'tcx>) -> Result<(), Unpromotable> {
576586
match *rvalue {
577587
Rvalue::Cast(CastKind::Misc, ref operand, cast_ty) => {
@@ -640,37 +650,20 @@ impl<'tcx> Validator<'_, 'tcx> {
640650
}
641651

642652
Rvalue::Ref(_, kind, place) => {
643-
if let BorrowKind::Mut { .. } = kind {
644-
let ty = place.ty(self.body, self.tcx).ty;
645-
646-
// In theory, any zero-sized value could be borrowed
647-
// mutably without consequences. However, only &mut []
648-
// is allowed right now.
649-
if let ty::Array(_, len) = ty.kind() {
650-
match len.try_eval_usize(self.tcx, self.param_env) {
651-
Some(0) => {}
652-
_ => return Err(Unpromotable),
653-
}
654-
} else {
655-
return Err(Unpromotable);
656-
}
657-
}
658-
659653
// Special-case reborrows to be more like a copy of the reference.
660-
let mut place = place.as_ref();
661-
if let [proj_base @ .., ProjectionElem::Deref] = &place.projection {
662-
let base_ty = Place::ty_from(place.local, proj_base, self.body, self.tcx).ty;
654+
let mut place_simplified = place.as_ref();
655+
if let [proj_base @ .., ProjectionElem::Deref] = &place_simplified.projection {
656+
let base_ty = Place::ty_from(place_simplified.local, proj_base, self.body, self.tcx).ty;
663657
if let ty::Ref(..) = base_ty.kind() {
664-
place = PlaceRef { local: place.local, projection: proj_base };
658+
place_simplified = PlaceRef { local: place_simplified.local, projection: proj_base };
665659
}
666660
}
667661

668-
self.validate_place(place)?;
662+
self.validate_place(place_simplified)?;
669663

670-
let has_mut_interior = self.qualif_local::<qualifs::HasMutInterior>(place.local);
671-
if has_mut_interior {
672-
return Err(Unpromotable);
673-
}
664+
// Check that the reference is fine (using the original place!).
665+
// (Needs to come after `validate_local` to avoid ICEs.)
666+
self.validate_ref(*kind, place)?;
674667

675668
Ok(())
676669
}

0 commit comments

Comments
 (0)