@@ -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,26 +309,50 @@ 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
+
312
322
// We can only promote interior borrows of promotable temps (non-temps
313
323
// don't get promoted anyway).
314
324
self . validate_local ( place. local ) ?;
315
325
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.
322
326
if place. projection . contains ( & ProjectionElem :: Deref ) {
323
327
return Err ( Unpromotable ) ;
324
328
}
325
-
326
- // We cannot promote things that need dropping, since the promoted value
327
- // would not get dropped.
328
329
if self . qualif_local :: < qualifs:: NeedsDrop > ( place. local ) {
329
330
return Err ( Unpromotable ) ;
330
331
}
331
332
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
+
332
356
Ok ( ( ) )
333
357
}
334
358
_ => bug ! ( ) ,
@@ -548,115 +572,58 @@ impl<'tcx> Validator<'_, 'tcx> {
548
572
}
549
573
}
550
574
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
560
583
return Err ( Unpromotable ) ;
561
584
}
562
585
}
563
586
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
+ ) ;
566
598
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
576
600
return Err ( Unpromotable ) ;
577
601
}
578
602
}
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
- }
591
603
592
- Rvalue :: Discriminant ( place) | Rvalue :: Len ( place) => {
593
- self . validate_place ( place. as_ref ( ) ) ?
594
- }
604
+ Rvalue :: NullaryOp ( NullOp :: Box , _) => return Err ( Unpromotable ) ,
595
605
596
- Rvalue :: ThreadLocalRef ( _) => return Err ( Unpromotable ) ,
606
+ // FIXME(RalfJung): the rest is *implicitly considered promotable*... that seems dangerous.
607
+ _ => { }
608
+ }
597
609
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 ) ,
609
612
610
- self . validate_operand ( operand) ?;
611
- }
613
+ Rvalue :: NullaryOp ( ..) => Ok ( ( ) ) ,
612
614
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 ( ) ) ,
629
616
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) ,
650
621
622
+ Rvalue :: BinaryOp ( _, lhs, rhs) | Rvalue :: CheckedBinaryOp ( _, lhs, rhs) => {
651
623
self . validate_operand ( lhs) ?;
652
- self . validate_operand ( rhs) ? ;
624
+ self . validate_operand ( rhs)
653
625
}
654
626
655
- Rvalue :: NullaryOp ( op, _) => match op {
656
- NullOp :: Box => return Err ( Unpromotable ) ,
657
- NullOp :: SizeOf => { }
658
- } ,
659
-
660
627
Rvalue :: AddressOf ( _, place) => {
661
628
// We accept `&raw *`, i.e., raw reborrows -- creating a raw pointer is
662
629
// no problem, only using it is.
@@ -669,36 +636,53 @@ impl<'tcx> Validator<'_, 'tcx> {
669
636
} ) ;
670
637
}
671
638
}
672
- return Err ( Unpromotable ) ;
639
+ Err ( Unpromotable )
673
640
}
674
641
675
642
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
+
676
659
// 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 ;
681
663
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 } ;
684
665
}
685
666
}
686
667
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
+ }
688
674
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 ( ( ) )
692
676
}
693
677
694
- Rvalue :: Aggregate ( _, operands) => {
678
+ Rvalue :: Aggregate ( _, ref operands) => {
695
679
for o in operands {
696
680
self . validate_operand ( o) ?;
697
681
}
682
+
683
+ Ok ( ( ) )
698
684
}
699
685
}
700
-
701
- Ok ( ( ) )
702
686
}
703
687
704
688
fn validate_call (
0 commit comments