Skip to content

Commit 10cc7a6

Browse files
committed
Auto merge of rust-lang#93449 - JakobDegen:restrict-hasdrop-optimization, r=cjgillot
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. Closes rust-lang#92725 . This is essentially a revert of rust-lang#90845 for the significant drop case only. The general `needs_drop` still does the same thing. The hope is that this is enough to preserve the performance improvements of that PR while fixing the ICE. Should get a perf run to verify that this is the case. cc `@cjgillot`
2 parents 8604ef0 + 5952d71 commit 10cc7a6

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)