@@ -6,7 +6,7 @@ use rustc_const_eval::const_eval::CheckAlignment;
6
6
use rustc_const_eval:: interpret:: { ImmTy , Immediate , InterpCx , OpTy , Projectable } ;
7
7
use rustc_data_structures:: fx:: FxHashMap ;
8
8
use rustc_hir:: def:: DefKind ;
9
- use rustc_middle:: mir:: interpret:: { ConstValue , Scalar } ;
9
+ use rustc_middle:: mir:: interpret:: { AllocId , ConstAllocation , ConstValue , InterpResult , Scalar } ;
10
10
use rustc_middle:: mir:: visit:: { MutVisitor , NonMutatingUseContext , PlaceContext , Visitor } ;
11
11
use rustc_middle:: mir:: * ;
12
12
use rustc_middle:: ty:: layout:: TyAndLayout ;
@@ -15,6 +15,7 @@ use rustc_mir_dataflow::value_analysis::{
15
15
Map , PlaceIndex , State , TrackElem , ValueAnalysis , ValueAnalysisWrapper , ValueOrPlace ,
16
16
} ;
17
17
use rustc_mir_dataflow:: { lattice:: FlatSet , Analysis , Results , ResultsVisitor } ;
18
+ use rustc_span:: def_id:: DefId ;
18
19
use rustc_span:: { Span , DUMMY_SP } ;
19
20
use rustc_target:: abi:: { Align , FieldIdx , VariantIdx } ;
20
21
@@ -78,7 +79,7 @@ struct ConstAnalysis<'a, 'tcx> {
78
79
}
79
80
80
81
impl < ' tcx > ValueAnalysis < ' tcx > for ConstAnalysis < ' _ , ' tcx > {
81
- type Value = FlatSet < ScalarInt > ;
82
+ type Value = FlatSet < Scalar > ;
82
83
83
84
const NAME : & ' static str = "ConstAnalysis" ;
84
85
@@ -182,7 +183,7 @@ impl<'tcx> ValueAnalysis<'tcx> for ConstAnalysis<'_, 'tcx> {
182
183
if let Some ( overflow_target) = overflow_target {
183
184
let overflow = match overflow {
184
185
FlatSet :: Top => FlatSet :: Top ,
185
- FlatSet :: Elem ( overflow) => FlatSet :: Elem ( overflow . into ( ) ) ,
186
+ FlatSet :: Elem ( overflow) => FlatSet :: Elem ( Scalar :: from_bool ( overflow ) ) ,
186
187
FlatSet :: Bottom => FlatSet :: Bottom ,
187
188
} ;
188
189
// We have flooded `target` earlier.
@@ -204,7 +205,7 @@ impl<'tcx> ValueAnalysis<'tcx> for ConstAnalysis<'_, 'tcx> {
204
205
&& let ty:: Array ( _, len) = operand_ty. ty . kind ( )
205
206
&& let Some ( len) = ConstantKind :: Ty ( * len) . eval ( self . tcx , self . param_env ) . try_to_scalar_int ( )
206
207
{
207
- state. insert_value_idx ( target_len, FlatSet :: Elem ( len) , self . map ( ) ) ;
208
+ state. insert_value_idx ( target_len, FlatSet :: Elem ( len. into ( ) ) , self . map ( ) ) ;
208
209
}
209
210
}
210
211
_ => self . super_assign ( target, rvalue, state) ,
@@ -222,7 +223,7 @@ impl<'tcx> ValueAnalysis<'tcx> for ConstAnalysis<'_, 'tcx> {
222
223
if let ty:: Array ( _, len) = place_ty. ty . kind ( ) {
223
224
ConstantKind :: Ty ( * len)
224
225
. eval ( self . tcx , self . param_env )
225
- . try_to_scalar_int ( )
226
+ . try_to_scalar ( )
226
227
. map_or ( FlatSet :: Top , FlatSet :: Elem )
227
228
} else if let [ ProjectionElem :: Deref ] = place. projection [ ..] {
228
229
state. get_len ( place. local . into ( ) , self . map ( ) )
@@ -281,7 +282,7 @@ impl<'tcx> ValueAnalysis<'tcx> for ConstAnalysis<'_, 'tcx> {
281
282
. bytes ( ) ,
282
283
_ => return ValueOrPlace :: Value ( FlatSet :: Top ) ,
283
284
} ;
284
- ScalarInt :: try_from_target_usize ( val, self . tcx ) . map_or ( FlatSet :: Top , FlatSet :: Elem )
285
+ FlatSet :: Elem ( Scalar :: from_target_usize ( val, & self . tcx ) )
285
286
}
286
287
Rvalue :: Discriminant ( place) => state. get_discr ( place. as_ref ( ) , self . map ( ) ) ,
287
288
_ => return self . super_rvalue ( rvalue, state) ,
@@ -297,7 +298,7 @@ impl<'tcx> ValueAnalysis<'tcx> for ConstAnalysis<'_, 'tcx> {
297
298
constant
298
299
. literal
299
300
. eval ( self . tcx , self . param_env )
300
- . try_to_scalar_int ( )
301
+ . try_to_scalar ( )
301
302
. map_or ( FlatSet :: Top , FlatSet :: Elem )
302
303
}
303
304
@@ -339,14 +340,21 @@ impl<'a, 'tcx> ConstAnalysis<'a, 'tcx> {
339
340
/// The caller must have flooded `place`.
340
341
fn assign_operand (
341
342
& self ,
342
- state : & mut State < FlatSet < ScalarInt > > ,
343
+ state : & mut State < FlatSet < Scalar > > ,
343
344
place : PlaceIndex ,
344
345
operand : & Operand < ' tcx > ,
345
346
) {
346
347
match operand {
347
348
Operand :: Copy ( rhs) | Operand :: Move ( rhs) => {
348
349
if let Some ( rhs) = self . map . find ( rhs. as_ref ( ) ) {
349
- state. insert_place_idx ( place, rhs, & self . map )
350
+ state. insert_place_idx ( place, rhs, & self . map ) ;
351
+ } else if rhs. projection . first ( ) == Some ( & PlaceElem :: Deref )
352
+ && let FlatSet :: Elem ( pointer) = state. get ( rhs. local . into ( ) , & self . map )
353
+ && let rhs_ty = self . local_decls [ rhs. local ] . ty
354
+ && let Ok ( rhs_layout) = self . tcx . layout_of ( self . param_env . and ( rhs_ty) )
355
+ {
356
+ let op = ImmTy :: from_scalar ( pointer, rhs_layout) . into ( ) ;
357
+ self . assign_constant ( state, place, op, & rhs. projection ) ;
350
358
}
351
359
}
352
360
Operand :: Constant ( box constant) => {
@@ -363,15 +371,15 @@ impl<'a, 'tcx> ConstAnalysis<'a, 'tcx> {
363
371
#[ instrument( level = "trace" , skip( self , state) ) ]
364
372
fn assign_constant (
365
373
& self ,
366
- state : & mut State < FlatSet < ScalarInt > > ,
374
+ state : & mut State < FlatSet < Scalar > > ,
367
375
place : PlaceIndex ,
368
376
mut operand : OpTy < ' tcx > ,
369
377
projection : & [ PlaceElem < ' tcx > ] ,
370
378
) -> Option < !> {
371
379
for & ( mut proj_elem) in projection {
372
380
if let PlaceElem :: Index ( index) = proj_elem {
373
381
if let FlatSet :: Elem ( index) = state. get ( index. into ( ) , & self . map )
374
- && let Ok ( offset) = index. try_to_target_usize ( self . tcx )
382
+ && let Ok ( offset) = index. to_target_usize ( & self . tcx )
375
383
&& let Some ( min_length) = offset. checked_add ( 1 )
376
384
{
377
385
proj_elem = PlaceElem :: ConstantIndex { offset, min_length, from_end : false } ;
@@ -406,7 +414,7 @@ impl<'a, 'tcx> ConstAnalysis<'a, 'tcx> {
406
414
& mut |place, op| {
407
415
if let Ok ( imm) = self . ecx . read_immediate_raw ( op)
408
416
&& let Some ( imm) = imm. right ( )
409
- && let Immediate :: Scalar ( Scalar :: Int ( scalar) ) = * imm
417
+ && let Immediate :: Scalar ( scalar) = * imm
410
418
{
411
419
state. insert_value_idx ( place, FlatSet :: Elem ( scalar) , & self . map ) ;
412
420
}
@@ -418,11 +426,11 @@ impl<'a, 'tcx> ConstAnalysis<'a, 'tcx> {
418
426
419
427
fn binary_op (
420
428
& self ,
421
- state : & mut State < FlatSet < ScalarInt > > ,
429
+ state : & mut State < FlatSet < Scalar > > ,
422
430
op : BinOp ,
423
431
left : & Operand < ' tcx > ,
424
432
right : & Operand < ' tcx > ,
425
- ) -> ( FlatSet < ScalarInt > , FlatSet < bool > ) {
433
+ ) -> ( FlatSet < Scalar > , FlatSet < bool > ) {
426
434
let left = self . eval_operand ( left, state) ;
427
435
let right = self . eval_operand ( right, state) ;
428
436
@@ -431,9 +439,7 @@ impl<'a, 'tcx> ConstAnalysis<'a, 'tcx> {
431
439
// Both sides are known, do the actual computation.
432
440
( FlatSet :: Elem ( left) , FlatSet :: Elem ( right) ) => {
433
441
match self . ecx . overflowing_binary_op ( op, & left, & right) {
434
- Ok ( ( Scalar :: Int ( val) , overflow, _) ) => {
435
- ( FlatSet :: Elem ( val) , FlatSet :: Elem ( overflow) )
436
- }
442
+ Ok ( ( val, overflow, _) ) => ( FlatSet :: Elem ( val) , FlatSet :: Elem ( overflow) ) ,
437
443
_ => ( FlatSet :: Top , FlatSet :: Top ) ,
438
444
}
439
445
}
@@ -445,9 +451,6 @@ impl<'a, 'tcx> ConstAnalysis<'a, 'tcx> {
445
451
}
446
452
447
453
let arg_scalar = const_arg. to_scalar ( ) ;
448
- let Ok ( arg_scalar) = arg_scalar. try_to_int ( ) else {
449
- return ( FlatSet :: Top , FlatSet :: Top ) ;
450
- } ;
451
454
let Ok ( arg_value) = arg_scalar. to_bits ( layout. size ) else {
452
455
return ( FlatSet :: Top , FlatSet :: Top ) ;
453
456
} ;
@@ -473,7 +476,7 @@ impl<'a, 'tcx> ConstAnalysis<'a, 'tcx> {
473
476
fn eval_operand (
474
477
& self ,
475
478
op : & Operand < ' tcx > ,
476
- state : & mut State < FlatSet < ScalarInt > > ,
479
+ state : & mut State < FlatSet < Scalar > > ,
477
480
) -> FlatSet < ImmTy < ' tcx > > {
478
481
let value = match self . handle_operand ( op, state) {
479
482
ValueOrPlace :: Value ( value) => value,
@@ -492,24 +495,24 @@ impl<'a, 'tcx> ConstAnalysis<'a, 'tcx> {
492
495
}
493
496
}
494
497
495
- fn eval_discriminant ( & self , enum_ty : Ty < ' tcx > , variant_index : VariantIdx ) -> Option < ScalarInt > {
498
+ fn eval_discriminant ( & self , enum_ty : Ty < ' tcx > , variant_index : VariantIdx ) -> Option < Scalar > {
496
499
if !enum_ty. is_enum ( ) {
497
500
return None ;
498
501
}
499
502
let discr = enum_ty. discriminant_for_variant ( self . tcx , variant_index) ?;
500
503
let discr_layout = self . tcx . layout_of ( self . param_env . and ( discr. ty ) ) . ok ( ) ?;
501
- let discr_value = ScalarInt :: try_from_uint ( discr. val , discr_layout. size ) ?;
504
+ let discr_value = Scalar :: try_from_uint ( discr. val , discr_layout. size ) ?;
502
505
Some ( discr_value)
503
506
}
504
507
505
- fn wrap_immediate ( & self , imm : Immediate ) -> FlatSet < ScalarInt > {
508
+ fn wrap_immediate ( & self , imm : Immediate ) -> FlatSet < Scalar > {
506
509
match imm {
507
- Immediate :: Scalar ( Scalar :: Int ( scalar) ) => FlatSet :: Elem ( scalar) ,
510
+ Immediate :: Scalar ( scalar) => FlatSet :: Elem ( scalar) ,
508
511
_ => FlatSet :: Top ,
509
512
}
510
513
}
511
514
512
- fn wrap_immty ( & self , val : ImmTy < ' tcx > ) -> FlatSet < ScalarInt > {
515
+ fn wrap_immty ( & self , val : ImmTy < ' tcx > ) -> FlatSet < Scalar > {
513
516
self . wrap_immediate ( * val)
514
517
}
515
518
}
@@ -550,7 +553,7 @@ impl<'mir, 'tcx>
550
553
ResultsVisitor < ' mir , ' tcx , Results < ' tcx , ValueAnalysisWrapper < ConstAnalysis < ' _ , ' tcx > > > >
551
554
for CollectAndPatch < ' tcx , ' _ >
552
555
{
553
- type FlowState = State < FlatSet < ScalarInt > > ;
556
+ type FlowState = State < FlatSet < Scalar > > ;
554
557
555
558
fn visit_statement_before_primary_effect (
556
559
& mut self ,
@@ -580,14 +583,10 @@ impl<'mir, 'tcx>
580
583
// Don't overwrite the assignment if it already uses a constant (to keep the span).
581
584
}
582
585
StatementKind :: Assign ( box ( place, _) ) => {
583
- match state. get ( place. as_ref ( ) , & results. analysis . 0 . map ) {
584
- FlatSet :: Top => ( ) ,
585
- FlatSet :: Elem ( value) => {
586
- self . assignments . insert ( location, value) ;
587
- }
588
- FlatSet :: Bottom => {
589
- // This assignment is either unreachable, or an uninitialized value is assigned.
590
- }
586
+ if let FlatSet :: Elem ( Scalar :: Int ( value) ) =
587
+ state. get ( place. as_ref ( ) , & results. analysis . 0 . map )
588
+ {
589
+ self . assignments . insert ( location, value) ;
591
590
}
592
591
}
593
592
_ => ( ) ,
@@ -657,15 +656,15 @@ impl<'tcx> MutVisitor<'tcx> for CollectAndPatch<'tcx, '_> {
657
656
}
658
657
659
658
struct OperandCollector < ' tcx , ' map , ' locals , ' a > {
660
- state : & ' a State < FlatSet < ScalarInt > > ,
659
+ state : & ' a State < FlatSet < Scalar > > ,
661
660
visitor : & ' a mut CollectAndPatch < ' tcx , ' locals > ,
662
661
map : & ' map Map ,
663
662
}
664
663
665
664
impl < ' tcx > Visitor < ' tcx > for OperandCollector < ' tcx , ' _ , ' _ , ' _ > {
666
665
fn visit_operand ( & mut self , operand : & Operand < ' tcx > , location : Location ) {
667
666
if let Some ( place) = operand. place ( ) {
668
- if let FlatSet :: Elem ( value) = self . state . get ( place. as_ref ( ) , self . map ) {
667
+ if let FlatSet :: Elem ( Scalar :: Int ( value) ) = self . state . get ( place. as_ref ( ) , self . map ) {
669
668
self . visitor . before_effect . insert ( ( location, place) , value) ;
670
669
} else if !place. projection . is_empty ( ) {
671
670
// Try to propagate into `Index` projections.
@@ -676,7 +675,7 @@ impl<'tcx> Visitor<'tcx> for OperandCollector<'tcx, '_, '_, '_> {
676
675
677
676
fn visit_local ( & mut self , local : Local , ctxt : PlaceContext , location : Location ) {
678
677
if let PlaceContext :: NonMutatingUse ( NonMutatingUseContext :: Copy | NonMutatingUseContext :: Move ) = ctxt
679
- && let FlatSet :: Elem ( value) = self . state . get ( local. into ( ) , self . map )
678
+ && let FlatSet :: Elem ( Scalar :: Int ( value) ) = self . state . get ( local. into ( ) , self . map )
680
679
{
681
680
self . visitor . before_effect . insert ( ( location, local. into ( ) ) , value) ;
682
681
}
@@ -685,6 +684,34 @@ impl<'tcx> Visitor<'tcx> for OperandCollector<'tcx, '_, '_, '_> {
685
684
686
685
struct DummyMachine ;
687
686
687
+ /// Macro for machine-specific `InterpError` without allocation.
688
+ /// (These will never be shown to the user, but they help diagnose ICEs.)
689
+ macro_rules! throw_machine_stop_str {
690
+ ( $( $tt: tt) * ) => { {
691
+ // We make a new local type for it. The type itself does not carry any information,
692
+ // but its vtable (for the `MachineStopType` trait) does.
693
+ #[ derive( Debug ) ]
694
+ struct Zst ;
695
+ // Printing this type shows the desired string.
696
+ impl std:: fmt:: Display for Zst {
697
+ fn fmt( & self , f: & mut std:: fmt:: Formatter <' _>) -> std:: fmt:: Result {
698
+ write!( f, $( $tt) * )
699
+ }
700
+ }
701
+ impl rustc_middle:: mir:: interpret:: MachineStopType for Zst {
702
+ fn diagnostic_message( & self ) -> rustc_errors:: DiagnosticMessage {
703
+ self . to_string( ) . into( )
704
+ }
705
+
706
+ fn add_args(
707
+ self : Box <Self >,
708
+ _: & mut dyn FnMut ( std:: borrow:: Cow <' static , str >, rustc_errors:: DiagnosticArgValue <' static >) ,
709
+ ) { }
710
+ }
711
+ throw_machine_stop!( Zst )
712
+ } } ;
713
+ }
714
+
688
715
impl < ' mir , ' tcx : ' mir > rustc_const_eval:: interpret:: Machine < ' mir , ' tcx > for DummyMachine {
689
716
rustc_const_eval:: interpret:: compile_time_machine!( <' mir, ' tcx>) ;
690
717
type MemoryKind = !;
@@ -714,6 +741,27 @@ impl<'mir, 'tcx: 'mir> rustc_const_eval::interpret::Machine<'mir, 'tcx> for Dumm
714
741
unimplemented ! ( )
715
742
}
716
743
744
+ fn before_access_global (
745
+ _tcx : TyCtxt < ' tcx > ,
746
+ _machine : & Self ,
747
+ _alloc_id : AllocId ,
748
+ alloc : ConstAllocation < ' tcx > ,
749
+ _static_def_id : Option < DefId > ,
750
+ is_write : bool ,
751
+ ) -> InterpResult < ' tcx > {
752
+ if is_write {
753
+ throw_machine_stop_str ! ( "can't write to global" ) ;
754
+ }
755
+
756
+ // If the static allocation is mutable, then we can't const prop it as its content
757
+ // might be different at runtime.
758
+ if alloc. inner ( ) . mutability . is_mut ( ) {
759
+ throw_machine_stop_str ! ( "can't access mutable globals in ConstProp" ) ;
760
+ }
761
+
762
+ Ok ( ( ) )
763
+ }
764
+
717
765
fn find_mir_or_eval_fn (
718
766
_ecx : & mut InterpCx < ' mir , ' tcx , Self > ,
719
767
_instance : ty:: Instance < ' tcx > ,
0 commit comments