@@ -90,7 +90,7 @@ pub enum TempState {
90
90
impl TempState {
91
91
pub fn is_promotable ( & self ) -> bool {
92
92
debug ! ( "is_promotable: self={:?}" , self ) ;
93
- matches ! ( self , TempState :: Defined { .. } )
93
+ matches ! ( self , TempState :: Defined { .. } )
94
94
}
95
95
}
96
96
@@ -309,50 +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
-
356
332
Ok ( ( ) )
357
333
}
358
334
_ => bug ! ( ) ,
@@ -572,58 +548,115 @@ impl<'tcx> Validator<'_, 'tcx> {
572
548
}
573
549
}
574
550
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 {
583
560
return Err ( Unpromotable ) ;
584
561
}
585
562
}
586
563
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 ;
598
566
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 {
600
576
return Err ( Unpromotable ) ;
601
577
}
602
578
}
603
-
604
- Rvalue :: NullaryOp ( NullOp :: Box , _) => return Err ( Unpromotable ) ,
605
-
606
- // FIXME(RalfJung): the rest is *implicitly considered promotable*... that seems dangerous.
607
- _ => { }
608
579
}
609
580
581
+ Ok ( ( ) )
582
+ }
583
+
584
+ fn validate_rvalue ( & self , rvalue : & Rvalue < ' tcx > ) -> Result < ( ) , Unpromotable > {
610
585
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
+ }
612
591
613
- Rvalue :: NullaryOp ( ..) => Ok ( ( ) ) ,
592
+ Rvalue :: Discriminant ( place) | Rvalue :: Len ( place) => {
593
+ self . validate_place ( place. as_ref ( ) ) ?
594
+ }
614
595
615
- Rvalue :: Discriminant ( place ) | Rvalue :: Len ( place ) => self . validate_place ( place . as_ref ( ) ) ,
596
+ Rvalue :: ThreadLocalRef ( _ ) => return Err ( Unpromotable ) ,
616
597
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
+ }
621
650
622
- Rvalue :: BinaryOp ( _, lhs, rhs) | Rvalue :: CheckedBinaryOp ( _, lhs, rhs) => {
623
651
self . validate_operand ( lhs) ?;
624
- self . validate_operand ( rhs)
652
+ self . validate_operand ( rhs) ? ;
625
653
}
626
654
655
+ Rvalue :: NullaryOp ( op, _) => match op {
656
+ NullOp :: Box => return Err ( Unpromotable ) ,
657
+ NullOp :: SizeOf => { }
658
+ } ,
659
+
627
660
Rvalue :: AddressOf ( _, place) => {
628
661
// We accept `&raw *`, i.e., raw reborrows -- creating a raw pointer is
629
662
// no problem, only using it is.
@@ -636,53 +669,36 @@ impl<'tcx> Validator<'_, 'tcx> {
636
669
} ) ;
637
670
}
638
671
}
639
- Err ( Unpromotable )
672
+ return Err ( Unpromotable ) ;
640
673
}
641
674
642
675
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
676
// 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 ;
663
681
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 } ;
665
684
}
666
685
}
667
686
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) ?;
674
688
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) ?;
676
692
}
677
693
678
- Rvalue :: Aggregate ( _, ref operands) => {
694
+ Rvalue :: Aggregate ( _, operands) => {
679
695
for o in operands {
680
696
self . validate_operand ( o) ?;
681
697
}
682
-
683
- Ok ( ( ) )
684
698
}
685
699
}
700
+
701
+ Ok ( ( ) )
686
702
}
687
703
688
704
fn validate_call (
0 commit comments