@@ -6,7 +6,7 @@ use rustc_const_eval::const_eval::CheckAlignment;
66use rustc_const_eval:: interpret:: { ImmTy , Immediate , InterpCx , OpTy , Projectable } ;
77use rustc_data_structures:: fx:: FxHashMap ;
88use rustc_hir:: def:: DefKind ;
9- use rustc_middle:: mir:: interpret:: { ConstValue , Scalar } ;
9+ use rustc_middle:: mir:: interpret:: { AllocId , ConstAllocation , ConstValue , InterpResult , Scalar } ;
1010use rustc_middle:: mir:: visit:: { MutVisitor , NonMutatingUseContext , PlaceContext , Visitor } ;
1111use rustc_middle:: mir:: * ;
1212use rustc_middle:: ty:: layout:: TyAndLayout ;
@@ -15,6 +15,7 @@ use rustc_mir_dataflow::value_analysis::{
1515 Map , PlaceIndex , State , TrackElem , ValueAnalysis , ValueAnalysisWrapper , ValueOrPlace ,
1616} ;
1717use rustc_mir_dataflow:: { lattice:: FlatSet , Analysis , Results , ResultsVisitor } ;
18+ use rustc_span:: def_id:: DefId ;
1819use rustc_span:: { Span , DUMMY_SP } ;
1920use rustc_target:: abi:: { Align , FieldIdx , VariantIdx } ;
2021
@@ -78,7 +79,7 @@ struct ConstAnalysis<'a, 'tcx> {
7879}
7980
8081impl < ' tcx > ValueAnalysis < ' tcx > for ConstAnalysis < ' _ , ' tcx > {
81- type Value = FlatSet < ScalarInt > ;
82+ type Value = FlatSet < Scalar > ;
8283
8384 const NAME : & ' static str = "ConstAnalysis" ;
8485
@@ -182,7 +183,7 @@ impl<'tcx> ValueAnalysis<'tcx> for ConstAnalysis<'_, 'tcx> {
182183 if let Some ( overflow_target) = overflow_target {
183184 let overflow = match overflow {
184185 FlatSet :: Top => FlatSet :: Top ,
185- FlatSet :: Elem ( overflow) => FlatSet :: Elem ( overflow . into ( ) ) ,
186+ FlatSet :: Elem ( overflow) => FlatSet :: Elem ( Scalar :: from_bool ( overflow ) ) ,
186187 FlatSet :: Bottom => FlatSet :: Bottom ,
187188 } ;
188189 // We have flooded `target` earlier.
@@ -204,7 +205,7 @@ impl<'tcx> ValueAnalysis<'tcx> for ConstAnalysis<'_, 'tcx> {
204205 && let ty:: Array ( _, len) = operand_ty. ty . kind ( )
205206 && let Some ( len) = ConstantKind :: Ty ( * len) . eval ( self . tcx , self . param_env ) . try_to_scalar_int ( )
206207 {
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 ( ) ) ;
208209 }
209210 }
210211 _ => self . super_assign ( target, rvalue, state) ,
@@ -222,7 +223,7 @@ impl<'tcx> ValueAnalysis<'tcx> for ConstAnalysis<'_, 'tcx> {
222223 if let ty:: Array ( _, len) = place_ty. ty . kind ( ) {
223224 ConstantKind :: Ty ( * len)
224225 . eval ( self . tcx , self . param_env )
225- . try_to_scalar_int ( )
226+ . try_to_scalar ( )
226227 . map_or ( FlatSet :: Top , FlatSet :: Elem )
227228 } else if let [ ProjectionElem :: Deref ] = place. projection [ ..] {
228229 state. get_len ( place. local . into ( ) , self . map ( ) )
@@ -281,7 +282,7 @@ impl<'tcx> ValueAnalysis<'tcx> for ConstAnalysis<'_, 'tcx> {
281282 . bytes ( ) ,
282283 _ => return ValueOrPlace :: Value ( FlatSet :: Top ) ,
283284 } ;
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 ) )
285286 }
286287 Rvalue :: Discriminant ( place) => state. get_discr ( place. as_ref ( ) , self . map ( ) ) ,
287288 _ => return self . super_rvalue ( rvalue, state) ,
@@ -297,7 +298,7 @@ impl<'tcx> ValueAnalysis<'tcx> for ConstAnalysis<'_, 'tcx> {
297298 constant
298299 . literal
299300 . eval ( self . tcx , self . param_env )
300- . try_to_scalar_int ( )
301+ . try_to_scalar ( )
301302 . map_or ( FlatSet :: Top , FlatSet :: Elem )
302303 }
303304
@@ -339,14 +340,21 @@ impl<'a, 'tcx> ConstAnalysis<'a, 'tcx> {
339340 /// The caller must have flooded `place`.
340341 fn assign_operand (
341342 & self ,
342- state : & mut State < FlatSet < ScalarInt > > ,
343+ state : & mut State < FlatSet < Scalar > > ,
343344 place : PlaceIndex ,
344345 operand : & Operand < ' tcx > ,
345346 ) {
346347 match operand {
347348 Operand :: Copy ( rhs) | Operand :: Move ( rhs) => {
348349 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 ) ;
350358 }
351359 }
352360 Operand :: Constant ( box constant) => {
@@ -363,15 +371,15 @@ impl<'a, 'tcx> ConstAnalysis<'a, 'tcx> {
363371 #[ instrument( level = "trace" , skip( self , state) ) ]
364372 fn assign_constant (
365373 & self ,
366- state : & mut State < FlatSet < ScalarInt > > ,
374+ state : & mut State < FlatSet < Scalar > > ,
367375 place : PlaceIndex ,
368376 mut operand : OpTy < ' tcx > ,
369377 projection : & [ PlaceElem < ' tcx > ] ,
370378 ) -> Option < !> {
371379 for & ( mut proj_elem) in projection {
372380 if let PlaceElem :: Index ( index) = proj_elem {
373381 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 )
375383 && let Some ( min_length) = offset. checked_add ( 1 )
376384 {
377385 proj_elem = PlaceElem :: ConstantIndex { offset, min_length, from_end : false } ;
@@ -406,7 +414,7 @@ impl<'a, 'tcx> ConstAnalysis<'a, 'tcx> {
406414 & mut |place, op| {
407415 if let Ok ( imm) = self . ecx . read_immediate_raw ( op)
408416 && let Some ( imm) = imm. right ( )
409- && let Immediate :: Scalar ( Scalar :: Int ( scalar) ) = * imm
417+ && let Immediate :: Scalar ( scalar) = * imm
410418 {
411419 state. insert_value_idx ( place, FlatSet :: Elem ( scalar) , & self . map ) ;
412420 }
@@ -418,11 +426,11 @@ impl<'a, 'tcx> ConstAnalysis<'a, 'tcx> {
418426
419427 fn binary_op (
420428 & self ,
421- state : & mut State < FlatSet < ScalarInt > > ,
429+ state : & mut State < FlatSet < Scalar > > ,
422430 op : BinOp ,
423431 left : & Operand < ' tcx > ,
424432 right : & Operand < ' tcx > ,
425- ) -> ( FlatSet < ScalarInt > , FlatSet < bool > ) {
433+ ) -> ( FlatSet < Scalar > , FlatSet < bool > ) {
426434 let left = self . eval_operand ( left, state) ;
427435 let right = self . eval_operand ( right, state) ;
428436
@@ -431,9 +439,7 @@ impl<'a, 'tcx> ConstAnalysis<'a, 'tcx> {
431439 // Both sides are known, do the actual computation.
432440 ( FlatSet :: Elem ( left) , FlatSet :: Elem ( right) ) => {
433441 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) ) ,
437443 _ => ( FlatSet :: Top , FlatSet :: Top ) ,
438444 }
439445 }
@@ -445,9 +451,6 @@ impl<'a, 'tcx> ConstAnalysis<'a, 'tcx> {
445451 }
446452
447453 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- } ;
451454 let Ok ( arg_value) = arg_scalar. to_bits ( layout. size ) else {
452455 return ( FlatSet :: Top , FlatSet :: Top ) ;
453456 } ;
@@ -473,7 +476,7 @@ impl<'a, 'tcx> ConstAnalysis<'a, 'tcx> {
473476 fn eval_operand (
474477 & self ,
475478 op : & Operand < ' tcx > ,
476- state : & mut State < FlatSet < ScalarInt > > ,
479+ state : & mut State < FlatSet < Scalar > > ,
477480 ) -> FlatSet < ImmTy < ' tcx > > {
478481 let value = match self . handle_operand ( op, state) {
479482 ValueOrPlace :: Value ( value) => value,
@@ -492,24 +495,24 @@ impl<'a, 'tcx> ConstAnalysis<'a, 'tcx> {
492495 }
493496 }
494497
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 > {
496499 if !enum_ty. is_enum ( ) {
497500 return None ;
498501 }
499502 let discr = enum_ty. discriminant_for_variant ( self . tcx , variant_index) ?;
500503 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 ) ?;
502505 Some ( discr_value)
503506 }
504507
505- fn wrap_immediate ( & self , imm : Immediate ) -> FlatSet < ScalarInt > {
508+ fn wrap_immediate ( & self , imm : Immediate ) -> FlatSet < Scalar > {
506509 match imm {
507- Immediate :: Scalar ( Scalar :: Int ( scalar) ) => FlatSet :: Elem ( scalar) ,
510+ Immediate :: Scalar ( scalar) => FlatSet :: Elem ( scalar) ,
508511 _ => FlatSet :: Top ,
509512 }
510513 }
511514
512- fn wrap_immty ( & self , val : ImmTy < ' tcx > ) -> FlatSet < ScalarInt > {
515+ fn wrap_immty ( & self , val : ImmTy < ' tcx > ) -> FlatSet < Scalar > {
513516 self . wrap_immediate ( * val)
514517 }
515518}
@@ -550,7 +553,7 @@ impl<'mir, 'tcx>
550553 ResultsVisitor < ' mir , ' tcx , Results < ' tcx , ValueAnalysisWrapper < ConstAnalysis < ' _ , ' tcx > > > >
551554 for CollectAndPatch < ' tcx , ' _ >
552555{
553- type FlowState = State < FlatSet < ScalarInt > > ;
556+ type FlowState = State < FlatSet < Scalar > > ;
554557
555558 fn visit_statement_before_primary_effect (
556559 & mut self ,
@@ -580,14 +583,10 @@ impl<'mir, 'tcx>
580583 // Don't overwrite the assignment if it already uses a constant (to keep the span).
581584 }
582585 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) ;
591590 }
592591 }
593592 _ => ( ) ,
@@ -657,15 +656,15 @@ impl<'tcx> MutVisitor<'tcx> for CollectAndPatch<'tcx, '_> {
657656}
658657
659658struct OperandCollector < ' tcx , ' map , ' locals , ' a > {
660- state : & ' a State < FlatSet < ScalarInt > > ,
659+ state : & ' a State < FlatSet < Scalar > > ,
661660 visitor : & ' a mut CollectAndPatch < ' tcx , ' locals > ,
662661 map : & ' map Map ,
663662}
664663
665664impl < ' tcx > Visitor < ' tcx > for OperandCollector < ' tcx , ' _ , ' _ , ' _ > {
666665 fn visit_operand ( & mut self , operand : & Operand < ' tcx > , location : Location ) {
667666 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 ) {
669668 self . visitor . before_effect . insert ( ( location, place) , value) ;
670669 } else if !place. projection . is_empty ( ) {
671670 // Try to propagate into `Index` projections.
@@ -676,7 +675,7 @@ impl<'tcx> Visitor<'tcx> for OperandCollector<'tcx, '_, '_, '_> {
676675
677676 fn visit_local ( & mut self , local : Local , ctxt : PlaceContext , location : Location ) {
678677 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 )
680679 {
681680 self . visitor . before_effect . insert ( ( location, local. into ( ) ) , value) ;
682681 }
@@ -685,6 +684,34 @@ impl<'tcx> Visitor<'tcx> for OperandCollector<'tcx, '_, '_, '_> {
685684
686685struct DummyMachine ;
687686
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+
688715impl < ' mir , ' tcx : ' mir > rustc_const_eval:: interpret:: Machine < ' mir , ' tcx > for DummyMachine {
689716 rustc_const_eval:: interpret:: compile_time_machine!( <' mir, ' tcx>) ;
690717 type MemoryKind = !;
@@ -714,6 +741,27 @@ impl<'mir, 'tcx: 'mir> rustc_const_eval::interpret::Machine<'mir, 'tcx> for Dumm
714741 unimplemented ! ( )
715742 }
716743
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+
717765 fn find_mir_or_eval_fn (
718766 _ecx : & mut InterpCx < ' mir , ' tcx , Self > ,
719767 _instance : ty:: Instance < ' tcx > ,
0 commit comments