@@ -9,7 +9,7 @@ use rustc_span::DUMMY_SP;
9
9
use rustc_trait_selection:: traits;
10
10
use rustc_index:: vec:: IndexVec ;
11
11
use rustc_index:: bit_set:: BitSet ;
12
- use crate :: dataflow:: JoinSemiLattice ;
12
+ use crate :: dataflow:: { JoinSemiLattice , fmt :: DebugWithContext } ;
13
13
14
14
use super :: ConstCx ;
15
15
@@ -44,7 +44,7 @@ pub(crate) trait Qualif {
44
44
/// The dataflow result type. If it's just qualified/not qualified, then
45
45
/// you can just use a `()` (most qualifs do that). But if you need more state, use a
46
46
/// custom enum.
47
- type Result : SetChoice = ( ) ;
47
+ type Result : SetChoice + std :: fmt :: Debug = ( ) ;
48
48
type Set : QualifsPerLocal < Self :: Result > = <Self :: Result as SetChoice >:: Set ;
49
49
50
50
/// Whether this `Qualif` is cleared when a local is moved from.
@@ -62,6 +62,12 @@ pub(crate) trait Qualif {
62
62
/// It also determines the `Qualif`s for primitive types.
63
63
fn in_any_value_of_ty ( cx : & ConstCx < ' _ , ' tcx > , ty : Ty < ' tcx > ) -> Option < Self :: Result > ;
64
64
65
+ /// Sometimes const fn calls cannot possibly contain the qualif, so we can treat function
66
+ /// calls special here.
67
+ fn in_any_function_call ( cx : & ConstCx < ' _ , ' tcx > , ty : Ty < ' tcx > , _args : Option < Self :: Result > ) -> Option < Self :: Result > {
68
+ Self :: in_any_value_of_ty ( cx, ty)
69
+ }
70
+
65
71
/// Returns `true` if this `Qualif` is inherent to the given struct or enum.
66
72
///
67
73
/// By default, `Qualif`s propagate into ADTs in a structural way: An ADT only becomes
@@ -75,6 +81,10 @@ pub(crate) trait Qualif {
75
81
adt : & ' tcx AdtDef ,
76
82
substs : SubstsRef < ' tcx > ,
77
83
) -> Option < Self :: Result > ;
84
+
85
+ fn in_value_behind_ref ( qualif : Option < Self :: Result > ) -> Option < Self :: Result > {
86
+ qualif
87
+ }
78
88
}
79
89
80
90
pub ( crate ) trait SetChoice : Sized + Clone + JoinSemiLattice {
@@ -116,7 +126,7 @@ impl<T: Clone + Eq + JoinSemiLattice> QualifsPerLocal<T> for IndexVec<Local, Opt
116
126
IndexVec :: from_elem_n ( None , n)
117
127
}
118
128
fn insert ( & mut self , local : Local , val : T ) {
119
- self [ local] = Some ( val) ;
129
+ self [ local] . join ( & Some ( val) ) ;
120
130
}
121
131
fn remove ( & mut self , local : Local ) {
122
132
self [ local] = None ;
@@ -156,6 +166,66 @@ impl Qualif for HasMutInterior {
156
166
}
157
167
}
158
168
169
+ /// Constant containing interior mutability (`UnsafeCell<T>`) behind a reference.
170
+ /// This must be ruled out to make sure that evaluating the constant at compile-time
171
+ /// and at *any point* during the run-time would produce the same result. In particular,
172
+ /// promotion of temporaries must not change program behavior; if the promoted could be
173
+ /// written to, that would be a problem.
174
+ pub struct HasMutInteriorBehindRef ;
175
+
176
+ #[ derive( Clone , Eq , PartialEq , Debug ) ]
177
+ pub enum HasMutInteriorBehindRefState {
178
+ Yes ,
179
+ /// As long as we haven't encountered a reference yet, we use this state
180
+ /// which is equivalent to the `HasMutInterior` qualif.
181
+ OnlyHasMutInterior ,
182
+ }
183
+ impl SetChoice for HasMutInteriorBehindRefState { }
184
+ impl < C > DebugWithContext < C > for HasMutInteriorBehindRefState { }
185
+
186
+ impl JoinSemiLattice for HasMutInteriorBehindRefState {
187
+ fn join ( & mut self , other : & Self ) -> bool {
188
+ match ( & self , other) {
189
+ ( Self :: Yes , _) => false ,
190
+ ( Self :: OnlyHasMutInterior , Self :: Yes ) => {
191
+ * self = Self :: Yes ;
192
+ true
193
+ } ,
194
+ ( Self :: OnlyHasMutInterior , Self :: OnlyHasMutInterior ) => false ,
195
+ }
196
+ }
197
+ }
198
+
199
+ impl Qualif for HasMutInteriorBehindRef {
200
+ const ANALYSIS_NAME : & ' static str = "flow_has_mut_interior_behind_ref" ;
201
+ type Result = HasMutInteriorBehindRefState ;
202
+
203
+ fn in_qualifs ( qualifs : & ConstQualifs ) -> Option < HasMutInteriorBehindRefState > {
204
+ HasMutInterior :: in_qualifs ( qualifs) . map ( |( ) | HasMutInteriorBehindRefState :: OnlyHasMutInterior )
205
+ }
206
+
207
+ fn in_any_value_of_ty ( cx : & ConstCx < ' _ , ' tcx > , ty : Ty < ' tcx > ) -> Option < HasMutInteriorBehindRefState > {
208
+ match ty. builtin_deref ( false ) {
209
+ None => HasMutInterior :: in_any_value_of_ty ( cx, ty) . map ( |( ) | HasMutInteriorBehindRefState :: OnlyHasMutInterior ) ,
210
+ Some ( tam) => HasMutInterior :: in_any_value_of_ty ( cx, tam. ty ) . map ( |( ) | HasMutInteriorBehindRefState :: Yes ) ,
211
+ }
212
+ }
213
+
214
+ #[ instrument( skip( cx) ) ]
215
+ fn in_any_function_call ( cx : & ConstCx < ' _ , ' tcx > , ty : Ty < ' tcx > , mut args : Option < Self :: Result > ) -> Option < Self :: Result > {
216
+ args. join ( & HasMutInterior :: in_any_value_of_ty ( cx, ty) . map ( |( ) | HasMutInteriorBehindRefState :: OnlyHasMutInterior ) ) ;
217
+ args
218
+ }
219
+
220
+ fn in_adt_inherently ( cx : & ConstCx < ' _ , ' tcx > , adt : & ' tcx AdtDef , substs : SubstsRef < ' tcx > ) -> Option < HasMutInteriorBehindRefState > {
221
+ HasMutInterior :: in_adt_inherently ( cx, adt, substs) . map ( |( ) | HasMutInteriorBehindRefState :: OnlyHasMutInterior )
222
+ }
223
+
224
+ fn in_value_behind_ref ( qualif : Option < HasMutInteriorBehindRefState > ) -> Option < HasMutInteriorBehindRefState > {
225
+ qualif. map ( |_| HasMutInteriorBehindRefState :: Yes )
226
+ }
227
+ }
228
+
159
229
/// Constant containing an ADT that implements `Drop`.
160
230
/// This must be ruled out (a) because we cannot run `Drop` during compile-time
161
231
/// as that might not be a `const fn`, and (b) because implicit promotion would
@@ -212,6 +282,7 @@ impl Qualif for CustomEq {
212
282
// FIXME: Use `mir::visit::Visitor` for the `in_*` functions if/when it supports early return.
213
283
214
284
/// Returns `true` if this `Rvalue` contains qualif `Q`.
285
+ #[ instrument( skip( cx, in_local) , fields( Q =std:: any:: type_name:: <Q >( ) ) ) ]
215
286
pub ( crate ) fn in_rvalue < Q , F > ( cx : & ConstCx < ' _ , ' tcx > , in_local : & mut F , rvalue : & Rvalue < ' tcx > ) -> Option < Q :: Result >
216
287
where
217
288
Q : Qualif ,
@@ -250,7 +321,7 @@ where
250
321
}
251
322
}
252
323
253
- in_place :: < Q , _ > ( cx, in_local, place. as_ref ( ) )
324
+ Q :: in_value_behind_ref ( in_place :: < Q , _ > ( cx, in_local, place. as_ref ( ) ) )
254
325
}
255
326
256
327
Rvalue :: Aggregate ( kind, operands) => {
@@ -270,6 +341,7 @@ where
270
341
}
271
342
272
343
/// Returns `true` if this `Place` contains qualif `Q`.
344
+ #[ instrument( skip( cx, in_local) , fields( Q =std:: any:: type_name:: <Q >( ) ) ) ]
273
345
pub ( crate ) fn in_place < Q , F > ( cx : & ConstCx < ' _ , ' tcx > , in_local : & mut F , place : PlaceRef < ' tcx > ) -> Option < Q :: Result >
274
346
where
275
347
Q : Qualif ,
@@ -305,6 +377,7 @@ where
305
377
}
306
378
307
379
/// Returns `true` if this `Operand` contains qualif `Q`.
380
+ #[ instrument( skip( cx, in_local) , fields( Q =std:: any:: type_name:: <Q >( ) ) ) ]
308
381
pub ( crate ) fn in_operand < Q , F > ( cx : & ConstCx < ' _ , ' tcx > , in_local : & mut F , operand : & Operand < ' tcx > ) -> Option < Q :: Result >
309
382
where
310
383
Q : Qualif ,
0 commit comments