2
2
//!
3
3
//! Currently, this pass only propagates scalar values.
4
4
5
+ use std:: assert_matches:: assert_matches;
6
+ use std:: fmt:: Formatter ;
7
+
5
8
use rustc_const_eval:: const_eval:: { DummyMachine , throw_machine_stop_str} ;
6
9
use rustc_const_eval:: interpret:: {
7
10
ImmTy , Immediate , InterpCx , OpTy , PlaceTy , Projectable , interp_ok,
@@ -14,9 +17,10 @@ use rustc_middle::mir::visit::{MutVisitor, PlaceContext, Visitor};
14
17
use rustc_middle:: mir:: * ;
15
18
use rustc_middle:: ty:: layout:: { HasParamEnv , LayoutOf } ;
16
19
use rustc_middle:: ty:: { self , Ty , TyCtxt } ;
17
- use rustc_mir_dataflow:: lattice:: FlatSet ;
20
+ use rustc_mir_dataflow:: fmt:: DebugWithContext ;
21
+ use rustc_mir_dataflow:: lattice:: { FlatSet , HasBottom } ;
18
22
use rustc_mir_dataflow:: value_analysis:: {
19
- Map , PlaceIndex , State , TrackElem , ValueAnalysis , ValueAnalysisWrapper , ValueOrPlace ,
23
+ Map , PlaceIndex , State , TrackElem , ValueOrPlace , debug_with_context ,
20
24
} ;
21
25
use rustc_mir_dataflow:: { Analysis , Results , ResultsVisitor } ;
22
26
use rustc_span:: DUMMY_SP ;
@@ -58,8 +62,8 @@ impl<'tcx> crate::MirPass<'tcx> for DataflowConstProp {
58
62
59
63
// Perform the actual dataflow analysis.
60
64
let analysis = ConstAnalysis :: new ( tcx, body, map) ;
61
- let mut results = debug_span ! ( "analyze" )
62
- . in_scope ( || analysis. wrap ( ) . iterate_to_fixpoint ( tcx, body, None ) ) ;
65
+ let mut results =
66
+ debug_span ! ( "analyze" ) . in_scope ( || analysis. iterate_to_fixpoint ( tcx, body, None ) ) ;
63
67
64
68
// Collect results and patch the body afterwards.
65
69
let mut visitor = Collector :: new ( tcx, & body. local_decls ) ;
@@ -69,6 +73,10 @@ impl<'tcx> crate::MirPass<'tcx> for DataflowConstProp {
69
73
}
70
74
}
71
75
76
+ // Note: Currently, places that have their reference taken cannot be tracked. Although this would
77
+ // be possible, it has to rely on some aliasing model, which we are not ready to commit to yet.
78
+ // Because of that, we can assume that the only way to change the value behind a tracked place is
79
+ // by direct assignment.
72
80
struct ConstAnalysis < ' a , ' tcx > {
73
81
map : Map < ' tcx > ,
74
82
tcx : TyCtxt < ' tcx > ,
@@ -77,20 +85,198 @@ struct ConstAnalysis<'a, 'tcx> {
77
85
param_env : ty:: ParamEnv < ' tcx > ,
78
86
}
79
87
80
- impl < ' tcx > ValueAnalysis < ' tcx > for ConstAnalysis < ' _ , ' tcx > {
81
- type Value = FlatSet < Scalar > ;
88
+ impl < ' tcx > Analysis < ' tcx > for ConstAnalysis < ' _ , ' tcx > {
89
+ type Domain = State < FlatSet < Scalar > > ;
82
90
83
91
const NAME : & ' static str = "ConstAnalysis" ;
84
92
85
- fn map ( & self ) -> & Map < ' tcx > {
86
- & self . map
93
+ // The bottom state denotes uninitialized memory. Because we are only doing a sound
94
+ // approximation of the actual execution, we can also use this state for places where access
95
+ // would be UB.
96
+ fn bottom_value ( & self , _body : & Body < ' tcx > ) -> Self :: Domain {
97
+ State :: Unreachable
98
+ }
99
+
100
+ fn initialize_start_block ( & self , body : & Body < ' tcx > , state : & mut Self :: Domain ) {
101
+ // The initial state maps all tracked places of argument projections to ⊤ and the rest to ⊥.
102
+ assert_matches ! ( state, State :: Unreachable ) ;
103
+ * state = State :: new_reachable ( ) ;
104
+ for arg in body. args_iter ( ) {
105
+ state. flood ( PlaceRef { local : arg, projection : & [ ] } , & self . map ) ;
106
+ }
107
+ }
108
+
109
+ fn apply_statement_effect (
110
+ & mut self ,
111
+ state : & mut Self :: Domain ,
112
+ statement : & Statement < ' tcx > ,
113
+ _location : Location ,
114
+ ) {
115
+ if state. is_reachable ( ) {
116
+ self . handle_statement ( statement, state) ;
117
+ }
118
+ }
119
+
120
+ fn apply_terminator_effect < ' mir > (
121
+ & mut self ,
122
+ state : & mut Self :: Domain ,
123
+ terminator : & ' mir Terminator < ' tcx > ,
124
+ _location : Location ,
125
+ ) -> TerminatorEdges < ' mir , ' tcx > {
126
+ if state. is_reachable ( ) {
127
+ self . handle_terminator ( terminator, state)
128
+ } else {
129
+ TerminatorEdges :: None
130
+ }
131
+ }
132
+
133
+ fn apply_call_return_effect (
134
+ & mut self ,
135
+ state : & mut Self :: Domain ,
136
+ _block : BasicBlock ,
137
+ return_places : CallReturnPlaces < ' _ , ' tcx > ,
138
+ ) {
139
+ if state. is_reachable ( ) {
140
+ self . handle_call_return ( return_places, state)
141
+ }
142
+ }
143
+ }
144
+
145
+ impl < ' a , ' tcx > ConstAnalysis < ' a , ' tcx > {
146
+ fn new ( tcx : TyCtxt < ' tcx > , body : & ' a Body < ' tcx > , map : Map < ' tcx > ) -> Self {
147
+ let param_env = tcx. param_env_reveal_all_normalized ( body. source . def_id ( ) ) ;
148
+ Self {
149
+ map,
150
+ tcx,
151
+ local_decls : & body. local_decls ,
152
+ ecx : InterpCx :: new ( tcx, DUMMY_SP , param_env, DummyMachine ) ,
153
+ param_env,
154
+ }
155
+ }
156
+
157
+ fn handle_statement ( & self , statement : & Statement < ' tcx > , state : & mut State < FlatSet < Scalar > > ) {
158
+ match & statement. kind {
159
+ StatementKind :: Assign ( box ( place, rvalue) ) => {
160
+ self . handle_assign ( * place, rvalue, state) ;
161
+ }
162
+ StatementKind :: SetDiscriminant { box place, variant_index } => {
163
+ self . handle_set_discriminant ( * place, * variant_index, state) ;
164
+ }
165
+ StatementKind :: Intrinsic ( box intrinsic) => {
166
+ self . handle_intrinsic ( intrinsic) ;
167
+ }
168
+ StatementKind :: StorageLive ( local) | StatementKind :: StorageDead ( local) => {
169
+ // StorageLive leaves the local in an uninitialized state.
170
+ // StorageDead makes it UB to access the local afterwards.
171
+ state. flood_with (
172
+ Place :: from ( * local) . as_ref ( ) ,
173
+ & self . map ,
174
+ FlatSet :: < Scalar > :: BOTTOM ,
175
+ ) ;
176
+ }
177
+ StatementKind :: Deinit ( box place) => {
178
+ // Deinit makes the place uninitialized.
179
+ state. flood_with ( place. as_ref ( ) , & self . map , FlatSet :: < Scalar > :: BOTTOM ) ;
180
+ }
181
+ StatementKind :: Retag ( ..) => {
182
+ // We don't track references.
183
+ }
184
+ StatementKind :: ConstEvalCounter
185
+ | StatementKind :: Nop
186
+ | StatementKind :: FakeRead ( ..)
187
+ | StatementKind :: PlaceMention ( ..)
188
+ | StatementKind :: Coverage ( ..)
189
+ | StatementKind :: AscribeUserType ( ..) => ( ) ,
190
+ }
191
+ }
192
+
193
+ fn handle_intrinsic ( & self , intrinsic : & NonDivergingIntrinsic < ' tcx > ) {
194
+ match intrinsic {
195
+ NonDivergingIntrinsic :: Assume ( ..) => {
196
+ // Could use this, but ignoring it is sound.
197
+ }
198
+ NonDivergingIntrinsic :: CopyNonOverlapping ( CopyNonOverlapping {
199
+ dst : _,
200
+ src : _,
201
+ count : _,
202
+ } ) => {
203
+ // This statement represents `*dst = *src`, `count` times.
204
+ }
205
+ }
206
+ }
207
+
208
+ fn handle_operand (
209
+ & self ,
210
+ operand : & Operand < ' tcx > ,
211
+ state : & mut State < FlatSet < Scalar > > ,
212
+ ) -> ValueOrPlace < FlatSet < Scalar > > {
213
+ match operand {
214
+ Operand :: Constant ( box constant) => {
215
+ ValueOrPlace :: Value ( self . handle_constant ( constant, state) )
216
+ }
217
+ Operand :: Copy ( place) | Operand :: Move ( place) => {
218
+ // On move, we would ideally flood the place with bottom. But with the current
219
+ // framework this is not possible (similar to `InterpCx::eval_operand`).
220
+ self . map . find ( place. as_ref ( ) ) . map ( ValueOrPlace :: Place ) . unwrap_or ( ValueOrPlace :: TOP )
221
+ }
222
+ }
223
+ }
224
+
225
+ /// The effect of a successful function call return should not be
226
+ /// applied here, see [`Analysis::apply_terminator_effect`].
227
+ fn handle_terminator < ' mir > (
228
+ & self ,
229
+ terminator : & ' mir Terminator < ' tcx > ,
230
+ state : & mut State < FlatSet < Scalar > > ,
231
+ ) -> TerminatorEdges < ' mir , ' tcx > {
232
+ match & terminator. kind {
233
+ TerminatorKind :: Call { .. } | TerminatorKind :: InlineAsm { .. } => {
234
+ // Effect is applied by `handle_call_return`.
235
+ }
236
+ TerminatorKind :: Drop { place, .. } => {
237
+ state. flood_with ( place. as_ref ( ) , & self . map , FlatSet :: < Scalar > :: BOTTOM ) ;
238
+ }
239
+ TerminatorKind :: Yield { .. } => {
240
+ // They would have an effect, but are not allowed in this phase.
241
+ bug ! ( "encountered disallowed terminator" ) ;
242
+ }
243
+ TerminatorKind :: SwitchInt { discr, targets } => {
244
+ return self . handle_switch_int ( discr, targets, state) ;
245
+ }
246
+ TerminatorKind :: TailCall { .. } => {
247
+ // FIXME(explicit_tail_calls): determine if we need to do something here (probably
248
+ // not)
249
+ }
250
+ TerminatorKind :: Goto { .. }
251
+ | TerminatorKind :: UnwindResume
252
+ | TerminatorKind :: UnwindTerminate ( _)
253
+ | TerminatorKind :: Return
254
+ | TerminatorKind :: Unreachable
255
+ | TerminatorKind :: Assert { .. }
256
+ | TerminatorKind :: CoroutineDrop
257
+ | TerminatorKind :: FalseEdge { .. }
258
+ | TerminatorKind :: FalseUnwind { .. } => {
259
+ // These terminators have no effect on the analysis.
260
+ }
261
+ }
262
+ terminator. edges ( )
263
+ }
264
+
265
+ fn handle_call_return (
266
+ & self ,
267
+ return_places : CallReturnPlaces < ' _ , ' tcx > ,
268
+ state : & mut State < FlatSet < Scalar > > ,
269
+ ) {
270
+ return_places. for_each ( |place| {
271
+ state. flood ( place. as_ref ( ) , & self . map ) ;
272
+ } )
87
273
}
88
274
89
275
fn handle_set_discriminant (
90
276
& self ,
91
277
place : Place < ' tcx > ,
92
278
variant_index : VariantIdx ,
93
- state : & mut State < Self :: Value > ,
279
+ state : & mut State < FlatSet < Scalar > > ,
94
280
) {
95
281
state. flood_discr ( place. as_ref ( ) , & self . map ) ;
96
282
if self . map . find_discr ( place. as_ref ( ) ) . is_some ( ) {
@@ -109,27 +295,27 @@ impl<'tcx> ValueAnalysis<'tcx> for ConstAnalysis<'_, 'tcx> {
109
295
& self ,
110
296
target : Place < ' tcx > ,
111
297
rvalue : & Rvalue < ' tcx > ,
112
- state : & mut State < Self :: Value > ,
298
+ state : & mut State < FlatSet < Scalar > > ,
113
299
) {
114
300
match rvalue {
115
301
Rvalue :: Use ( operand) => {
116
- state. flood ( target. as_ref ( ) , self . map ( ) ) ;
302
+ state. flood ( target. as_ref ( ) , & self . map ) ;
117
303
if let Some ( target) = self . map . find ( target. as_ref ( ) ) {
118
304
self . assign_operand ( state, target, operand) ;
119
305
}
120
306
}
121
307
Rvalue :: CopyForDeref ( rhs) => {
122
- state. flood ( target. as_ref ( ) , self . map ( ) ) ;
308
+ state. flood ( target. as_ref ( ) , & self . map ) ;
123
309
if let Some ( target) = self . map . find ( target. as_ref ( ) ) {
124
310
self . assign_operand ( state, target, & Operand :: Copy ( * rhs) ) ;
125
311
}
126
312
}
127
313
Rvalue :: Aggregate ( kind, operands) => {
128
314
// If we assign `target = Enum::Variant#0(operand)`,
129
315
// we must make sure that all `target as Variant#i` are `Top`.
130
- state. flood ( target. as_ref ( ) , self . map ( ) ) ;
316
+ state. flood ( target. as_ref ( ) , & self . map ) ;
131
317
132
- let Some ( target_idx) = self . map ( ) . find ( target. as_ref ( ) ) else { return } ;
318
+ let Some ( target_idx) = self . map . find ( target. as_ref ( ) ) else { return } ;
133
319
134
320
let ( variant_target, variant_index) = match * * kind {
135
321
AggregateKind :: Tuple | AggregateKind :: Closure ( ..) => ( Some ( target_idx) , None ) ,
@@ -148,14 +334,14 @@ impl<'tcx> ValueAnalysis<'tcx> for ConstAnalysis<'_, 'tcx> {
148
334
if let Some ( variant_target_idx) = variant_target {
149
335
for ( field_index, operand) in operands. iter_enumerated ( ) {
150
336
if let Some ( field) =
151
- self . map ( ) . apply ( variant_target_idx, TrackElem :: Field ( field_index) )
337
+ self . map . apply ( variant_target_idx, TrackElem :: Field ( field_index) )
152
338
{
153
339
self . assign_operand ( state, field, operand) ;
154
340
}
155
341
}
156
342
}
157
343
if let Some ( variant_index) = variant_index
158
- && let Some ( discr_idx) = self . map ( ) . apply ( target_idx, TrackElem :: Discriminant )
344
+ && let Some ( discr_idx) = self . map . apply ( target_idx, TrackElem :: Discriminant )
159
345
{
160
346
// We are assigning the discriminant as part of an aggregate.
161
347
// This discriminant can only alias a variant field's value if the operand
@@ -170,23 +356,23 @@ impl<'tcx> ValueAnalysis<'tcx> for ConstAnalysis<'_, 'tcx> {
170
356
}
171
357
Rvalue :: BinaryOp ( op, box ( left, right) ) if op. is_overflowing ( ) => {
172
358
// Flood everything now, so we can use `insert_value_idx` directly later.
173
- state. flood ( target. as_ref ( ) , self . map ( ) ) ;
359
+ state. flood ( target. as_ref ( ) , & self . map ) ;
174
360
175
- let Some ( target) = self . map ( ) . find ( target. as_ref ( ) ) else { return } ;
361
+ let Some ( target) = self . map . find ( target. as_ref ( ) ) else { return } ;
176
362
177
- let value_target = self . map ( ) . apply ( target, TrackElem :: Field ( 0_u32 . into ( ) ) ) ;
178
- let overflow_target = self . map ( ) . apply ( target, TrackElem :: Field ( 1_u32 . into ( ) ) ) ;
363
+ let value_target = self . map . apply ( target, TrackElem :: Field ( 0_u32 . into ( ) ) ) ;
364
+ let overflow_target = self . map . apply ( target, TrackElem :: Field ( 1_u32 . into ( ) ) ) ;
179
365
180
366
if value_target. is_some ( ) || overflow_target. is_some ( ) {
181
367
let ( val, overflow) = self . binary_op ( state, * op, left, right) ;
182
368
183
369
if let Some ( value_target) = value_target {
184
370
// We have flooded `target` earlier.
185
- state. insert_value_idx ( value_target, val, self . map ( ) ) ;
371
+ state. insert_value_idx ( value_target, val, & self . map ) ;
186
372
}
187
373
if let Some ( overflow_target) = overflow_target {
188
374
// We have flooded `target` earlier.
189
- state. insert_value_idx ( overflow_target, overflow, self . map ( ) ) ;
375
+ state. insert_value_idx ( overflow_target, overflow, & self . map ) ;
190
376
}
191
377
}
192
378
}
@@ -196,27 +382,30 @@ impl<'tcx> ValueAnalysis<'tcx> for ConstAnalysis<'_, 'tcx> {
196
382
_,
197
383
) => {
198
384
let pointer = self . handle_operand ( operand, state) ;
199
- state. assign ( target. as_ref ( ) , pointer, self . map ( ) ) ;
385
+ state. assign ( target. as_ref ( ) , pointer, & self . map ) ;
200
386
201
- if let Some ( target_len) = self . map ( ) . find_len ( target. as_ref ( ) )
387
+ if let Some ( target_len) = self . map . find_len ( target. as_ref ( ) )
202
388
&& let operand_ty = operand. ty ( self . local_decls , self . tcx )
203
389
&& let Some ( operand_ty) = operand_ty. builtin_deref ( true )
204
390
&& let ty:: Array ( _, len) = operand_ty. kind ( )
205
391
&& let Some ( len) = Const :: Ty ( self . tcx . types . usize , * len)
206
392
. try_eval_scalar_int ( self . tcx , self . param_env )
207
393
{
208
- state. insert_value_idx ( target_len, FlatSet :: Elem ( len. into ( ) ) , self . map ( ) ) ;
394
+ state. insert_value_idx ( target_len, FlatSet :: Elem ( len. into ( ) ) , & self . map ) ;
209
395
}
210
396
}
211
- _ => self . super_assign ( target, rvalue, state) ,
397
+ _ => {
398
+ let result = self . handle_rvalue ( rvalue, state) ;
399
+ state. assign ( target. as_ref ( ) , result, & self . map ) ;
400
+ }
212
401
}
213
402
}
214
403
215
404
fn handle_rvalue (
216
405
& self ,
217
406
rvalue : & Rvalue < ' tcx > ,
218
- state : & mut State < Self :: Value > ,
219
- ) -> ValueOrPlace < Self :: Value > {
407
+ state : & mut State < FlatSet < Scalar > > ,
408
+ ) -> ValueOrPlace < FlatSet < Scalar > > {
220
409
let val = match rvalue {
221
410
Rvalue :: Len ( place) => {
222
411
let place_ty = place. ty ( self . local_decls , self . tcx ) ;
@@ -225,7 +414,7 @@ impl<'tcx> ValueAnalysis<'tcx> for ConstAnalysis<'_, 'tcx> {
225
414
. try_eval_scalar ( self . tcx , self . param_env )
226
415
. map_or ( FlatSet :: Top , FlatSet :: Elem )
227
416
} else if let [ ProjectionElem :: Deref ] = place. projection [ ..] {
228
- state. get_len ( place. local . into ( ) , self . map ( ) )
417
+ state. get_len ( place. local . into ( ) , & self . map )
229
418
} else {
230
419
FlatSet :: Top
231
420
}
@@ -296,17 +485,33 @@ impl<'tcx> ValueAnalysis<'tcx> for ConstAnalysis<'_, 'tcx> {
296
485
} ;
297
486
FlatSet :: Elem ( Scalar :: from_target_usize ( val, & self . tcx ) )
298
487
}
299
- Rvalue :: Discriminant ( place) => state. get_discr ( place. as_ref ( ) , self . map ( ) ) ,
300
- _ => return self . super_rvalue ( rvalue, state) ,
488
+ Rvalue :: Discriminant ( place) => state. get_discr ( place. as_ref ( ) , & self . map ) ,
489
+ Rvalue :: Use ( operand) => return self . handle_operand ( operand, state) ,
490
+ Rvalue :: CopyForDeref ( place) => {
491
+ return self . handle_operand ( & Operand :: Copy ( * place) , state) ;
492
+ }
493
+ Rvalue :: Ref ( ..) | Rvalue :: RawPtr ( ..) => {
494
+ // We don't track such places.
495
+ return ValueOrPlace :: TOP ;
496
+ }
497
+ Rvalue :: Repeat ( ..)
498
+ | Rvalue :: ThreadLocalRef ( ..)
499
+ | Rvalue :: Cast ( ..)
500
+ | Rvalue :: BinaryOp ( ..)
501
+ | Rvalue :: Aggregate ( ..)
502
+ | Rvalue :: ShallowInitBox ( ..) => {
503
+ // No modification is possible through these r-values.
504
+ return ValueOrPlace :: TOP ;
505
+ }
301
506
} ;
302
507
ValueOrPlace :: Value ( val)
303
508
}
304
509
305
510
fn handle_constant (
306
511
& self ,
307
512
constant : & ConstOperand < ' tcx > ,
308
- _state : & mut State < Self :: Value > ,
309
- ) -> Self :: Value {
513
+ _state : & mut State < FlatSet < Scalar > > ,
514
+ ) -> FlatSet < Scalar > {
310
515
constant
311
516
. const_
312
517
. try_eval_scalar ( self . tcx , self . param_env )
@@ -317,11 +522,11 @@ impl<'tcx> ValueAnalysis<'tcx> for ConstAnalysis<'_, 'tcx> {
317
522
& self ,
318
523
discr : & ' mir Operand < ' tcx > ,
319
524
targets : & ' mir SwitchTargets ,
320
- state : & mut State < Self :: Value > ,
525
+ state : & mut State < FlatSet < Scalar > > ,
321
526
) -> TerminatorEdges < ' mir , ' tcx > {
322
527
let value = match self . handle_operand ( discr, state) {
323
528
ValueOrPlace :: Value ( value) => value,
324
- ValueOrPlace :: Place ( place) => state. get_idx ( place, self . map ( ) ) ,
529
+ ValueOrPlace :: Place ( place) => state. get_idx ( place, & self . map ) ,
325
530
} ;
326
531
match value {
327
532
// We are branching on uninitialized data, this is UB, treat it as unreachable.
@@ -334,19 +539,6 @@ impl<'tcx> ValueAnalysis<'tcx> for ConstAnalysis<'_, 'tcx> {
334
539
FlatSet :: Top => TerminatorEdges :: SwitchInt { discr, targets } ,
335
540
}
336
541
}
337
- }
338
-
339
- impl < ' a , ' tcx > ConstAnalysis < ' a , ' tcx > {
340
- fn new ( tcx : TyCtxt < ' tcx > , body : & ' a Body < ' tcx > , map : Map < ' tcx > ) -> Self {
341
- let param_env = tcx. param_env_reveal_all_normalized ( body. source . def_id ( ) ) ;
342
- Self {
343
- map,
344
- tcx,
345
- local_decls : & body. local_decls ,
346
- ecx : InterpCx :: new ( tcx, DUMMY_SP , param_env, DummyMachine ) ,
347
- param_env,
348
- }
349
- }
350
542
351
543
/// The caller must have flooded `place`.
352
544
fn assign_operand (
@@ -537,16 +729,40 @@ impl<'a, 'tcx> ConstAnalysis<'a, 'tcx> {
537
729
}
538
730
}
539
731
540
- pub ( crate ) struct Patch < ' tcx > {
732
+ /// This is used to visualize the dataflow analysis.
733
+ impl < ' tcx > DebugWithContext < ConstAnalysis < ' _ , ' tcx > > for State < FlatSet < Scalar > > {
734
+ fn fmt_with ( & self , ctxt : & ConstAnalysis < ' _ , ' tcx > , f : & mut Formatter < ' _ > ) -> std:: fmt:: Result {
735
+ match self {
736
+ State :: Reachable ( values) => debug_with_context ( values, None , & ctxt. map , f) ,
737
+ State :: Unreachable => write ! ( f, "unreachable" ) ,
738
+ }
739
+ }
740
+
741
+ fn fmt_diff_with (
742
+ & self ,
743
+ old : & Self ,
744
+ ctxt : & ConstAnalysis < ' _ , ' tcx > ,
745
+ f : & mut Formatter < ' _ > ,
746
+ ) -> std:: fmt:: Result {
747
+ match ( self , old) {
748
+ ( State :: Reachable ( this) , State :: Reachable ( old) ) => {
749
+ debug_with_context ( this, Some ( old) , & ctxt. map , f)
750
+ }
751
+ _ => Ok ( ( ) ) , // Consider printing something here.
752
+ }
753
+ }
754
+ }
755
+
756
+ struct Patch < ' tcx > {
541
757
tcx : TyCtxt < ' tcx > ,
542
758
543
759
/// For a given MIR location, this stores the values of the operands used by that location. In
544
760
/// particular, this is before the effect, such that the operands of `_1 = _1 + _2` are
545
761
/// properly captured. (This may become UB soon, but it is currently emitted even by safe code.)
546
- pub ( crate ) before_effect : FxHashMap < ( Location , Place < ' tcx > ) , Const < ' tcx > > ,
762
+ before_effect : FxHashMap < ( Location , Place < ' tcx > ) , Const < ' tcx > > ,
547
763
548
764
/// Stores the assigned values for assignments where the Rvalue is constant.
549
- pub ( crate ) assignments : FxHashMap < Location , Const < ' tcx > > ,
765
+ assignments : FxHashMap < Location , Const < ' tcx > > ,
550
766
}
551
767
552
768
impl < ' tcx > Patch < ' tcx > {
@@ -725,16 +941,15 @@ fn try_write_constant<'tcx>(
725
941
interp_ok ( ( ) )
726
942
}
727
943
728
- impl < ' mir , ' tcx >
729
- ResultsVisitor < ' mir , ' tcx , Results < ' tcx , ValueAnalysisWrapper < ConstAnalysis < ' _ , ' tcx > > > >
944
+ impl < ' mir , ' tcx > ResultsVisitor < ' mir , ' tcx , Results < ' tcx , ConstAnalysis < ' _ , ' tcx > > >
730
945
for Collector < ' _ , ' tcx >
731
946
{
732
947
type Domain = State < FlatSet < Scalar > > ;
733
948
734
949
#[ instrument( level = "trace" , skip( self , results, statement) ) ]
735
950
fn visit_statement_before_primary_effect (
736
951
& mut self ,
737
- results : & mut Results < ' tcx , ValueAnalysisWrapper < ConstAnalysis < ' _ , ' tcx > > > ,
952
+ results : & mut Results < ' tcx , ConstAnalysis < ' _ , ' tcx > > ,
738
953
state : & Self :: Domain ,
739
954
statement : & ' mir Statement < ' tcx > ,
740
955
location : Location ,
@@ -744,8 +959,8 @@ impl<'mir, 'tcx>
744
959
OperandCollector {
745
960
state,
746
961
visitor : self ,
747
- ecx : & mut results. analysis . 0 . ecx ,
748
- map : & results. analysis . 0 . map ,
962
+ ecx : & mut results. analysis . ecx ,
963
+ map : & results. analysis . map ,
749
964
}
750
965
. visit_rvalue ( rvalue, location) ;
751
966
}
@@ -756,7 +971,7 @@ impl<'mir, 'tcx>
756
971
#[ instrument( level = "trace" , skip( self , results, statement) ) ]
757
972
fn visit_statement_after_primary_effect (
758
973
& mut self ,
759
- results : & mut Results < ' tcx , ValueAnalysisWrapper < ConstAnalysis < ' _ , ' tcx > > > ,
974
+ results : & mut Results < ' tcx , ConstAnalysis < ' _ , ' tcx > > ,
760
975
state : & Self :: Domain ,
761
976
statement : & ' mir Statement < ' tcx > ,
762
977
location : Location ,
@@ -767,10 +982,10 @@ impl<'mir, 'tcx>
767
982
}
768
983
StatementKind :: Assign ( box ( place, _) ) => {
769
984
if let Some ( value) = self . try_make_constant (
770
- & mut results. analysis . 0 . ecx ,
985
+ & mut results. analysis . ecx ,
771
986
place,
772
987
state,
773
- & results. analysis . 0 . map ,
988
+ & results. analysis . map ,
774
989
) {
775
990
self . patch . assignments . insert ( location, value) ;
776
991
}
@@ -781,16 +996,16 @@ impl<'mir, 'tcx>
781
996
782
997
fn visit_terminator_before_primary_effect (
783
998
& mut self ,
784
- results : & mut Results < ' tcx , ValueAnalysisWrapper < ConstAnalysis < ' _ , ' tcx > > > ,
999
+ results : & mut Results < ' tcx , ConstAnalysis < ' _ , ' tcx > > ,
785
1000
state : & Self :: Domain ,
786
1001
terminator : & ' mir Terminator < ' tcx > ,
787
1002
location : Location ,
788
1003
) {
789
1004
OperandCollector {
790
1005
state,
791
1006
visitor : self ,
792
- ecx : & mut results. analysis . 0 . ecx ,
793
- map : & results. analysis . 0 . map ,
1007
+ ecx : & mut results. analysis . ecx ,
1008
+ map : & results. analysis . map ,
794
1009
}
795
1010
. visit_terminator ( terminator, location) ;
796
1011
}
0 commit comments