@@ -9,7 +9,7 @@ use rustc_span::DUMMY_SP;
99use rustc_trait_selection:: traits;
1010use rustc_index:: vec:: IndexVec ;
1111use rustc_index:: bit_set:: BitSet ;
12- use crate :: dataflow:: JoinSemiLattice ;
12+ use crate :: dataflow:: { JoinSemiLattice , fmt :: DebugWithContext } ;
1313
1414use super :: ConstCx ;
1515
@@ -44,7 +44,7 @@ pub(crate) trait Qualif {
4444 /// The dataflow result type. If it's just qualified/not qualified, then
4545 /// you can just use a `()` (most qualifs do that). But if you need more state, use a
4646 /// custom enum.
47- type Result : SetChoice = ( ) ;
47+ type Result : SetChoice + std :: fmt :: Debug = ( ) ;
4848 type Set : QualifsPerLocal < Self :: Result > = <Self :: Result as SetChoice >:: Set ;
4949
5050 /// Whether this `Qualif` is cleared when a local is moved from.
@@ -62,6 +62,12 @@ pub(crate) trait Qualif {
6262 /// It also determines the `Qualif`s for primitive types.
6363 fn in_any_value_of_ty ( cx : & ConstCx < ' _ , ' tcx > , ty : Ty < ' tcx > ) -> Option < Self :: Result > ;
6464
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+
6571 /// Returns `true` if this `Qualif` is inherent to the given struct or enum.
6672 ///
6773 /// By default, `Qualif`s propagate into ADTs in a structural way: An ADT only becomes
@@ -75,6 +81,10 @@ pub(crate) trait Qualif {
7581 adt : & ' tcx AdtDef ,
7682 substs : SubstsRef < ' tcx > ,
7783 ) -> Option < Self :: Result > ;
84+
85+ fn in_value_behind_ref ( qualif : Option < Self :: Result > ) -> Option < Self :: Result > {
86+ qualif
87+ }
7888}
7989
8090pub ( crate ) trait SetChoice : Sized + Clone + JoinSemiLattice {
@@ -116,7 +126,7 @@ impl<T: Clone + Eq + JoinSemiLattice> QualifsPerLocal<T> for IndexVec<Local, Opt
116126 IndexVec :: from_elem_n ( None , n)
117127 }
118128 fn insert ( & mut self , local : Local , val : T ) {
119- self [ local] = Some ( val) ;
129+ self [ local] . join ( & Some ( val) ) ;
120130 }
121131 fn remove ( & mut self , local : Local ) {
122132 self [ local] = None ;
@@ -156,6 +166,66 @@ impl Qualif for HasMutInterior {
156166 }
157167}
158168
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+
159229/// Constant containing an ADT that implements `Drop`.
160230/// This must be ruled out (a) because we cannot run `Drop` during compile-time
161231/// as that might not be a `const fn`, and (b) because implicit promotion would
@@ -212,6 +282,7 @@ impl Qualif for CustomEq {
212282// FIXME: Use `mir::visit::Visitor` for the `in_*` functions if/when it supports early return.
213283
214284/// Returns `true` if this `Rvalue` contains qualif `Q`.
285+ #[ instrument( skip( cx, in_local) , fields( Q =std:: any:: type_name:: <Q >( ) ) ) ]
215286pub ( crate ) fn in_rvalue < Q , F > ( cx : & ConstCx < ' _ , ' tcx > , in_local : & mut F , rvalue : & Rvalue < ' tcx > ) -> Option < Q :: Result >
216287where
217288 Q : Qualif ,
@@ -250,7 +321,7 @@ where
250321 }
251322 }
252323
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 ( ) ) )
254325 }
255326
256327 Rvalue :: Aggregate ( kind, operands) => {
@@ -270,6 +341,7 @@ where
270341}
271342
272343/// Returns `true` if this `Place` contains qualif `Q`.
344+ #[ instrument( skip( cx, in_local) , fields( Q =std:: any:: type_name:: <Q >( ) ) ) ]
273345pub ( crate ) fn in_place < Q , F > ( cx : & ConstCx < ' _ , ' tcx > , in_local : & mut F , place : PlaceRef < ' tcx > ) -> Option < Q :: Result >
274346where
275347 Q : Qualif ,
@@ -305,6 +377,7 @@ where
305377}
306378
307379/// Returns `true` if this `Operand` contains qualif `Q`.
380+ #[ instrument( skip( cx, in_local) , fields( Q =std:: any:: type_name:: <Q >( ) ) ) ]
308381pub ( crate ) fn in_operand < Q , F > ( cx : & ConstCx < ' _ , ' tcx > , in_local : & mut F , operand : & Operand < ' tcx > ) -> Option < Q :: Result >
309382where
310383 Q : Qualif ,
0 commit comments