Skip to content

Commit 5952d71

Browse files
committed
Restrict query recursion in needs_significant_drop
Overly aggressive use of the query system to improve caching lead to query cycles and consequently ICEs. This patch fixes this by restricting the use of the query system as a cache to those cases where it is definitely correct.
1 parent 9ecd75b commit 5952d71

File tree

2 files changed

+31
-19
lines changed

2 files changed

+31
-19
lines changed

Diff for: compiler/rustc_ty_utils/src/needs_drop.rs

+17-19
Original file line numberDiff line numberDiff line change
@@ -199,16 +199,11 @@ fn drop_tys_helper<'tcx>(
199199
fn with_query_cache<'tcx>(
200200
tcx: TyCtxt<'tcx>,
201201
iter: impl IntoIterator<Item = Ty<'tcx>>,
202-
only_significant: bool,
203202
) -> NeedsDropResult<Vec<Ty<'tcx>>> {
204203
iter.into_iter().try_fold(Vec::new(), |mut vec, subty| {
205204
match subty.kind() {
206205
ty::Adt(adt_id, subst) => {
207-
for subty in if only_significant {
208-
tcx.adt_significant_drop_tys(adt_id.did)?
209-
} else {
210-
tcx.adt_drop_tys(adt_id.did)?
211-
} {
206+
for subty in tcx.adt_drop_tys(adt_id.did)? {
212207
vec.push(subty.subst(tcx, subst));
213208
}
214209
}
@@ -234,25 +229,28 @@ fn drop_tys_helper<'tcx>(
234229
// Since the destructor is insignificant, we just want to make sure all of
235230
// the passed in type parameters are also insignificant.
236231
// Eg: Vec<T> dtor is insignificant when T=i32 but significant when T=Mutex.
237-
with_query_cache(tcx, substs.types(), only_significant)
232+
Ok(substs.types().collect())
238233
}
239234
}
240235
} else if adt_def.is_union() {
241236
debug!("drop_tys_helper: `{:?}` is a union", adt_def);
242237
Ok(Vec::new())
243238
} else {
244-
with_query_cache(
245-
tcx,
246-
adt_def.all_fields().map(|field| {
247-
let r = tcx.type_of(field.did).subst(tcx, substs);
248-
debug!(
249-
"drop_tys_helper: Subst into {:?} with {:?} gettng {:?}",
250-
field, substs, r
251-
);
252-
r
253-
}),
254-
only_significant,
255-
)
239+
let field_tys = adt_def.all_fields().map(|field| {
240+
let r = tcx.type_of(field.did).subst(tcx, substs);
241+
debug!("drop_tys_helper: Subst into {:?} with {:?} gettng {:?}", field, substs, r);
242+
r
243+
});
244+
if only_significant {
245+
// We can't recurse through the query system here because we might induce a cycle
246+
Ok(field_tys.collect())
247+
} else {
248+
// We can use the query system if we consider all drops significant. In that case,
249+
// ADTs are `needs_drop` exactly if they `impl Drop` or if any of their "transitive"
250+
// fields do. There can be no cycles here, because ADTs cannot contain themselves as
251+
// fields.
252+
with_query_cache(tcx, field_tys)
253+
}
256254
}
257255
.map(|v| v.into_iter())
258256
};
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
// ICEs if checking if there is a significant destructor causes a query cycle
2+
// check-pass
3+
4+
#![warn(rust_2021_incompatible_closure_captures)]
5+
pub struct Foo(Bar);
6+
pub struct Bar(Baz);
7+
pub struct Baz(Vec<Foo>);
8+
9+
impl Foo {
10+
pub fn baz(self, v: Baz) -> Baz {
11+
(|| v)()
12+
}
13+
}
14+
fn main() {}

0 commit comments

Comments
 (0)