@@ -145,11 +145,83 @@ use rustc_data_structures::graph::scc::Sccs;
145
145
use rustc_middle:: mir:: visit:: PlaceContext ;
146
146
use rustc_middle:: mir:: visit:: Visitor ;
147
147
use rustc_middle:: mir:: * ;
148
- use rustc_middle:: ty;
148
+ use rustc_middle:: ty:: TypeVisitable ;
149
+ use rustc_middle:: ty:: { self , TypeSuperVisitable } ;
149
150
150
151
use either:: Either ;
151
152
use std:: cell:: RefCell ;
152
- use std:: ops:: { Deref , DerefMut } ;
153
+ use std:: ops:: { ControlFlow , Deref , DerefMut } ;
154
+
155
+ const DEPTH_LEVEL : u8 = 5 ;
156
+
157
+ /// Checks whether a given type allows for interior mutability
158
+ struct MaybeContainsInteriorMutabilityVisitor < ' tcx > {
159
+ tcx : TyCtxt < ' tcx > ,
160
+ has_interior_mut : bool ,
161
+ reached_depth_limit : bool ,
162
+ current_depth_level : u8 ,
163
+ }
164
+
165
+ impl < ' tcx > MaybeContainsInteriorMutabilityVisitor < ' tcx > {
166
+ fn new ( tcx : TyCtxt < ' tcx > ) -> Self {
167
+ MaybeContainsInteriorMutabilityVisitor {
168
+ tcx,
169
+ has_interior_mut : false ,
170
+ reached_depth_limit : false ,
171
+ current_depth_level : 0 ,
172
+ }
173
+ }
174
+ }
175
+
176
+ impl < ' tcx > ty:: TypeVisitor < TyCtxt < ' tcx > > for MaybeContainsInteriorMutabilityVisitor < ' tcx > {
177
+ type BreakTy = ( ) ;
178
+
179
+ #[ instrument( skip( self ) , level = "debug" ) ]
180
+ fn visit_ty (
181
+ & mut self ,
182
+ t : <TyCtxt < ' tcx > as ty:: Interner >:: Ty ,
183
+ ) -> std:: ops:: ControlFlow < Self :: BreakTy >
184
+ where
185
+ <TyCtxt < ' tcx > as ty:: Interner >:: Ty : ty:: TypeSuperVisitable < TyCtxt < ' tcx > > ,
186
+ {
187
+ self . current_depth_level += 1 ;
188
+ debug ! ( ?self . current_depth_level) ;
189
+ if self . current_depth_level >= DEPTH_LEVEL {
190
+ self . reached_depth_limit = true ;
191
+ return ControlFlow :: Break ( ( ) ) ;
192
+ }
193
+
194
+ let control_flow = match t. kind ( ) {
195
+ ty:: Param ( ..) => {
196
+ // Need to be conservative here
197
+ self . has_interior_mut = true ;
198
+ return ControlFlow :: Break ( ( ) ) ;
199
+ }
200
+ ty:: Adt ( adt_def, substs) => {
201
+ if adt_def. is_unsafe_cell ( ) {
202
+ self . has_interior_mut = true ;
203
+ return ControlFlow :: Break ( ( ) ) ;
204
+ }
205
+
206
+ let mut control_flow = ControlFlow :: Continue ( ( ) ) ;
207
+ for field in adt_def. all_fields ( ) {
208
+ let field_ty = field. ty ( self . tcx , substs) ;
209
+ control_flow = field_ty. visit_with ( self ) ;
210
+
211
+ if control_flow == ControlFlow :: Break ( ( ) ) {
212
+ return ControlFlow :: Break ( ( ) ) ;
213
+ }
214
+ }
215
+
216
+ control_flow
217
+ }
218
+ _ => t. super_visit_with ( self ) ,
219
+ } ;
220
+
221
+ self . current_depth_level -= 1 ;
222
+ control_flow
223
+ }
224
+ }
153
225
154
226
#[ derive( Copy , Clone , Debug ) ]
155
227
enum NodeKind {
0 commit comments