mirror of
https://github.com/rust-lang/rust.git
synced 2026-04-26 13:01:27 +03:00
Add a handle_cycle_error query modifier.
This modifier indicates that a query has a custom handler for cycles. That custom handler must be found at `rustc_query_impl::handle_cycle_error::$name`. This eliminates the need for `specialize_query_vtables`, which is the current hack to install custom handlers. It's more lines of code in total, but indicating special treatment of a query via a modifier in `queries.rs` is more consistent with how other aspects of queries are handled.
This commit is contained in:
@@ -142,6 +142,7 @@ struct QueryModifiers {
|
|||||||
desc: Desc,
|
desc: Desc,
|
||||||
eval_always: Option<Ident>,
|
eval_always: Option<Ident>,
|
||||||
feedable: Option<Ident>,
|
feedable: Option<Ident>,
|
||||||
|
handle_cycle_error: Option<Ident>,
|
||||||
no_force: Option<Ident>,
|
no_force: Option<Ident>,
|
||||||
no_hash: Option<Ident>,
|
no_hash: Option<Ident>,
|
||||||
separate_provide_extern: Option<Ident>,
|
separate_provide_extern: Option<Ident>,
|
||||||
@@ -156,6 +157,7 @@ fn parse_query_modifiers(input: ParseStream<'_>) -> Result<QueryModifiers> {
|
|||||||
let mut desc = None;
|
let mut desc = None;
|
||||||
let mut eval_always = None;
|
let mut eval_always = None;
|
||||||
let mut feedable = None;
|
let mut feedable = None;
|
||||||
|
let mut handle_cycle_error = None;
|
||||||
let mut no_force = None;
|
let mut no_force = None;
|
||||||
let mut no_hash = None;
|
let mut no_hash = None;
|
||||||
let mut separate_provide_extern = None;
|
let mut separate_provide_extern = None;
|
||||||
@@ -190,6 +192,8 @@ macro_rules! try_insert {
|
|||||||
try_insert!(eval_always = modifier);
|
try_insert!(eval_always = modifier);
|
||||||
} else if modifier == "feedable" {
|
} else if modifier == "feedable" {
|
||||||
try_insert!(feedable = modifier);
|
try_insert!(feedable = modifier);
|
||||||
|
} else if modifier == "handle_cycle_error" {
|
||||||
|
try_insert!(handle_cycle_error = modifier);
|
||||||
} else if modifier == "no_force" {
|
} else if modifier == "no_force" {
|
||||||
try_insert!(no_force = modifier);
|
try_insert!(no_force = modifier);
|
||||||
} else if modifier == "no_hash" {
|
} else if modifier == "no_hash" {
|
||||||
@@ -211,6 +215,7 @@ macro_rules! try_insert {
|
|||||||
desc,
|
desc,
|
||||||
eval_always,
|
eval_always,
|
||||||
feedable,
|
feedable,
|
||||||
|
handle_cycle_error,
|
||||||
no_force,
|
no_force,
|
||||||
no_hash,
|
no_hash,
|
||||||
separate_provide_extern,
|
separate_provide_extern,
|
||||||
@@ -246,6 +251,7 @@ fn make_modifiers_stream(query: &Query) -> proc_macro2::TokenStream {
|
|||||||
desc,
|
desc,
|
||||||
eval_always,
|
eval_always,
|
||||||
feedable,
|
feedable,
|
||||||
|
handle_cycle_error,
|
||||||
no_force,
|
no_force,
|
||||||
no_hash,
|
no_hash,
|
||||||
separate_provide_extern,
|
separate_provide_extern,
|
||||||
@@ -270,6 +276,7 @@ fn make_modifiers_stream(query: &Query) -> proc_macro2::TokenStream {
|
|||||||
};
|
};
|
||||||
let eval_always = eval_always.is_some();
|
let eval_always = eval_always.is_some();
|
||||||
let feedable = feedable.is_some();
|
let feedable = feedable.is_some();
|
||||||
|
let handle_cycle_error = handle_cycle_error.is_some();
|
||||||
let no_force = no_force.is_some();
|
let no_force = no_force.is_some();
|
||||||
let no_hash = no_hash.is_some();
|
let no_hash = no_hash.is_some();
|
||||||
let returns_error_guaranteed = returns_error_guaranteed(&query.return_ty);
|
let returns_error_guaranteed = returns_error_guaranteed(&query.return_ty);
|
||||||
@@ -290,6 +297,7 @@ fn make_modifiers_stream(query: &Query) -> proc_macro2::TokenStream {
|
|||||||
desc: #desc,
|
desc: #desc,
|
||||||
eval_always: #eval_always,
|
eval_always: #eval_always,
|
||||||
feedable: #feedable,
|
feedable: #feedable,
|
||||||
|
handle_cycle_error: #handle_cycle_error,
|
||||||
no_force: #no_force,
|
no_force: #no_force,
|
||||||
no_hash: #no_hash,
|
no_hash: #no_hash,
|
||||||
returns_error_guaranteed: #returns_error_guaranteed,
|
returns_error_guaranteed: #returns_error_guaranteed,
|
||||||
@@ -358,6 +366,7 @@ macro_rules! doc_link {
|
|||||||
// `desc` is handled above
|
// `desc` is handled above
|
||||||
eval_always,
|
eval_always,
|
||||||
feedable,
|
feedable,
|
||||||
|
handle_cycle_error,
|
||||||
no_force,
|
no_force,
|
||||||
no_hash,
|
no_hash,
|
||||||
separate_provide_extern,
|
separate_provide_extern,
|
||||||
|
|||||||
@@ -583,6 +583,7 @@
|
|||||||
// messages about cycles that then abort.)
|
// messages about cycles that then abort.)
|
||||||
query check_representability(key: LocalDefId) {
|
query check_representability(key: LocalDefId) {
|
||||||
desc { "checking if `{}` is representable", tcx.def_path_str(key) }
|
desc { "checking if `{}` is representable", tcx.def_path_str(key) }
|
||||||
|
handle_cycle_error
|
||||||
// We don't want recursive representability calls to be forced with
|
// We don't want recursive representability calls to be forced with
|
||||||
// incremental compilation because, if a cycle occurs, we need the
|
// incremental compilation because, if a cycle occurs, we need the
|
||||||
// entire cycle to be in memory for diagnostics.
|
// entire cycle to be in memory for diagnostics.
|
||||||
@@ -593,6 +594,7 @@
|
|||||||
/// details, particularly on the modifiers.
|
/// details, particularly on the modifiers.
|
||||||
query check_representability_adt_ty(key: Ty<'tcx>) {
|
query check_representability_adt_ty(key: Ty<'tcx>) {
|
||||||
desc { "checking if `{}` is representable", key }
|
desc { "checking if `{}` is representable", key }
|
||||||
|
handle_cycle_error
|
||||||
no_force
|
no_force
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1032,6 +1034,7 @@
|
|||||||
query variances_of(def_id: DefId) -> &'tcx [ty::Variance] {
|
query variances_of(def_id: DefId) -> &'tcx [ty::Variance] {
|
||||||
desc { "computing the variances of `{}`", tcx.def_path_str(def_id) }
|
desc { "computing the variances of `{}`", tcx.def_path_str(def_id) }
|
||||||
cache_on_disk
|
cache_on_disk
|
||||||
|
handle_cycle_error
|
||||||
separate_provide_extern
|
separate_provide_extern
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1164,6 +1167,7 @@
|
|||||||
query fn_sig(key: DefId) -> ty::EarlyBinder<'tcx, ty::PolyFnSig<'tcx>> {
|
query fn_sig(key: DefId) -> ty::EarlyBinder<'tcx, ty::PolyFnSig<'tcx>> {
|
||||||
desc { "computing function signature of `{}`", tcx.def_path_str(key) }
|
desc { "computing function signature of `{}`", tcx.def_path_str(key) }
|
||||||
cache_on_disk
|
cache_on_disk
|
||||||
|
handle_cycle_error
|
||||||
separate_provide_extern
|
separate_provide_extern
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1756,6 +1760,7 @@
|
|||||||
) -> Result<ty::layout::TyAndLayout<'tcx>, &'tcx ty::layout::LayoutError<'tcx>> {
|
) -> Result<ty::layout::TyAndLayout<'tcx>, &'tcx ty::layout::LayoutError<'tcx>> {
|
||||||
depth_limit
|
depth_limit
|
||||||
desc { "computing layout of `{}`", key.value }
|
desc { "computing layout of `{}`", key.value }
|
||||||
|
handle_cycle_error
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Compute a `FnAbi` suitable for indirect calls, i.e. to `fn` pointers.
|
/// Compute a `FnAbi` suitable for indirect calls, i.e. to `fn` pointers.
|
||||||
|
|||||||
@@ -58,6 +58,14 @@
|
|||||||
/// Generate a `feed` method to set the query's value from another query.
|
/// Generate a `feed` method to set the query's value from another query.
|
||||||
pub(crate) struct feedable;
|
pub(crate) struct feedable;
|
||||||
|
|
||||||
|
/// # `handle_cycle_error` query modifier
|
||||||
|
///
|
||||||
|
/// The default behaviour for a query cycle is to emit a cycle error and halt
|
||||||
|
/// compilation. Queries with this modifier will instead use a custom handler,
|
||||||
|
/// which must be provided at `rustc_query_impl::handle_cycle_error::$name`,
|
||||||
|
/// where `$name` is the query name.
|
||||||
|
pub(crate) struct handle_cycle_error;
|
||||||
|
|
||||||
/// # `no_force` query modifier
|
/// # `no_force` query modifier
|
||||||
///
|
///
|
||||||
/// Dep nodes of queries with this modifier will never be "forced" when trying
|
/// Dep nodes of queries with this modifier will never be "forced" when trying
|
||||||
|
|||||||
@@ -304,6 +304,7 @@ fn $name:ident($($K:tt)*) -> $V:ty
|
|||||||
desc: $desc:expr,
|
desc: $desc:expr,
|
||||||
eval_always: $eval_always:literal,
|
eval_always: $eval_always:literal,
|
||||||
feedable: $feedable:literal,
|
feedable: $feedable:literal,
|
||||||
|
handle_cycle_error: $handle_cycle_error:literal,
|
||||||
no_force: $no_force:literal,
|
no_force: $no_force:literal,
|
||||||
no_hash: $no_hash:literal,
|
no_hash: $no_hash:literal,
|
||||||
returns_error_guaranteed: $returns_error_guaranteed:literal,
|
returns_error_guaranteed: $returns_error_guaranteed:literal,
|
||||||
|
|||||||
@@ -138,6 +138,7 @@ fn $name:ident($K:ty) -> $V:ty
|
|||||||
desc: $desc:expr,
|
desc: $desc:expr,
|
||||||
eval_always: $eval_always:literal,
|
eval_always: $eval_always:literal,
|
||||||
feedable: $feedable:literal,
|
feedable: $feedable:literal,
|
||||||
|
handle_cycle_error: $handle_cycle_error:literal,
|
||||||
no_force: $no_force:literal,
|
no_force: $no_force:literal,
|
||||||
no_hash: $no_hash:literal,
|
no_hash: $no_hash:literal,
|
||||||
returns_error_guaranteed: $returns_error_guaranteed:literal,
|
returns_error_guaranteed: $returns_error_guaranteed:literal,
|
||||||
|
|||||||
@@ -9,48 +9,29 @@
|
|||||||
use rustc_hir as hir;
|
use rustc_hir as hir;
|
||||||
use rustc_hir::def::{DefKind, Res};
|
use rustc_hir::def::{DefKind, Res};
|
||||||
use rustc_middle::bug;
|
use rustc_middle::bug;
|
||||||
use rustc_middle::queries::{QueryVTables, TaggedQueryKey};
|
use rustc_middle::queries::TaggedQueryKey;
|
||||||
use rustc_middle::query::Cycle;
|
use rustc_middle::query::Cycle;
|
||||||
use rustc_middle::query::erase::erase_val;
|
|
||||||
use rustc_middle::ty::{self, Ty, TyCtxt};
|
use rustc_middle::ty::{self, Ty, TyCtxt};
|
||||||
use rustc_span::def_id::{DefId, LocalDefId};
|
use rustc_span::def_id::{DefId, LocalDefId};
|
||||||
use rustc_span::{ErrorGuaranteed, Span};
|
use rustc_span::{ErrorGuaranteed, Span};
|
||||||
|
|
||||||
use crate::job::create_cycle_error;
|
use crate::job::create_cycle_error;
|
||||||
|
|
||||||
pub(crate) fn specialize_query_vtables<'tcx>(vtables: &mut QueryVTables<'tcx>) {
|
// Default cycle handler used for all queries that don't use the `handle_cycle_error` query
|
||||||
vtables.fn_sig.handle_cycle_error_fn = |tcx, key, _, err| {
|
// modifier.
|
||||||
let guar = err.delay_as_bug();
|
|
||||||
erase_val(fn_sig(tcx, key, guar))
|
|
||||||
};
|
|
||||||
|
|
||||||
vtables.check_representability.handle_cycle_error_fn =
|
|
||||||
|tcx, _, cycle, _err| check_representability(tcx, cycle);
|
|
||||||
|
|
||||||
vtables.check_representability_adt_ty.handle_cycle_error_fn =
|
|
||||||
|tcx, _, cycle, _err| check_representability(tcx, cycle);
|
|
||||||
|
|
||||||
vtables.variances_of.handle_cycle_error_fn = |tcx, key, _, err| {
|
|
||||||
let _guar = err.delay_as_bug();
|
|
||||||
erase_val(variances_of(tcx, key))
|
|
||||||
};
|
|
||||||
|
|
||||||
vtables.layout_of.handle_cycle_error_fn = |tcx, _, cycle, err| {
|
|
||||||
let _guar = err.delay_as_bug();
|
|
||||||
erase_val(Err(layout_of(tcx, cycle)))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub(crate) fn default(err: Diag<'_>) -> ! {
|
pub(crate) fn default(err: Diag<'_>) -> ! {
|
||||||
let guar = err.emit();
|
let guar = err.emit();
|
||||||
guar.raise_fatal()
|
guar.raise_fatal()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn fn_sig<'tcx>(
|
pub(crate) fn fn_sig<'tcx>(
|
||||||
tcx: TyCtxt<'tcx>,
|
tcx: TyCtxt<'tcx>,
|
||||||
def_id: DefId,
|
def_id: DefId,
|
||||||
guar: ErrorGuaranteed,
|
_: Cycle<'tcx>,
|
||||||
|
err: Diag<'_>,
|
||||||
) -> ty::EarlyBinder<'tcx, ty::PolyFnSig<'tcx>> {
|
) -> ty::EarlyBinder<'tcx, ty::PolyFnSig<'tcx>> {
|
||||||
|
let guar = err.delay_as_bug();
|
||||||
|
|
||||||
let err = Ty::new_error(tcx, guar);
|
let err = Ty::new_error(tcx, guar);
|
||||||
|
|
||||||
let arity = if let Some(node) = tcx.hir_get_if_local(def_id)
|
let arity = if let Some(node) = tcx.hir_get_if_local(def_id)
|
||||||
@@ -71,7 +52,25 @@ fn fn_sig<'tcx>(
|
|||||||
)))
|
)))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn check_representability<'tcx>(tcx: TyCtxt<'tcx>, cycle: Cycle<'tcx>) -> ! {
|
pub(crate) fn check_representability<'tcx>(
|
||||||
|
tcx: TyCtxt<'tcx>,
|
||||||
|
_key: LocalDefId,
|
||||||
|
cycle: Cycle<'tcx>,
|
||||||
|
_err: Diag<'_>,
|
||||||
|
) {
|
||||||
|
check_representability_inner(tcx, cycle);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn check_representability_adt_ty<'tcx>(
|
||||||
|
tcx: TyCtxt<'tcx>,
|
||||||
|
_key: Ty<'tcx>,
|
||||||
|
cycle: Cycle<'tcx>,
|
||||||
|
_err: Diag<'_>,
|
||||||
|
) {
|
||||||
|
check_representability_inner(tcx, cycle);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn check_representability_inner<'tcx>(tcx: TyCtxt<'tcx>, cycle: Cycle<'tcx>) -> ! {
|
||||||
let mut item_and_field_ids = Vec::new();
|
let mut item_and_field_ids = Vec::new();
|
||||||
let mut representable_ids = FxHashSet::default();
|
let mut representable_ids = FxHashSet::default();
|
||||||
for frame in &cycle.frames {
|
for frame in &cycle.frames {
|
||||||
@@ -102,7 +101,13 @@ fn check_representability<'tcx>(tcx: TyCtxt<'tcx>, cycle: Cycle<'tcx>) -> ! {
|
|||||||
guar.raise_fatal()
|
guar.raise_fatal()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn variances_of<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId) -> &'tcx [ty::Variance] {
|
pub(crate) fn variances_of<'tcx>(
|
||||||
|
tcx: TyCtxt<'tcx>,
|
||||||
|
def_id: DefId,
|
||||||
|
_cycle: Cycle<'tcx>,
|
||||||
|
err: Diag<'_>,
|
||||||
|
) -> &'tcx [ty::Variance] {
|
||||||
|
let _guar = err.delay_as_bug();
|
||||||
let n = tcx.generics_of(def_id).own_params.len();
|
let n = tcx.generics_of(def_id).own_params.len();
|
||||||
tcx.arena.alloc_from_iter(iter::repeat_n(ty::Bivariant, n))
|
tcx.arena.alloc_from_iter(iter::repeat_n(ty::Bivariant, n))
|
||||||
}
|
}
|
||||||
@@ -126,7 +131,13 @@ fn search_for_cycle_permutation<Q, T>(
|
|||||||
otherwise()
|
otherwise()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn layout_of<'tcx>(tcx: TyCtxt<'tcx>, cycle: Cycle<'tcx>) -> &'tcx ty::layout::LayoutError<'tcx> {
|
pub(crate) fn layout_of<'tcx>(
|
||||||
|
tcx: TyCtxt<'tcx>,
|
||||||
|
_key: ty::PseudoCanonicalInput<'tcx, Ty<'tcx>>,
|
||||||
|
cycle: Cycle<'tcx>,
|
||||||
|
err: Diag<'_>,
|
||||||
|
) -> Result<ty::layout::TyAndLayout<'tcx>, &'tcx ty::layout::LayoutError<'tcx>> {
|
||||||
|
let _guar = err.delay_as_bug();
|
||||||
let diag = search_for_cycle_permutation(
|
let diag = search_for_cycle_permutation(
|
||||||
&cycle.frames,
|
&cycle.frames,
|
||||||
|frames| {
|
|frames| {
|
||||||
|
|||||||
@@ -48,11 +48,9 @@ pub fn query_system<'tcx>(
|
|||||||
on_disk_cache: Option<OnDiskCache>,
|
on_disk_cache: Option<OnDiskCache>,
|
||||||
incremental: bool,
|
incremental: bool,
|
||||||
) -> QuerySystem<'tcx> {
|
) -> QuerySystem<'tcx> {
|
||||||
let mut query_vtables = query_impl::make_query_vtables(incremental);
|
|
||||||
handle_cycle_error::specialize_query_vtables(&mut query_vtables);
|
|
||||||
QuerySystem {
|
QuerySystem {
|
||||||
arenas: Default::default(),
|
arenas: Default::default(),
|
||||||
query_vtables,
|
query_vtables: query_impl::make_query_vtables(incremental),
|
||||||
side_effects: Default::default(),
|
side_effects: Default::default(),
|
||||||
on_disk_cache,
|
on_disk_cache,
|
||||||
local_providers,
|
local_providers,
|
||||||
|
|||||||
@@ -22,6 +22,7 @@ fn $name:ident($K:ty) -> $V:ty
|
|||||||
desc: $desc:expr,
|
desc: $desc:expr,
|
||||||
eval_always: $eval_always:literal,
|
eval_always: $eval_always:literal,
|
||||||
feedable: $feedable:literal,
|
feedable: $feedable:literal,
|
||||||
|
handle_cycle_error: $handle_cycle_error:literal,
|
||||||
no_force: $no_force:literal,
|
no_force: $no_force:literal,
|
||||||
no_hash: $no_hash:literal,
|
no_hash: $no_hash:literal,
|
||||||
returns_error_guaranteed: $returns_error_guaranteed:literal,
|
returns_error_guaranteed: $returns_error_guaranteed:literal,
|
||||||
@@ -144,7 +145,6 @@ pub(crate) fn make_query_vtable<'tcx>(incremental: bool)
|
|||||||
-> QueryVTable<'tcx, rustc_middle::queries::$name::Cache<'tcx>>
|
-> QueryVTable<'tcx, rustc_middle::queries::$name::Cache<'tcx>>
|
||||||
{
|
{
|
||||||
use rustc_middle::queries::$name::Value;
|
use rustc_middle::queries::$name::Value;
|
||||||
|
|
||||||
QueryVTable {
|
QueryVTable {
|
||||||
name: stringify!($name),
|
name: stringify!($name),
|
||||||
eval_always: $eval_always,
|
eval_always: $eval_always,
|
||||||
@@ -177,9 +177,13 @@ pub(crate) fn make_query_vtable<'tcx>(incremental: bool)
|
|||||||
#[cfg(not($cache_on_disk))]
|
#[cfg(not($cache_on_disk))]
|
||||||
try_load_from_disk_fn: |_tcx, _key, _prev_index, _index| None,
|
try_load_from_disk_fn: |_tcx, _key, _prev_index, _index| None,
|
||||||
|
|
||||||
// The default just emits `err` and then aborts.
|
#[cfg($handle_cycle_error)]
|
||||||
// `handle_cycle_error::specialize_query_vtables` overwrites this default
|
handle_cycle_error_fn: |tcx, key, cycle, err| {
|
||||||
// for certain queries.
|
use rustc_middle::query::erase::erase_val;
|
||||||
|
|
||||||
|
erase_val($crate::handle_cycle_error::$name(tcx, key, cycle, err))
|
||||||
|
},
|
||||||
|
#[cfg(not($handle_cycle_error))]
|
||||||
handle_cycle_error_fn: |_tcx, _key, _cycle, err| {
|
handle_cycle_error_fn: |_tcx, _key, _cycle, err| {
|
||||||
$crate::handle_cycle_error::default(err)
|
$crate::handle_cycle_error::default(err)
|
||||||
},
|
},
|
||||||
|
|||||||
Reference in New Issue
Block a user