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:
bors
2022-08-25 21:27:38 +00:00
8 changed files with 82 additions and 53 deletions

View File

@@ -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
}

View File

@@ -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,
}
}

View File

@@ -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> {