Skip to content

Commit 1343797

Browse files
Lazily run dataflow for const qualification
1 parent 274c85f commit 1343797

File tree

1 file changed

+56
-43
lines changed

1 file changed

+56
-43
lines changed

src/librustc_mir/transform/check_consts/validation.rs

+56-43
Original file line numberDiff line numberDiff line change
@@ -33,42 +33,72 @@ type IndirectlyMutableResults<'mir, 'tcx> =
3333
type QualifResults<'mir, 'tcx, Q> =
3434
dataflow::ResultsCursor<'mir, 'tcx, FlowSensitiveAnalysis<'mir, 'mir, 'tcx, Q>>;
3535

36+
#[derive(Default)]
3637
pub struct Qualifs<'mir, 'tcx> {
37-
has_mut_interior: QualifResults<'mir, 'tcx, HasMutInterior>,
38-
needs_drop: QualifResults<'mir, 'tcx, NeedsDrop>,
39-
indirectly_mutable: IndirectlyMutableResults<'mir, 'tcx>,
38+
has_mut_interior: Option<QualifResults<'mir, 'tcx, HasMutInterior>>,
39+
needs_drop: Option<QualifResults<'mir, 'tcx, NeedsDrop>>,
40+
indirectly_mutable: Option<IndirectlyMutableResults<'mir, 'tcx>>,
4041
}
4142

4243
impl Qualifs<'mir, 'tcx> {
4344
fn indirectly_mutable(
4445
&mut self,
45-
_: &Item<'mir, 'tcx>,
46+
ccx: &'mir ConstCx<'mir, 'tcx>,
4647
local: Local,
4748
location: Location,
4849
) -> bool {
49-
self.indirectly_mutable.seek_before(location);
50-
self.indirectly_mutable.get().contains(local)
50+
let indirectly_mutable = self.indirectly_mutable.get_or_insert_with(|| {
51+
let ConstCx { tcx, body, def_id, param_env, .. } = *ccx;
52+
53+
// We can use `unsound_ignore_borrow_on_drop` here because custom drop impls are not
54+
// allowed in a const.
55+
//
56+
// FIXME(ecstaticmorse): Someday we want to allow custom drop impls. How do we do this
57+
// without breaking stable code?
58+
MaybeMutBorrowedLocals::mut_borrows_only(tcx, &body, param_env)
59+
.unsound_ignore_borrow_on_drop()
60+
.into_engine(tcx, &body, def_id)
61+
.iterate_to_fixpoint()
62+
.into_results_cursor(&body)
63+
});
64+
65+
indirectly_mutable.seek_before(location);
66+
indirectly_mutable.get().contains(local)
5167
}
5268

5369
/// Returns `true` if `local` is `NeedsDrop` at the given `Location`.
5470
///
5571
/// Only updates the cursor if absolutely necessary
56-
fn needs_drop(&mut self, item: &Item<'mir, 'tcx>, local: Local, location: Location) -> bool {
57-
let ty = item.body.local_decls[local].ty;
58-
if !NeedsDrop::in_any_value_of_ty(item, ty) {
72+
fn needs_drop(
73+
&mut self,
74+
ccx: &'mir ConstCx<'mir, 'tcx>,
75+
local: Local,
76+
location: Location,
77+
) -> bool {
78+
let ty = ccx.body.local_decls[local].ty;
79+
if !NeedsDrop::in_any_value_of_ty(ccx, ty) {
5980
return false;
6081
}
6182

62-
self.needs_drop.seek_before(location);
63-
self.needs_drop.get().contains(local) || self.indirectly_mutable(item, local, location)
83+
let needs_drop = self.needs_drop.get_or_insert_with(|| {
84+
let ConstCx { tcx, body, def_id, .. } = *ccx;
85+
86+
FlowSensitiveAnalysis::new(NeedsDrop, ccx)
87+
.into_engine(tcx, &body, def_id)
88+
.iterate_to_fixpoint()
89+
.into_results_cursor(&body)
90+
});
91+
92+
needs_drop.seek_before(location);
93+
needs_drop.get().contains(local) || self.indirectly_mutable(ccx, local, location)
6494
}
6595

6696
/// Returns `true` if `local` is `HasMutInterior` at the given `Location`.
6797
///
6898
/// Only updates the cursor if absolutely necessary.
6999
fn has_mut_interior(
70100
&mut self,
71-
item: &Item<'mir, 'tcx>,
101+
ccx: &'mir ConstCx<'mir, 'tcx>,
72102
local: Local,
73103
location: Location,
74104
) -> bool {
@@ -77,12 +107,20 @@ impl Qualifs<'mir, 'tcx> {
77107
return false;
78108
}
79109

80-
self.has_mut_interior.seek_before(location);
81-
self.has_mut_interior.get().contains(local)
82-
|| self.indirectly_mutable(item, local, location)
110+
let has_mut_interior = self.has_mut_interior.get_or_insert_with(|| {
111+
let ConstCx { tcx, body, def_id, .. } = *ccx;
112+
113+
FlowSensitiveAnalysis::new(HasMutInterior, ccx)
114+
.into_engine(tcx, &body, def_id)
115+
.iterate_to_fixpoint()
116+
.into_results_cursor(&body)
117+
});
118+
119+
has_mut_interior.seek_before(location);
120+
has_mut_interior.get().contains(local) || self.indirectly_mutable(ccx, local, location)
83121
}
84122

85-
fn in_return_place(&mut self, item: &Item<'mir, 'tcx>) -> ConstQualifs {
123+
fn in_return_place(&mut self, ccx: &'mir ConstCx<'mir, 'tcx>) -> ConstQualifs {
86124
// Find the `Return` terminator if one exists.
87125
//
88126
// If no `Return` terminator exists, this MIR is divergent. Just return the conservative
@@ -128,33 +166,8 @@ impl Deref for Validator<'mir, 'tcx> {
128166
}
129167

130168
impl Validator<'mir, 'tcx> {
131-
pub fn new(item: &'mir Item<'mir, 'tcx>) -> Self {
132-
let Item { tcx, body, def_id, param_env, .. } = *item;
133-
134-
// We can use `unsound_ignore_borrow_on_drop` here because custom drop impls are not
135-
// allowed in a const.
136-
//
137-
// FIXME(ecstaticmorse): Someday we want to allow custom drop impls. How do we do this
138-
// without breaking stable code?
139-
let indirectly_mutable = MaybeMutBorrowedLocals::mut_borrows_only(tcx, body, param_env)
140-
.unsound_ignore_borrow_on_drop()
141-
.into_engine(tcx, body, def_id)
142-
.iterate_to_fixpoint()
143-
.into_results_cursor(body);
144-
145-
let needs_drop = FlowSensitiveAnalysis::new(NeedsDrop, item)
146-
.into_engine(item.tcx, &item.body, item.def_id)
147-
.iterate_to_fixpoint()
148-
.into_results_cursor(*item.body);
149-
150-
let has_mut_interior = FlowSensitiveAnalysis::new(HasMutInterior, item)
151-
.into_engine(item.tcx, &item.body, item.def_id)
152-
.iterate_to_fixpoint()
153-
.into_results_cursor(*item.body);
154-
155-
let qualifs = Qualifs { needs_drop, has_mut_interior, indirectly_mutable };
156-
157-
Validator { span: ccx.body.span, ccx, qualifs }
169+
pub fn new(ccx: &'mir ConstCx<'mir, 'tcx>) -> Self {
170+
Validator { span: ccx.body.span, ccx, qualifs: Default::default() }
158171
}
159172

160173
pub fn check_body(&mut self) {

0 commit comments

Comments
 (0)