@@ -145,11 +145,83 @@ use rustc_data_structures::graph::scc::Sccs;
145145use rustc_middle:: mir:: visit:: PlaceContext ;
146146use rustc_middle:: mir:: visit:: Visitor ;
147147use rustc_middle:: mir:: * ;
148- use rustc_middle:: ty;
148+ use rustc_middle:: ty:: TypeVisitable ;
149+ use rustc_middle:: ty:: { self , TypeSuperVisitable } ;
149150
150151use either:: Either ;
151152use 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+ }
153225
154226#[ derive( Copy , Clone , Debug ) ]
155227enum NodeKind {
0 commit comments