@@ -7,6 +7,9 @@ use rustc_middle::mir::*;
77use rustc_middle:: ty:: { self , subst:: SubstsRef , AdtDef , Ty } ;
88use rustc_span:: DUMMY_SP ;
99use rustc_trait_selection:: traits;
10+ use rustc_index:: vec:: IndexVec ;
11+ use rustc_index:: bit_set:: BitSet ;
12+ use crate :: dataflow:: JoinSemiLattice ;
1013
1114use super :: ConstCx ;
1215
@@ -16,9 +19,9 @@ pub fn in_any_value_of_ty(
1619 error_occured : Option < ErrorReported > ,
1720) -> ConstQualifs {
1821 ConstQualifs {
19- has_mut_interior : HasMutInterior :: in_any_value_of_ty ( cx, ty) ,
20- needs_drop : NeedsDrop :: in_any_value_of_ty ( cx, ty) ,
21- custom_eq : CustomEq :: in_any_value_of_ty ( cx, ty) ,
22+ has_mut_interior : HasMutInterior :: in_any_value_of_ty ( cx, ty) . is_some ( ) ,
23+ needs_drop : NeedsDrop :: in_any_value_of_ty ( cx, ty) . is_some ( ) ,
24+ custom_eq : CustomEq :: in_any_value_of_ty ( cx, ty) . is_some ( ) ,
2225 error_occured,
2326 }
2427}
@@ -34,15 +37,21 @@ pub fn in_any_value_of_ty(
3437/// To accomplish this, const-checking and promotion use a value-based analysis (as opposed to a
3538/// type-based one). Qualifications propagate structurally across variables: If a local (or a
3639/// projection of a local) is assigned a qualifed value, that local itself becomes qualifed.
37- pub trait Qualif {
40+ pub ( crate ) trait Qualif {
3841 /// The name of the file used to debug the dataflow analysis that computes this qualif.
3942 const ANALYSIS_NAME : & ' static str ;
4043
44+ /// The dataflow result type. If it's just qualified/not qualified, then
45+ /// you can just use a `()` (most qualifs do that). But if you need more state, use a
46+ /// custom enum.
47+ type Result : SetChoice = ( ) ;
48+ type Set : QualifsPerLocal < Self :: Result > = <Self :: Result as SetChoice >:: Set ;
49+
4150 /// Whether this `Qualif` is cleared when a local is moved from.
4251 const IS_CLEARED_ON_MOVE : bool = false ;
4352
4453 /// Extracts the field of `ConstQualifs` that corresponds to this `Qualif`.
45- fn in_qualifs ( qualifs : & ConstQualifs ) -> bool ;
54+ fn in_qualifs ( qualifs : & ConstQualifs ) -> Option < Self :: Result > ;
4655
4756 /// Returns `true` if *any* value of the given type could possibly have this `Qualif`.
4857 ///
@@ -51,7 +60,7 @@ pub trait Qualif {
5160 /// from a call to another function.
5261 ///
5362 /// It also determines the `Qualif`s for primitive types.
54- fn in_any_value_of_ty ( cx : & ConstCx < ' _ , ' tcx > , ty : Ty < ' tcx > ) -> bool ;
63+ fn in_any_value_of_ty ( cx : & ConstCx < ' _ , ' tcx > , ty : Ty < ' tcx > ) -> Option < Self :: Result > ;
5564
5665 /// Returns `true` if this `Qualif` is inherent to the given struct or enum.
5766 ///
@@ -65,7 +74,61 @@ pub trait Qualif {
6574 cx : & ConstCx < ' _ , ' tcx > ,
6675 adt : & ' tcx AdtDef ,
6776 substs : SubstsRef < ' tcx > ,
68- ) -> bool ;
77+ ) -> Option < Self :: Result > ;
78+ }
79+
80+ pub ( crate ) trait SetChoice : Sized + Clone + JoinSemiLattice {
81+ type Set : QualifsPerLocal < Self > = IndexVec < Local , Option < Self > > ;
82+ }
83+
84+ impl SetChoice for ( ) {
85+ type Set = BitSet < Local > ;
86+ }
87+
88+ pub ( crate ) trait QualifsPerLocal < Value > : Sized + Clone + JoinSemiLattice {
89+ fn new_empty ( n : usize ) -> Self ;
90+ fn insert ( & mut self , local : Local , val : Value ) ;
91+ fn remove ( & mut self , local : Local ) ;
92+ fn clear ( & mut self ) ;
93+ fn get ( & self , local : Local ) -> Option < Value > ;
94+ }
95+
96+ impl QualifsPerLocal < ( ) > for BitSet < Local > {
97+ fn new_empty ( n : usize ) -> Self {
98+ BitSet :: new_empty ( n)
99+ }
100+ fn insert ( & mut self , local : Local , _: ( ) ) {
101+ BitSet :: insert ( self , local) ;
102+ }
103+ fn remove ( & mut self , local : Local ) {
104+ BitSet :: remove ( self , local) ;
105+ }
106+ fn clear ( & mut self ) {
107+ BitSet :: clear ( self )
108+ }
109+ fn get ( & self , local : Local ) -> Option < ( ) > {
110+ self . contains ( local) . then_some ( ( ) )
111+ }
112+ }
113+
114+ impl < T : Clone + Eq + JoinSemiLattice > QualifsPerLocal < T > for IndexVec < Local , Option < T > > {
115+ fn new_empty ( n : usize ) -> Self {
116+ IndexVec :: from_elem_n ( None , n)
117+ }
118+ fn insert ( & mut self , local : Local , val : T ) {
119+ self [ local] = Some ( val) ;
120+ }
121+ fn remove ( & mut self , local : Local ) {
122+ self [ local] = None ;
123+ }
124+ fn clear ( & mut self ) {
125+ for elem in self . iter_mut ( ) {
126+ * elem = None ;
127+ }
128+ }
129+ fn get ( & self , local : Local ) -> Option < T > {
130+ self [ local] . clone ( )
131+ }
69132}
70133
71134/// Constant containing interior mutability (`UnsafeCell<T>`).
@@ -78,18 +141,18 @@ pub struct HasMutInterior;
78141impl Qualif for HasMutInterior {
79142 const ANALYSIS_NAME : & ' static str = "flow_has_mut_interior" ;
80143
81- fn in_qualifs ( qualifs : & ConstQualifs ) -> bool {
82- qualifs. has_mut_interior
144+ fn in_qualifs ( qualifs : & ConstQualifs ) -> Option < ( ) > {
145+ qualifs. has_mut_interior . then_some ( ( ) )
83146 }
84147
85- fn in_any_value_of_ty ( cx : & ConstCx < ' _ , ' tcx > , ty : Ty < ' tcx > ) -> bool {
86- !ty. is_freeze ( cx. tcx . at ( DUMMY_SP ) , cx. param_env )
148+ fn in_any_value_of_ty ( cx : & ConstCx < ' _ , ' tcx > , ty : Ty < ' tcx > ) -> Option < ( ) > {
149+ ( !ty. is_freeze ( cx. tcx . at ( DUMMY_SP ) , cx. param_env ) ) . then_some ( ( ) )
87150 }
88151
89- fn in_adt_inherently ( cx : & ConstCx < ' _ , ' tcx > , adt : & ' tcx AdtDef , _: SubstsRef < ' tcx > ) -> bool {
152+ fn in_adt_inherently ( cx : & ConstCx < ' _ , ' tcx > , adt : & ' tcx AdtDef , _: SubstsRef < ' tcx > ) -> Option < ( ) > {
90153 // Exactly one type, `UnsafeCell`, has the `HasMutInterior` qualif inherently.
91154 // It arises structurally for all other types.
92- Some ( adt. did ) == cx. tcx . lang_items ( ) . unsafe_cell_type ( )
155+ ( Some ( adt. did ) == cx. tcx . lang_items ( ) . unsafe_cell_type ( ) ) . then_some ( ( ) )
93156 }
94157}
95158
@@ -103,16 +166,16 @@ impl Qualif for NeedsDrop {
103166 const ANALYSIS_NAME : & ' static str = "flow_needs_drop" ;
104167 const IS_CLEARED_ON_MOVE : bool = true ;
105168
106- fn in_qualifs ( qualifs : & ConstQualifs ) -> bool {
107- qualifs. needs_drop
169+ fn in_qualifs ( qualifs : & ConstQualifs ) -> Option < ( ) > {
170+ qualifs. needs_drop . then_some ( ( ) )
108171 }
109172
110- fn in_any_value_of_ty ( cx : & ConstCx < ' _ , ' tcx > , ty : Ty < ' tcx > ) -> bool {
111- ty. needs_drop ( cx. tcx , cx. param_env )
173+ fn in_any_value_of_ty ( cx : & ConstCx < ' _ , ' tcx > , ty : Ty < ' tcx > ) -> Option < ( ) > {
174+ ty. needs_drop ( cx. tcx , cx. param_env ) . then_some ( ( ) )
112175 }
113176
114- fn in_adt_inherently ( cx : & ConstCx < ' _ , ' tcx > , adt : & ' tcx AdtDef , _: SubstsRef < ' tcx > ) -> bool {
115- adt. has_dtor ( cx. tcx )
177+ fn in_adt_inherently ( cx : & ConstCx < ' _ , ' tcx > , adt : & ' tcx AdtDef , _: SubstsRef < ' tcx > ) -> Option < ( ) > {
178+ adt. has_dtor ( cx. tcx ) . then_some ( ( ) )
116179 }
117180}
118181
@@ -122,37 +185,37 @@ pub struct CustomEq;
122185impl Qualif for CustomEq {
123186 const ANALYSIS_NAME : & ' static str = "flow_custom_eq" ;
124187
125- fn in_qualifs ( qualifs : & ConstQualifs ) -> bool {
126- qualifs. custom_eq
188+ fn in_qualifs ( qualifs : & ConstQualifs ) -> Option < ( ) > {
189+ qualifs. custom_eq . then_some ( ( ) )
127190 }
128191
129- fn in_any_value_of_ty ( cx : & ConstCx < ' _ , ' tcx > , ty : Ty < ' tcx > ) -> bool {
192+ fn in_any_value_of_ty ( cx : & ConstCx < ' _ , ' tcx > , ty : Ty < ' tcx > ) -> Option < ( ) > {
130193 // If *any* component of a composite data type does not implement `Structural{Partial,}Eq`,
131194 // we know that at least some values of that type are not structural-match. I say "some"
132195 // because that component may be part of an enum variant (e.g.,
133196 // `Option::<NonStructuralMatchTy>::Some`), in which case some values of this type may be
134197 // structural-match (`Option::None`).
135198 let id = cx. tcx . hir ( ) . local_def_id_to_hir_id ( cx. def_id ( ) ) ;
136- traits:: search_for_structural_match_violation ( id, cx. body . span , cx. tcx , ty) . is_some ( )
199+ traits:: search_for_structural_match_violation ( id, cx. body . span , cx. tcx , ty) . map ( drop )
137200 }
138201
139202 fn in_adt_inherently (
140203 cx : & ConstCx < ' _ , ' tcx > ,
141204 adt : & ' tcx AdtDef ,
142205 substs : SubstsRef < ' tcx > ,
143- ) -> bool {
206+ ) -> Option < ( ) > {
144207 let ty = cx. tcx . mk_ty ( ty:: Adt ( adt, substs) ) ;
145- !ty. is_structural_eq_shallow ( cx. tcx )
208+ ( !ty. is_structural_eq_shallow ( cx. tcx ) ) . then_some ( ( ) )
146209 }
147210}
148211
149212// FIXME: Use `mir::visit::Visitor` for the `in_*` functions if/when it supports early return.
150213
151214/// Returns `true` if this `Rvalue` contains qualif `Q`.
152- pub fn in_rvalue < Q , F > ( cx : & ConstCx < ' _ , ' tcx > , in_local : & mut F , rvalue : & Rvalue < ' tcx > ) -> bool
215+ pub ( crate ) fn in_rvalue < Q , F > ( cx : & ConstCx < ' _ , ' tcx > , in_local : & mut F , rvalue : & Rvalue < ' tcx > ) -> Option < Q :: Result >
153216where
154217 Q : Qualif ,
155- F : FnMut ( Local ) -> bool ,
218+ F : FnMut ( Local ) -> Option < Q :: Result > ,
156219{
157220 match rvalue {
158221 Rvalue :: ThreadLocalRef ( _) | Rvalue :: NullaryOp ( ..) => {
@@ -169,7 +232,9 @@ where
169232 | Rvalue :: Cast ( _, operand, _) => in_operand :: < Q , _ > ( cx, in_local, operand) ,
170233
171234 Rvalue :: BinaryOp ( _, lhs, rhs) | Rvalue :: CheckedBinaryOp ( _, lhs, rhs) => {
172- in_operand :: < Q , _ > ( cx, in_local, lhs) || in_operand :: < Q , _ > ( cx, in_local, rhs)
235+ let mut res = in_operand :: < Q , _ > ( cx, in_local, lhs) ;
236+ res. join ( & in_operand :: < Q , _ > ( cx, in_local, rhs) ) ;
237+ res
173238 }
174239
175240 Rvalue :: Ref ( _, _, place) | Rvalue :: AddressOf ( _, place) => {
@@ -189,57 +254,61 @@ where
189254 }
190255
191256 Rvalue :: Aggregate ( kind, operands) => {
192- // Return early if we know that the struct or enum being constructed is always
193- // qualified.
257+ // Check if we know that the struct or enum being constructed is always qualified.
258+ let mut result = None ;
194259 if let AggregateKind :: Adt ( def, _, substs, ..) = * * kind {
195- if Q :: in_adt_inherently ( cx, def, substs) {
196- return true ;
197- }
260+ result. join ( & Q :: in_adt_inherently ( cx, def, substs) ) ;
198261 }
199262
200263 // Otherwise, proceed structurally...
201- operands. iter ( ) . any ( |o| in_operand :: < Q , _ > ( cx, in_local, o) )
264+ for o in operands {
265+ result. join ( & in_operand :: < Q , _ > ( cx, in_local, o) ) ;
266+ }
267+ result
202268 }
203269 }
204270}
205271
206272/// Returns `true` if this `Place` contains qualif `Q`.
207- pub fn in_place < Q , F > ( cx : & ConstCx < ' _ , ' tcx > , in_local : & mut F , place : PlaceRef < ' tcx > ) -> bool
273+ pub ( crate ) fn in_place < Q , F > ( cx : & ConstCx < ' _ , ' tcx > , in_local : & mut F , place : PlaceRef < ' tcx > ) -> Option < Q :: Result >
208274where
209275 Q : Qualif ,
210- F : FnMut ( Local ) -> bool ,
276+ F : FnMut ( Local ) -> Option < Q :: Result > ,
211277{
212278 let mut projection = place. projection ;
279+ let mut result = None ;
213280 while let & [ ref proj_base @ .., proj_elem] = projection {
214281 match proj_elem {
215- ProjectionElem :: Index ( index) if in_local ( index) => return true ,
282+ ProjectionElem :: Index ( index) => {
283+ result. join ( & in_local ( index) ) ;
284+ } ,
216285
217286 ProjectionElem :: Deref
218287 | ProjectionElem :: Field ( _, _)
219288 | ProjectionElem :: ConstantIndex { .. }
220289 | ProjectionElem :: Subslice { .. }
221- | ProjectionElem :: Downcast ( _, _)
222- | ProjectionElem :: Index ( _) => { }
290+ | ProjectionElem :: Downcast ( _, _) => { }
223291 }
224292
225293 let base_ty = Place :: ty_from ( place. local , proj_base, cx. body , cx. tcx ) ;
226294 let proj_ty = base_ty. projection_ty ( cx. tcx , proj_elem) . ty ;
227- if ! Q :: in_any_value_of_ty ( cx, proj_ty) {
228- return false ;
295+ if Q :: in_any_value_of_ty ( cx, proj_ty) . is_none ( ) {
296+ return result ;
229297 }
230298
231299 projection = proj_base;
232300 }
233301
234302 assert ! ( projection. is_empty( ) ) ;
235- in_local ( place. local )
303+ result. join ( & in_local ( place. local ) ) ;
304+ result
236305}
237306
238307/// Returns `true` if this `Operand` contains qualif `Q`.
239- pub fn in_operand < Q , F > ( cx : & ConstCx < ' _ , ' tcx > , in_local : & mut F , operand : & Operand < ' tcx > ) -> bool
308+ pub ( crate ) fn in_operand < Q , F > ( cx : & ConstCx < ' _ , ' tcx > , in_local : & mut F , operand : & Operand < ' tcx > ) -> Option < Q :: Result >
240309where
241310 Q : Qualif ,
242- F : FnMut ( Local ) -> bool ,
311+ F : FnMut ( Local ) -> Option < Q :: Result > ,
243312{
244313 let constant = match operand {
245314 Operand :: Copy ( place) | Operand :: Move ( place) => {
@@ -260,9 +329,10 @@ where
260329 cx. tcx . at ( constant. span ) . mir_const_qualif ( def. did )
261330 } ;
262331
263- if !Q :: in_qualifs ( & qualifs) {
264- return false ;
265- }
332+ // Since this comes from a constant's qualifs, there can only
333+ // be `Option<()>` style qualifs, so we are allowed to early
334+ // return here and not try to join the results.
335+ Q :: in_qualifs ( & qualifs) ?;
266336
267337 // Just in case the type is more specific than
268338 // the definition, e.g., impl associated const
0 commit comments