@@ -309,49 +309,26 @@ impl<'tcx> Validator<'_, 'tcx> {
309
309
let statement = & self . body [ loc. block ] . statements [ loc. statement_index ] ;
310
310
match & statement. kind {
311
311
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
-
322
312
// We can only promote interior borrows of promotable temps (non-temps
323
313
// don't get promoted anyway).
324
314
self . validate_local ( place. local ) ?;
325
315
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.
326
322
if place. projection . contains ( & ProjectionElem :: Deref ) {
327
323
return Err ( Unpromotable ) ;
328
324
}
329
- if self . qualif_local :: < qualifs:: NeedsDrop > ( place. local ) {
330
- return Err ( Unpromotable ) ;
331
- }
332
325
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 ) {
337
329
return Err ( Unpromotable ) ;
338
330
}
339
331
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
- }
355
332
356
333
Ok ( ( ) )
357
334
}
@@ -572,6 +549,39 @@ impl<'tcx> Validator<'_, 'tcx> {
572
549
}
573
550
}
574
551
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
+
575
585
fn validate_rvalue ( & self , rvalue : & Rvalue < ' tcx > ) -> Result < ( ) , Unpromotable > {
576
586
match * rvalue {
577
587
Rvalue :: Cast ( CastKind :: Misc , ref operand, cast_ty) => {
@@ -640,37 +650,20 @@ impl<'tcx> Validator<'_, 'tcx> {
640
650
}
641
651
642
652
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
-
659
653
// 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 ;
663
657
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 } ;
665
659
}
666
660
}
667
661
668
- self . validate_place ( place ) ?;
662
+ self . validate_place ( place_simplified ) ?;
669
663
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) ?;
674
667
675
668
Ok ( ( ) )
676
669
}
0 commit comments