Auto merge of #100748 - SparrowLii:query_depth, r=cjgillot
add `depth_limit` in `QueryVTable` to avoid entering a new tcx in `layout_of` Fixes #49735 Updates #48685 The `layout_of` query needs to check whether it overflows the depth limit, and the current implementation needs to create a new `ImplicitCtxt` inside `layout_of`. However, `start_query` will already create a new `ImplicitCtxt`, so we can check the depth limit in `start_query`. We can tell whether we need to check the depth limit simply by whether the return value of `to_debug_str` of the query is `layout_of`. But I think adding the `depth_limit` field in `QueryVTable` may be more elegant and more scalable.
This commit is contained in:
@@ -1309,6 +1309,7 @@ rustc_queries! {
|
||||
query layout_of(
|
||||
key: ty::ParamEnvAnd<'tcx, Ty<'tcx>>
|
||||
) -> Result<ty::layout::TyAndLayout<'tcx>, ty::layout::LayoutError<'tcx>> {
|
||||
depth_limit
|
||||
desc { "computing layout of `{}`", key.value }
|
||||
remap_env_constness
|
||||
}
|
||||
|
||||
@@ -1857,8 +1857,8 @@ pub mod tls {
|
||||
/// This is updated by `JobOwner::start` in `ty::query::plumbing` when executing a query.
|
||||
pub diagnostics: Option<&'a Lock<ThinVec<Diagnostic>>>,
|
||||
|
||||
/// Used to prevent layout from recursing too deeply.
|
||||
pub layout_depth: usize,
|
||||
/// Used to prevent queries from calling too deeply.
|
||||
pub query_depth: usize,
|
||||
|
||||
/// The current dep graph task. This is used to add dependencies to queries
|
||||
/// when executing them.
|
||||
@@ -1872,7 +1872,7 @@ pub mod tls {
|
||||
tcx,
|
||||
query: None,
|
||||
diagnostics: None,
|
||||
layout_depth: 0,
|
||||
query_depth: 0,
|
||||
task_deps: TaskDepsRef::Ignore,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -229,49 +229,38 @@ fn layout_of<'tcx>(
|
||||
tcx: TyCtxt<'tcx>,
|
||||
query: ty::ParamEnvAnd<'tcx, Ty<'tcx>>,
|
||||
) -> Result<TyAndLayout<'tcx>, LayoutError<'tcx>> {
|
||||
ty::tls::with_related_context(tcx, move |icx| {
|
||||
let (param_env, ty) = query.into_parts();
|
||||
debug!(?ty);
|
||||
let (param_env, ty) = query.into_parts();
|
||||
debug!(?ty);
|
||||
|
||||
if !tcx.recursion_limit().value_within_limit(icx.layout_depth) {
|
||||
tcx.sess.fatal(&format!("overflow representing the type `{}`", ty));
|
||||
let param_env = param_env.with_reveal_all_normalized(tcx);
|
||||
let unnormalized_ty = ty;
|
||||
|
||||
// FIXME: We might want to have two different versions of `layout_of`:
|
||||
// One that can be called after typecheck has completed and can use
|
||||
// `normalize_erasing_regions` here and another one that can be called
|
||||
// before typecheck has completed and uses `try_normalize_erasing_regions`.
|
||||
let ty = match tcx.try_normalize_erasing_regions(param_env, ty) {
|
||||
Ok(t) => t,
|
||||
Err(normalization_error) => {
|
||||
return Err(LayoutError::NormalizationFailure(ty, normalization_error));
|
||||
}
|
||||
};
|
||||
|
||||
// Update the ImplicitCtxt to increase the layout_depth
|
||||
let icx = ty::tls::ImplicitCtxt { layout_depth: icx.layout_depth + 1, ..icx.clone() };
|
||||
if ty != unnormalized_ty {
|
||||
// Ensure this layout is also cached for the normalized type.
|
||||
return tcx.layout_of(param_env.and(ty));
|
||||
}
|
||||
|
||||
ty::tls::enter_context(&icx, |_| {
|
||||
let param_env = param_env.with_reveal_all_normalized(tcx);
|
||||
let unnormalized_ty = ty;
|
||||
let cx = LayoutCx { tcx, param_env };
|
||||
|
||||
// FIXME: We might want to have two different versions of `layout_of`:
|
||||
// One that can be called after typecheck has completed and can use
|
||||
// `normalize_erasing_regions` here and another one that can be called
|
||||
// before typecheck has completed and uses `try_normalize_erasing_regions`.
|
||||
let ty = match tcx.try_normalize_erasing_regions(param_env, ty) {
|
||||
Ok(t) => t,
|
||||
Err(normalization_error) => {
|
||||
return Err(LayoutError::NormalizationFailure(ty, normalization_error));
|
||||
}
|
||||
};
|
||||
let layout = cx.layout_of_uncached(ty)?;
|
||||
let layout = TyAndLayout { ty, layout };
|
||||
|
||||
if ty != unnormalized_ty {
|
||||
// Ensure this layout is also cached for the normalized type.
|
||||
return tcx.layout_of(param_env.and(ty));
|
||||
}
|
||||
cx.record_layout_for_printing(layout);
|
||||
|
||||
let cx = LayoutCx { tcx, param_env };
|
||||
sanity_check_layout(&cx, &layout);
|
||||
|
||||
let layout = cx.layout_of_uncached(ty)?;
|
||||
let layout = TyAndLayout { ty, layout };
|
||||
|
||||
cx.record_layout_for_printing(layout);
|
||||
|
||||
sanity_check_layout(&cx, &layout);
|
||||
|
||||
Ok(layout)
|
||||
})
|
||||
})
|
||||
Ok(layout)
|
||||
}
|
||||
|
||||
pub struct LayoutCx<'tcx, C> {
|
||||
|
||||
Reference in New Issue
Block a user