@@ -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