@@ -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,26 +309,50 @@ 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+
312322 // We can only promote interior borrows of promotable temps (non-temps
313323 // don't get promoted anyway).
314324 self . validate_local ( place. local ) ?;
315325
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.
322326 if place. projection . contains ( & ProjectionElem :: Deref ) {
323327 return Err ( Unpromotable ) ;
324328 }
325-
326- // We cannot promote things that need dropping, since the promoted value
327- // would not get dropped.
328329 if self . qualif_local :: < qualifs:: NeedsDrop > ( place. local ) {
329330 return Err ( Unpromotable ) ;
330331 }
331332
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 {
337+ return Err ( Unpromotable ) ;
338+ }
339+
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+
332356 Ok ( ( ) )
333357 }
334358 _ => bug ! ( ) ,
@@ -548,115 +572,58 @@ impl<'tcx> Validator<'_, 'tcx> {
548572 }
549573 }
550574
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 {
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
560583 return Err ( Unpromotable ) ;
561584 }
562585 }
563586
564- BorrowKind :: Mut { .. } => {
565- let ty = place. ty ( self . body , self . tcx ) . ty ;
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+ ) ;
566598
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 {
599+ // raw pointer operations are not allowed inside consts and thus not promotable
576600 return Err ( Unpromotable ) ;
577601 }
578602 }
579- }
580-
581- Ok ( ( ) )
582- }
583-
584- fn validate_rvalue ( & self , rvalue : & Rvalue < ' tcx > ) -> Result < ( ) , Unpromotable > {
585- match rvalue {
586- Rvalue :: Use ( operand)
587- | Rvalue :: Repeat ( operand, _)
588- | Rvalue :: UnaryOp ( UnOp :: Not | UnOp :: Neg , operand) => {
589- self . validate_operand ( operand) ?;
590- }
591603
592- Rvalue :: Discriminant ( place) | Rvalue :: Len ( place) => {
593- self . validate_place ( place. as_ref ( ) ) ?
594- }
604+ Rvalue :: NullaryOp ( NullOp :: Box , _) => return Err ( Unpromotable ) ,
595605
596- Rvalue :: ThreadLocalRef ( _) => return Err ( Unpromotable ) ,
606+ // FIXME(RalfJung): the rest is *implicitly considered promotable*... that seems dangerous.
607+ _ => { }
608+ }
597609
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- }
610+ match rvalue {
611+ Rvalue :: ThreadLocalRef ( _) => Err ( Unpromotable ) ,
609612
610- self . validate_operand ( operand) ?;
611- }
613+ Rvalue :: NullaryOp ( ..) => Ok ( ( ) ) ,
612614
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- }
615+ Rvalue :: Discriminant ( place) | Rvalue :: Len ( place) => self . validate_place ( place. as_ref ( ) ) ,
629616
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- }
617+ Rvalue :: Use ( operand)
618+ | Rvalue :: Repeat ( operand, _)
619+ | Rvalue :: UnaryOp ( _, operand)
620+ | Rvalue :: Cast ( _, operand, _) => self . validate_operand ( operand) ,
650621
622+ Rvalue :: BinaryOp ( _, lhs, rhs) | Rvalue :: CheckedBinaryOp ( _, lhs, rhs) => {
651623 self . validate_operand ( lhs) ?;
652- self . validate_operand ( rhs) ? ;
624+ self . validate_operand ( rhs)
653625 }
654626
655- Rvalue :: NullaryOp ( op, _) => match op {
656- NullOp :: Box => return Err ( Unpromotable ) ,
657- NullOp :: SizeOf => { }
658- } ,
659-
660627 Rvalue :: AddressOf ( _, place) => {
661628 // We accept `&raw *`, i.e., raw reborrows -- creating a raw pointer is
662629 // no problem, only using it is.
@@ -669,36 +636,53 @@ impl<'tcx> Validator<'_, 'tcx> {
669636 } ) ;
670637 }
671638 }
672- return Err ( Unpromotable ) ;
639+ Err ( Unpromotable )
673640 }
674641
675642 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+
676659 // Special-case reborrows to be more like a copy of the reference.
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 ;
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 ;
681663 if let ty:: Ref ( ..) = base_ty. kind ( ) {
682- place_simplified =
683- PlaceRef { local : place_simplified. local , projection : proj_base } ;
664+ place = PlaceRef { local : place. local , projection : proj_base } ;
684665 }
685666 }
686667
687- self . validate_place ( place_simplified) ?;
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+ }
688674
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) ?;
675+ Ok ( ( ) )
692676 }
693677
694- Rvalue :: Aggregate ( _, operands) => {
678+ Rvalue :: Aggregate ( _, ref operands) => {
695679 for o in operands {
696680 self . validate_operand ( o) ?;
697681 }
682+
683+ Ok ( ( ) )
698684 }
699685 }
700-
701- Ok ( ( ) )
702686 }
703687
704688 fn validate_call (
0 commit comments