Skip to content

Commit d16bff4

Browse files
committed
add visitor to detect interior mutability
1 parent b679a03 commit d16bff4

File tree

1 file changed

+74
-2
lines changed

1 file changed

+74
-2
lines changed

compiler/rustc_mir_dataflow/src/impls/live_borrows.rs

Lines changed: 74 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -145,11 +145,83 @@ use rustc_data_structures::graph::scc::Sccs;
145145
use rustc_middle::mir::visit::PlaceContext;
146146
use rustc_middle::mir::visit::Visitor;
147147
use rustc_middle::mir::*;
148-
use rustc_middle::ty;
148+
use rustc_middle::ty::TypeVisitable;
149+
use rustc_middle::ty::{self, TypeSuperVisitable};
149150

150151
use either::Either;
151152
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+
}
153225

154226
#[derive(Copy, Clone, Debug)]
155227
enum NodeKind {

0 commit comments

Comments
 (0)