1
1
//! Propagates constants for early reporting of statically known
2
2
//! assertion failures
3
3
4
- use std:: cell:: Cell ;
5
-
6
- use rustc_ast:: Mutability ;
7
- use rustc_data_structures:: fx:: FxHashSet ;
4
+ use crate :: const_prop:: ConstPropMachine ;
5
+ use crate :: const_prop:: ConstPropMode ;
6
+ use crate :: MirLint ;
7
+ use rustc_const_eval:: const_eval:: ConstEvalErr ;
8
+ use rustc_const_eval:: interpret:: {
9
+ self , InterpCx , InterpResult , LocalState , LocalValue , MemoryKind , OpTy , Scalar ,
10
+ ScalarMaybeUninit , StackPopCleanup ,
11
+ } ;
8
12
use rustc_hir:: def:: DefKind ;
9
13
use rustc_hir:: HirId ;
10
14
use rustc_index:: bit_set:: BitSet ;
11
15
use rustc_index:: vec:: IndexVec ;
12
16
use rustc_middle:: mir:: visit:: { MutatingUseContext , NonMutatingUseContext , PlaceContext , Visitor } ;
13
17
use rustc_middle:: mir:: {
14
- AssertKind , BasicBlock , BinOp , Body , Constant , ConstantKind , Local , LocalDecl , LocalKind ,
15
- Location , Operand , Place , Rvalue , SourceInfo , SourceScope , SourceScopeData , Statement ,
16
- StatementKind , Terminator , TerminatorKind , UnOp , RETURN_PLACE ,
18
+ AssertKind , BinOp , Body , Constant , ConstantKind , Local , LocalDecl , LocalKind , Location ,
19
+ Operand , Place , Rvalue , SourceInfo , SourceScope , SourceScopeData , Statement , StatementKind ,
20
+ Terminator , TerminatorKind , UnOp , RETURN_PLACE ,
17
21
} ;
18
22
use rustc_middle:: ty:: layout:: { LayoutError , LayoutOf , LayoutOfHelpers , TyAndLayout } ;
19
23
use rustc_middle:: ty:: subst:: { InternalSubsts , Subst } ;
@@ -22,42 +26,15 @@ use rustc_middle::ty::{
22
26
TypeVisitable ,
23
27
} ;
24
28
use rustc_session:: lint;
25
- use rustc_span:: { def_id :: DefId , Span } ;
29
+ use rustc_span:: Span ;
26
30
use rustc_target:: abi:: { HasDataLayout , Size , TargetDataLayout } ;
27
- use rustc_target:: spec:: abi:: Abi as CallAbi ;
28
31
use rustc_trait_selection:: traits;
29
-
30
- use crate :: MirLint ;
31
- use rustc_const_eval:: const_eval:: ConstEvalErr ;
32
- use rustc_const_eval:: interpret:: {
33
- self , compile_time_machine, AllocId , ConstAllocation , Frame , ImmTy , InterpCx , InterpResult ,
34
- LocalState , LocalValue , MemoryKind , OpTy , PlaceTy , Pointer , Scalar , ScalarMaybeUninit ,
35
- StackPopCleanup , StackPopUnwind ,
36
- } ;
32
+ use std:: cell:: Cell ;
37
33
38
34
/// The maximum number of bytes that we'll allocate space for a local or the return value.
39
35
/// Needed for #66397, because otherwise we eval into large places and that can cause OOM or just
40
36
/// Severely regress performance.
41
37
const MAX_ALLOC_LIMIT : u64 = 1024 ;
42
-
43
- /// Macro for machine-specific `InterpError` without allocation.
44
- /// (These will never be shown to the user, but they help diagnose ICEs.)
45
- macro_rules! throw_machine_stop_str {
46
- ( $( $tt: tt) * ) => { {
47
- // We make a new local type for it. The type itself does not carry any information,
48
- // but its vtable (for the `MachineStopType` trait) does.
49
- struct Zst ;
50
- // Printing this type shows the desired string.
51
- impl std:: fmt:: Display for Zst {
52
- fn fmt( & self , f: & mut std:: fmt:: Formatter <' _>) -> std:: fmt:: Result {
53
- write!( f, $( $tt) * )
54
- }
55
- }
56
- impl rustc_middle:: mir:: interpret:: MachineStopType for Zst { }
57
- throw_machine_stop!( Zst )
58
- } } ;
59
- }
60
-
61
38
pub struct ConstProp ;
62
39
63
40
impl < ' tcx > MirLint < ' tcx > for ConstProp {
@@ -151,172 +128,6 @@ impl<'tcx> MirLint<'tcx> for ConstProp {
151
128
}
152
129
}
153
130
154
- struct ConstPropMachine < ' mir , ' tcx > {
155
- /// The virtual call stack.
156
- stack : Vec < Frame < ' mir , ' tcx > > ,
157
- /// `OnlyInsideOwnBlock` locals that were written in the current block get erased at the end.
158
- written_only_inside_own_block_locals : FxHashSet < Local > ,
159
- /// Locals that need to be cleared after every block terminates.
160
- only_propagate_inside_block_locals : BitSet < Local > ,
161
- can_const_prop : IndexVec < Local , ConstPropMode > ,
162
- }
163
-
164
- impl ConstPropMachine < ' _ , ' _ > {
165
- fn new (
166
- only_propagate_inside_block_locals : BitSet < Local > ,
167
- can_const_prop : IndexVec < Local , ConstPropMode > ,
168
- ) -> Self {
169
- Self {
170
- stack : Vec :: new ( ) ,
171
- written_only_inside_own_block_locals : Default :: default ( ) ,
172
- only_propagate_inside_block_locals,
173
- can_const_prop,
174
- }
175
- }
176
- }
177
-
178
- impl < ' mir , ' tcx > interpret:: Machine < ' mir , ' tcx > for ConstPropMachine < ' mir , ' tcx > {
179
- compile_time_machine ! ( <' mir, ' tcx>) ;
180
- const PANIC_ON_ALLOC_FAIL : bool = true ; // all allocations are small (see `MAX_ALLOC_LIMIT`)
181
-
182
- type MemoryKind = !;
183
-
184
- fn load_mir (
185
- _ecx : & InterpCx < ' mir , ' tcx , Self > ,
186
- _instance : ty:: InstanceDef < ' tcx > ,
187
- ) -> InterpResult < ' tcx , & ' tcx Body < ' tcx > > {
188
- throw_machine_stop_str ! ( "calling functions isn't supported in ConstProp" )
189
- }
190
-
191
- fn find_mir_or_eval_fn (
192
- _ecx : & mut InterpCx < ' mir , ' tcx , Self > ,
193
- _instance : ty:: Instance < ' tcx > ,
194
- _abi : CallAbi ,
195
- _args : & [ OpTy < ' tcx > ] ,
196
- _destination : & PlaceTy < ' tcx > ,
197
- _target : Option < BasicBlock > ,
198
- _unwind : StackPopUnwind ,
199
- ) -> InterpResult < ' tcx , Option < ( & ' mir Body < ' tcx > , ty:: Instance < ' tcx > ) > > {
200
- Ok ( None )
201
- }
202
-
203
- fn call_intrinsic (
204
- _ecx : & mut InterpCx < ' mir , ' tcx , Self > ,
205
- _instance : ty:: Instance < ' tcx > ,
206
- _args : & [ OpTy < ' tcx > ] ,
207
- _destination : & PlaceTy < ' tcx > ,
208
- _target : Option < BasicBlock > ,
209
- _unwind : StackPopUnwind ,
210
- ) -> InterpResult < ' tcx > {
211
- throw_machine_stop_str ! ( "calling intrinsics isn't supported in ConstProp" )
212
- }
213
-
214
- fn assert_panic (
215
- _ecx : & mut InterpCx < ' mir , ' tcx , Self > ,
216
- _msg : & rustc_middle:: mir:: AssertMessage < ' tcx > ,
217
- _unwind : Option < rustc_middle:: mir:: BasicBlock > ,
218
- ) -> InterpResult < ' tcx > {
219
- bug ! ( "panics terminators are not evaluated in ConstProp" )
220
- }
221
-
222
- fn binary_ptr_op (
223
- _ecx : & InterpCx < ' mir , ' tcx , Self > ,
224
- _bin_op : BinOp ,
225
- _left : & ImmTy < ' tcx > ,
226
- _right : & ImmTy < ' tcx > ,
227
- ) -> InterpResult < ' tcx , ( Scalar , bool , Ty < ' tcx > ) > {
228
- // We can't do this because aliasing of memory can differ between const eval and llvm
229
- throw_machine_stop_str ! ( "pointer arithmetic or comparisons aren't supported in ConstProp" )
230
- }
231
-
232
- fn access_local < ' a > (
233
- frame : & ' a Frame < ' mir , ' tcx , Self :: Provenance , Self :: FrameExtra > ,
234
- local : Local ,
235
- ) -> InterpResult < ' tcx , & ' a interpret:: Operand < Self :: Provenance > > {
236
- let l = & frame. locals [ local] ;
237
-
238
- if matches ! (
239
- l. value,
240
- LocalValue :: Live ( interpret:: Operand :: Immediate ( interpret:: Immediate :: Uninit ) )
241
- ) {
242
- // For us "uninit" means "we don't know its value, might be initiailized or not".
243
- // So stop here.
244
- throw_machine_stop_str ! ( "tried to access a local with unknown value" )
245
- }
246
-
247
- l. access ( )
248
- }
249
-
250
- fn access_local_mut < ' a > (
251
- ecx : & ' a mut InterpCx < ' mir , ' tcx , Self > ,
252
- frame : usize ,
253
- local : Local ,
254
- ) -> InterpResult < ' tcx , & ' a mut interpret:: Operand < Self :: Provenance > > {
255
- if ecx. machine . can_const_prop [ local] == ConstPropMode :: NoPropagation {
256
- throw_machine_stop_str ! ( "tried to write to a local that is marked as not propagatable" )
257
- }
258
- if frame == 0 && ecx. machine . only_propagate_inside_block_locals . contains ( local) {
259
- trace ! (
260
- "mutating local {:?} which is restricted to its block. \
261
- Will remove it from const-prop after block is finished.",
262
- local
263
- ) ;
264
- ecx. machine . written_only_inside_own_block_locals . insert ( local) ;
265
- }
266
- ecx. machine . stack [ frame] . locals [ local] . access_mut ( )
267
- }
268
-
269
- fn before_access_global (
270
- _tcx : TyCtxt < ' tcx > ,
271
- _machine : & Self ,
272
- _alloc_id : AllocId ,
273
- alloc : ConstAllocation < ' tcx , Self :: Provenance , Self :: AllocExtra > ,
274
- _static_def_id : Option < DefId > ,
275
- is_write : bool ,
276
- ) -> InterpResult < ' tcx > {
277
- if is_write {
278
- throw_machine_stop_str ! ( "can't write to global" ) ;
279
- }
280
- // If the static allocation is mutable, then we can't const prop it as its content
281
- // might be different at runtime.
282
- if alloc. inner ( ) . mutability == Mutability :: Mut {
283
- throw_machine_stop_str ! ( "can't access mutable globals in ConstProp" ) ;
284
- }
285
-
286
- Ok ( ( ) )
287
- }
288
-
289
- #[ inline( always) ]
290
- fn expose_ptr (
291
- _ecx : & mut InterpCx < ' mir , ' tcx , Self > ,
292
- _ptr : Pointer < AllocId > ,
293
- ) -> InterpResult < ' tcx > {
294
- throw_machine_stop_str ! ( "exposing pointers isn't supported in ConstProp" )
295
- }
296
-
297
- #[ inline( always) ]
298
- fn init_frame_extra (
299
- _ecx : & mut InterpCx < ' mir , ' tcx , Self > ,
300
- frame : Frame < ' mir , ' tcx > ,
301
- ) -> InterpResult < ' tcx , Frame < ' mir , ' tcx > > {
302
- Ok ( frame)
303
- }
304
-
305
- #[ inline( always) ]
306
- fn stack < ' a > (
307
- ecx : & ' a InterpCx < ' mir , ' tcx , Self > ,
308
- ) -> & ' a [ Frame < ' mir , ' tcx , Self :: Provenance , Self :: FrameExtra > ] {
309
- & ecx. machine . stack
310
- }
311
-
312
- #[ inline( always) ]
313
- fn stack_mut < ' a > (
314
- ecx : & ' a mut InterpCx < ' mir , ' tcx , Self > ,
315
- ) -> & ' a mut Vec < Frame < ' mir , ' tcx , Self :: Provenance , Self :: FrameExtra > > {
316
- & mut ecx. machine . stack
317
- }
318
- }
319
-
320
131
/// Finds optimization opportunities on the MIR.
321
132
struct ConstPropagator < ' mir , ' tcx > {
322
133
ecx : InterpCx < ' mir , ' tcx , ConstPropMachine < ' mir , ' tcx > > ,
@@ -711,20 +522,6 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> {
711
522
}
712
523
}
713
524
714
- /// The mode that `ConstProp` is allowed to run in for a given `Local`.
715
- #[ derive( Clone , Copy , Debug , PartialEq ) ]
716
- enum ConstPropMode {
717
- /// The `Local` can be propagated into and reads of this `Local` can also be propagated.
718
- FullConstProp ,
719
- /// The `Local` can only be propagated into and from its own block.
720
- OnlyInsideOwnBlock ,
721
- /// The `Local` can be propagated into but reads cannot be propagated.
722
- OnlyPropagateInto ,
723
- /// The `Local` cannot be part of propagation at all. Any statement
724
- /// referencing it either for reading or writing will not get propagated.
725
- NoPropagation ,
726
- }
727
-
728
525
struct CanConstProp {
729
526
can_const_prop : IndexVec < Local , ConstPropMode > ,
730
527
// False at the beginning. Once set, no more assignments are allowed to that local.
0 commit comments