@@ -90,7 +90,7 @@ pub enum TempState {
9090impl TempState {
9191 pub fn is_promotable ( & self ) -> bool {
9292 debug ! ( "is_promotable: self={:?}" , self ) ;
93- matches ! ( self , TempState :: Defined { .. } )
93+ matches ! ( self , TempState :: Defined { .. } )
9494 }
9595}
9696
@@ -309,50 +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- }
355-
356332 Ok ( ( ) )
357333 }
358334 _ => bug ! ( ) ,
@@ -572,58 +548,115 @@ impl<'tcx> Validator<'_, 'tcx> {
572548 }
573549 }
574550
575- fn validate_rvalue ( & self , rvalue : & Rvalue < ' tcx > ) -> Result < ( ) , Unpromotable > {
576- match * rvalue {
577- Rvalue :: Cast ( CastKind :: Misc , ref operand, cast_ty) => {
578- let operand_ty = operand. ty ( self . body , self . tcx ) ;
579- let cast_in = CastTy :: from_ty ( operand_ty) . expect ( "bad input type for cast" ) ;
580- let cast_out = CastTy :: from_ty ( cast_ty) . expect ( "bad output type for cast" ) ;
581- if let ( CastTy :: Ptr ( _) | CastTy :: FnPtr , CastTy :: Int ( _) ) = ( cast_in, cast_out) {
582- // ptr-to-int casts are not possible in consts and thus not promotable
551+ fn validate_ref ( & self , kind : BorrowKind , place : & Place < ' tcx > ) -> Result < ( ) , Unpromotable > {
552+ match kind {
553+ // Reject these borrow types just to be safe.
554+ // FIXME(RalfJung): could we allow them? Should we? No point in it until we have a usecase.
555+ BorrowKind :: Shallow | BorrowKind :: Unique => return Err ( Unpromotable ) ,
556+
557+ BorrowKind :: Shared => {
558+ let has_mut_interior = self . qualif_local :: < qualifs:: HasMutInterior > ( place. local ) ;
559+ if has_mut_interior {
583560 return Err ( Unpromotable ) ;
584561 }
585562 }
586563
587- Rvalue :: BinaryOp ( op, ref lhs, _) => {
588- if let ty:: RawPtr ( _) | ty:: FnPtr ( ..) = lhs. ty ( self . body , self . tcx ) . kind ( ) {
589- assert ! (
590- op == BinOp :: Eq
591- || op == BinOp :: Ne
592- || op == BinOp :: Le
593- || op == BinOp :: Lt
594- || op == BinOp :: Ge
595- || op == BinOp :: Gt
596- || op == BinOp :: Offset
597- ) ;
564+ BorrowKind :: Mut { .. } => {
565+ let ty = place. ty ( self . body , self . tcx ) . ty ;
598566
599- // raw pointer operations are not allowed inside consts and thus not promotable
567+ // In theory, any zero-sized value could be borrowed
568+ // mutably without consequences. However, only &mut []
569+ // is allowed right now.
570+ if let ty:: Array ( _, len) = ty. kind ( ) {
571+ match len. try_eval_usize ( self . tcx , self . param_env ) {
572+ Some ( 0 ) => { }
573+ _ => return Err ( Unpromotable ) ,
574+ }
575+ } else {
600576 return Err ( Unpromotable ) ;
601577 }
602578 }
603-
604- Rvalue :: NullaryOp ( NullOp :: Box , _) => return Err ( Unpromotable ) ,
605-
606- // FIXME(RalfJung): the rest is *implicitly considered promotable*... that seems dangerous.
607- _ => { }
608579 }
609580
581+ Ok ( ( ) )
582+ }
583+
584+ fn validate_rvalue ( & self , rvalue : & Rvalue < ' tcx > ) -> Result < ( ) , Unpromotable > {
610585 match rvalue {
611- Rvalue :: ThreadLocalRef ( _) => Err ( Unpromotable ) ,
586+ Rvalue :: Use ( operand)
587+ | Rvalue :: Repeat ( operand, _)
588+ | Rvalue :: UnaryOp ( UnOp :: Not | UnOp :: Neg , operand) => {
589+ self . validate_operand ( operand) ?;
590+ }
612591
613- Rvalue :: NullaryOp ( ..) => Ok ( ( ) ) ,
592+ Rvalue :: Discriminant ( place) | Rvalue :: Len ( place) => {
593+ self . validate_place ( place. as_ref ( ) ) ?
594+ }
614595
615- Rvalue :: Discriminant ( place ) | Rvalue :: Len ( place ) => self . validate_place ( place . as_ref ( ) ) ,
596+ Rvalue :: ThreadLocalRef ( _ ) => return Err ( Unpromotable ) ,
616597
617- Rvalue :: Use ( operand)
618- | Rvalue :: Repeat ( operand, _)
619- | Rvalue :: UnaryOp ( _, operand)
620- | Rvalue :: Cast ( _, operand, _) => self . validate_operand ( operand) ,
598+ Rvalue :: Cast ( kind, operand, cast_ty) => {
599+ if matches ! ( kind, CastKind :: Misc ) {
600+ let operand_ty = operand. ty ( self . body , self . tcx ) ;
601+ let cast_in = CastTy :: from_ty ( operand_ty) . expect ( "bad input type for cast" ) ;
602+ let cast_out = CastTy :: from_ty ( cast_ty) . expect ( "bad output type for cast" ) ;
603+ if let ( CastTy :: Ptr ( _) | CastTy :: FnPtr , CastTy :: Int ( _) ) = ( cast_in, cast_out) {
604+ // ptr-to-int casts are not possible in consts and thus not promotable
605+ return Err ( Unpromotable ) ;
606+ }
607+ // int-to-ptr casts are fine, they just use the integer value at pointer type.
608+ }
609+
610+ self . validate_operand ( operand) ?;
611+ }
612+
613+ Rvalue :: BinaryOp ( op, lhs, rhs) | Rvalue :: CheckedBinaryOp ( op, lhs, rhs) => {
614+ let op = * op;
615+ if let ty:: RawPtr ( _) | ty:: FnPtr ( ..) = lhs. ty ( self . body , self . tcx ) . kind ( ) {
616+ // raw pointer operations are not allowed inside consts and thus not promotable
617+ assert ! ( matches!(
618+ op,
619+ BinOp :: Eq
620+ | BinOp :: Ne
621+ | BinOp :: Le
622+ | BinOp :: Lt
623+ | BinOp :: Ge
624+ | BinOp :: Gt
625+ | BinOp :: Offset
626+ ) ) ;
627+ return Err ( Unpromotable ) ;
628+ }
629+
630+ match op {
631+ // FIXME: reject operations that can fail -- namely, division and modulo.
632+ BinOp :: Eq
633+ | BinOp :: Ne
634+ | BinOp :: Le
635+ | BinOp :: Lt
636+ | BinOp :: Ge
637+ | BinOp :: Gt
638+ | BinOp :: Offset
639+ | BinOp :: Add
640+ | BinOp :: Sub
641+ | BinOp :: Mul
642+ | BinOp :: Div
643+ | BinOp :: Rem
644+ | BinOp :: BitXor
645+ | BinOp :: BitAnd
646+ | BinOp :: BitOr
647+ | BinOp :: Shl
648+ | BinOp :: Shr => { }
649+ }
621650
622- Rvalue :: BinaryOp ( _, lhs, rhs) | Rvalue :: CheckedBinaryOp ( _, lhs, rhs) => {
623651 self . validate_operand ( lhs) ?;
624- self . validate_operand ( rhs)
652+ self . validate_operand ( rhs) ? ;
625653 }
626654
655+ Rvalue :: NullaryOp ( op, _) => match op {
656+ NullOp :: Box => return Err ( Unpromotable ) ,
657+ NullOp :: SizeOf => { }
658+ } ,
659+
627660 Rvalue :: AddressOf ( _, place) => {
628661 // We accept `&raw *`, i.e., raw reborrows -- creating a raw pointer is
629662 // no problem, only using it is.
@@ -636,53 +669,36 @@ impl<'tcx> Validator<'_, 'tcx> {
636669 } ) ;
637670 }
638671 }
639- Err ( Unpromotable )
672+ return Err ( Unpromotable ) ;
640673 }
641674
642675 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-
659676 // 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 ;
677+ 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 ;
663681 if let ty:: Ref ( ..) = base_ty. kind ( ) {
664- place = PlaceRef { local : place. local , projection : proj_base } ;
682+ place_simplified =
683+ PlaceRef { local : place_simplified. local , projection : proj_base } ;
665684 }
666685 }
667686
668- self . validate_place ( place) ?;
669-
670- let has_mut_interior = self . qualif_local :: < qualifs:: HasMutInterior > ( place. local ) ;
671- if has_mut_interior {
672- return Err ( Unpromotable ) ;
673- }
687+ self . validate_place ( place_simplified) ?;
674688
675- Ok ( ( ) )
689+ // Check that the reference is fine (using the original place!).
690+ // (Needs to come after `validate_place` to avoid ICEs.)
691+ self . validate_ref ( * kind, place) ?;
676692 }
677693
678- Rvalue :: Aggregate ( _, ref operands) => {
694+ Rvalue :: Aggregate ( _, operands) => {
679695 for o in operands {
680696 self . validate_operand ( o) ?;
681697 }
682-
683- Ok ( ( ) )
684698 }
685699 }
700+
701+ Ok ( ( ) )
686702 }
687703
688704 fn validate_call (
0 commit comments