Auto merge of #154122 - Zalathar:no-anon, r=nnethercote

Remove the `anon` query modifier



Prior experiments:
- https://github.com/rust-lang/rust/pull/152268
- https://github.com/rust-lang/rust/pull/153996

[Zulip thread: *Removing the `anon` query modifier*](https://rust-lang.zulipchat.com/#narrow/channel/582699-t-compiler.2Fquery-system/topic/Removing.20the.20.60anon.60.20query.20modifier/with/580760962)

---

There are currently three queries that use the `anon` modifier:
- `check_representability`
- `check_representability_adt_ty`
- `erase_and_anonymize_regions_ty`

It seems that none of them are using `anon` in an essential way.

According to comments and tests, the *representability* queries mainly care about not being eligible for forcing (despite having a recoverable key type), so that if a cycle does occur then the entire cycle will be on the query stack. Replacing `anon` with a new `no_force` modifier gives a modest perf improvement.

The `erase_and_anonymize_regions_ty` query appears to be using `anon` to reduce the dep-graph overhead of a query that is expected to not call any other queries (and thus have no dependencies). Replacing `anon` with either `no_hash` or nothing appears to give only a very small perf hit on `cargo` benchmarks, which is justified by the fact that it lets us remove a lot of machinery for anonymous queries.

We still need to retain some of the machinery for anonymous *tasks*, because the non-query task `DepKind::TraitSelect` still uses it.

---

I have some ideas for a follow-up that will reduce dep-graph overhead by replacing *all* zero-dependency nodes with a singleton node, but I want to keep that separate in case it causes unexpected issues and needs to be bisected or reverted.
This commit is contained in:
bors
2026-03-21 21:53:47 +00:00
14 changed files with 64 additions and 83 deletions
@@ -998,7 +998,7 @@ fn check_type_defn<'tcx>(
item: &hir::Item<'tcx>, item: &hir::Item<'tcx>,
all_sized: bool, all_sized: bool,
) -> Result<(), ErrorGuaranteed> { ) -> Result<(), ErrorGuaranteed> {
let _ = tcx.check_representability(item.owner_id.def_id); tcx.ensure_ok().check_representability(item.owner_id.def_id);
let adt_def = tcx.adt_def(item.owner_id); let adt_def = tcx.adt_def(item.owner_id);
enter_wf_checking_ctxt(tcx, item.owner_id.def_id, |wfcx| { enter_wf_checking_ctxt(tcx, item.owner_id.def_id, |wfcx| {
+14 -17
View File
@@ -140,13 +140,13 @@ struct CacheOnDiskIf {
/// See `rustc_middle::query::modifiers` for documentation of each query modifier. /// See `rustc_middle::query::modifiers` for documentation of each query modifier.
struct QueryModifiers { struct QueryModifiers {
// tidy-alphabetical-start // tidy-alphabetical-start
anon: Option<Ident>,
arena_cache: Option<Ident>, arena_cache: Option<Ident>,
cache_on_disk_if: Option<CacheOnDiskIf>, cache_on_disk_if: Option<CacheOnDiskIf>,
depth_limit: Option<Ident>, depth_limit: Option<Ident>,
desc: Desc, desc: Desc,
eval_always: Option<Ident>, eval_always: Option<Ident>,
feedable: Option<Ident>, feedable: Option<Ident>,
no_force: Option<Ident>,
no_hash: Option<Ident>, no_hash: Option<Ident>,
separate_provide_extern: Option<Ident>, separate_provide_extern: Option<Ident>,
// tidy-alphabetical-end // tidy-alphabetical-end
@@ -156,8 +156,8 @@ fn parse_query_modifiers(input: ParseStream<'_>) -> Result<QueryModifiers> {
let mut arena_cache = None; let mut arena_cache = None;
let mut cache_on_disk_if = None; let mut cache_on_disk_if = None;
let mut desc = None; let mut desc = None;
let mut no_force = None;
let mut no_hash = None; let mut no_hash = None;
let mut anon = None;
let mut eval_always = None; let mut eval_always = None;
let mut depth_limit = None; let mut depth_limit = None;
let mut separate_provide_extern = None; let mut separate_provide_extern = None;
@@ -189,10 +189,10 @@ macro_rules! try_insert {
try_insert!(cache_on_disk_if = CacheOnDiskIf { modifier, block }); try_insert!(cache_on_disk_if = CacheOnDiskIf { modifier, block });
} else if modifier == "arena_cache" { } else if modifier == "arena_cache" {
try_insert!(arena_cache = modifier); try_insert!(arena_cache = modifier);
} else if modifier == "no_force" {
try_insert!(no_force = modifier);
} else if modifier == "no_hash" { } else if modifier == "no_hash" {
try_insert!(no_hash = modifier); try_insert!(no_hash = modifier);
} else if modifier == "anon" {
try_insert!(anon = modifier);
} else if modifier == "eval_always" { } else if modifier == "eval_always" {
try_insert!(eval_always = modifier); try_insert!(eval_always = modifier);
} else if modifier == "depth_limit" { } else if modifier == "depth_limit" {
@@ -212,8 +212,8 @@ macro_rules! try_insert {
arena_cache, arena_cache,
cache_on_disk_if, cache_on_disk_if,
desc, desc,
no_force,
no_hash, no_hash,
anon,
eval_always, eval_always,
depth_limit, depth_limit,
separate_provide_extern, separate_provide_extern,
@@ -243,24 +243,24 @@ fn returns_error_guaranteed(ret_ty: &ReturnType) -> bool {
fn make_modifiers_stream(query: &Query) -> proc_macro2::TokenStream { fn make_modifiers_stream(query: &Query) -> proc_macro2::TokenStream {
let QueryModifiers { let QueryModifiers {
// tidy-alphabetical-start // tidy-alphabetical-start
anon,
arena_cache, arena_cache,
cache_on_disk_if, cache_on_disk_if,
depth_limit, depth_limit,
desc: _, desc: _,
eval_always, eval_always,
feedable, feedable,
no_force,
no_hash, no_hash,
separate_provide_extern, separate_provide_extern,
// tidy-alphabetical-end // tidy-alphabetical-end
} = &query.modifiers; } = &query.modifiers;
let anon = anon.is_some();
let arena_cache = arena_cache.is_some(); let arena_cache = arena_cache.is_some();
let cache_on_disk = cache_on_disk_if.is_some(); let cache_on_disk = cache_on_disk_if.is_some();
let depth_limit = depth_limit.is_some(); let depth_limit = depth_limit.is_some();
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 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);
let separate_provide_extern = separate_provide_extern.is_some(); let separate_provide_extern = separate_provide_extern.is_some();
@@ -273,12 +273,12 @@ fn make_modifiers_stream(query: &Query) -> proc_macro2::TokenStream {
query_name_span => query_name_span =>
// Search for (QMODLIST) to find all occurrences of this query modifier list. // Search for (QMODLIST) to find all occurrences of this query modifier list.
// tidy-alphabetical-start // tidy-alphabetical-start
anon: #anon,
arena_cache: #arena_cache, arena_cache: #arena_cache,
cache_on_disk: #cache_on_disk, cache_on_disk: #cache_on_disk,
depth_limit: #depth_limit, depth_limit: #depth_limit,
eval_always: #eval_always, eval_always: #eval_always,
feedable: #feedable, feedable: #feedable,
no_force: #no_force,
no_hash: #no_hash, no_hash: #no_hash,
returns_error_guaranteed: #returns_error_guaranteed, returns_error_guaranteed: #returns_error_guaranteed,
separate_provide_extern: #separate_provide_extern, separate_provide_extern: #separate_provide_extern,
@@ -387,13 +387,15 @@ macro_rules! doc_link {
} }
doc_link!( doc_link!(
// tidy-alphabetical-start
arena_cache, arena_cache,
no_hash,
anon,
eval_always,
depth_limit, depth_limit,
separate_provide_extern, eval_always,
feedable, feedable,
no_force,
no_hash,
separate_provide_extern,
// tidy-alphabetical-end
); );
let name = &query.name; let name = &query.name;
@@ -476,11 +478,6 @@ fn #name(#key_ty) #return_ty
}); });
if let Some(feedable) = &modifiers.feedable { if let Some(feedable) = &modifiers.feedable {
assert!(
modifiers.anon.is_none(),
feedable.span(),
"Query {name} cannot be both `feedable` and `anon`."
);
assert!( assert!(
modifiers.eval_always.is_none(), modifiers.eval_always.is_none(),
feedable.span(), feedable.span(),
@@ -94,10 +94,14 @@ pub const fn as_usize(&self) -> usize {
pub struct DepNode { pub struct DepNode {
pub kind: DepKind, pub kind: DepKind,
/// This is _typically_ a hash of the query key, but sometimes not. /// If `kind` is a query method, then its "key fingerprint" is always a
/// stable hash of the query key.
/// ///
/// For example, `anon` nodes have a fingerprint that is derived from their /// For non-query nodes, the content of this field varies:
/// dependencies instead of a key. /// - Some dep kinds always use a dummy `ZERO` fingerprint.
/// - Some dep kinds use the stable hash of some relevant key-like value.
/// - Some dep kinds use the `with_anon_task` mechanism, and set their key
/// fingerprint to a hash derived from the task's dependencies.
/// ///
/// In some cases the key value can be reconstructed from this fingerprint; /// In some cases the key value can be reconstructed from this fingerprint;
/// see [`KeyFingerprintStyle`]. /// see [`KeyFingerprintStyle`].
+2 -3
View File
@@ -375,9 +375,8 @@ pub fn with_task<'tcx, A: Debug, R>(
/// incorrectly marked green. /// incorrectly marked green.
/// ///
/// FIXME: This could perhaps return a `WithDepNode` to ensure that the /// FIXME: This could perhaps return a `WithDepNode` to ensure that the
/// user of this function actually performs the read; we'll have to see /// user of this function actually performs the read.
/// how to make that work with `anon` in `execute_job_incr`, though. fn with_anon_task_inner<'tcx, OP, R>(
pub fn with_anon_task_inner<'tcx, OP, R>(
&self, &self,
tcx: TyCtxt<'tcx>, tcx: TyCtxt<'tcx>,
dep_kind: DepKind, dep_kind: DepKind,
+6 -11
View File
@@ -585,16 +585,15 @@
desc { "checking if `{}` is representable", tcx.def_path_str(key) } desc { "checking if `{}` is representable", tcx.def_path_str(key) }
// 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. This means we can't // entire cycle to be in memory for diagnostics.
// use `ensure_ok()` with this query. no_force
anon
} }
/// An implementation detail for the `check_representability` query. See that query for more /// An implementation detail for the `check_representability` query. See that query for more
/// 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 }
anon no_force
} }
/// Set of param indexes for type params that are in the type's representation /// Set of param indexes for type params that are in the type's representation
@@ -768,14 +767,10 @@
/// Normally you would just use `tcx.erase_and_anonymize_regions(value)`, /// Normally you would just use `tcx.erase_and_anonymize_regions(value)`,
/// however, which uses this query as a kind of cache. /// however, which uses this query as a kind of cache.
query erase_and_anonymize_regions_ty(ty: Ty<'tcx>) -> Ty<'tcx> { query erase_and_anonymize_regions_ty(ty: Ty<'tcx>) -> Ty<'tcx> {
// This query is not expected to have input -- as a result, it
// is not a good candidates for "replay" because it is essentially a
// pure function of its input (and hence the expectation is that
// no caller would be green **apart** from just these
// queries). Making it anonymous avoids hashing the result, which
// may save a bit of time.
anon
desc { "erasing regions from `{}`", ty } desc { "erasing regions from `{}`", ty }
// Not hashing the return value appears to give marginally better perf for this query,
// which should always be marked green for having no dependencies anyway.
no_hash
} }
query wasm_import_module_map(_: CrateNum) -> &'tcx DefIdMap<String> { query wasm_import_module_map(_: CrateNum) -> &'tcx DefIdMap<String> {
+10 -5
View File
@@ -7,11 +7,6 @@
// tidy-alphabetical-start // tidy-alphabetical-start
// //
/// # `anon` query modifier
///
/// Generate a dep node based not on the query key, but on the query's dependencies.
pub(crate) struct anon;
/// # `arena_cache` query modifier /// # `arena_cache` query modifier
/// ///
/// Query return values must impl `Copy` and be small, but some queries must return values that /// Query return values must impl `Copy` and be small, but some queries must return values that
@@ -59,6 +54,16 @@
/// 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;
/// # `no_force` query modifier
///
/// Dep nodes of queries with this modifier will never be "forced" when trying
/// to mark their dependents green, even if their key is recoverable from the
/// key fingerprint.
///
/// Used by some queries with custom cycle-handlers to ensure that if a cycle
/// occurs, all of the relevant query calls will be on the query stack.
pub(crate) struct no_force;
/// # `no_hash` query modifier /// # `no_hash` query modifier
/// ///
/// Do not hash the query's return value for incremental compilation. If the value needs to be /// Do not hash the query's return value for incremental compilation. If the value needs to be
+1 -3
View File
@@ -77,8 +77,6 @@ pub enum EnsureMode {
pub struct QueryVTable<'tcx, C: QueryCache> { pub struct QueryVTable<'tcx, C: QueryCache> {
pub name: &'static str, pub name: &'static str,
/// True if this query has the `anon` modifier.
pub anon: bool,
/// True if this query has the `eval_always` modifier. /// True if this query has the `eval_always` modifier.
pub eval_always: bool, pub eval_always: bool,
/// True if this query has the `depth_limit` modifier. /// True if this query has the `depth_limit` modifier.
@@ -283,12 +281,12 @@ macro_rules! define_callbacks {
fn $name:ident($($K:tt)*) -> $V:ty fn $name:ident($($K:tt)*) -> $V:ty
{ {
// Search for (QMODLIST) to find all occurrences of this query modifier list. // Search for (QMODLIST) to find all occurrences of this query modifier list.
anon: $anon:literal,
arena_cache: $arena_cache:literal, arena_cache: $arena_cache:literal,
cache_on_disk: $cache_on_disk:literal, cache_on_disk: $cache_on_disk:literal,
depth_limit: $depth_limit:literal, depth_limit: $depth_limit:literal,
eval_always: $eval_always:literal, eval_always: $eval_always:literal,
feedable: $feedable:literal, feedable: $feedable: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,
separate_provide_extern: $separate_provide_extern:literal, separate_provide_extern: $separate_provide_extern:literal,
@@ -61,7 +61,7 @@ pub(crate) fn provide(providers: &mut Providers) {
/// requires calling [`InhabitedPredicate::instantiate`] /// requires calling [`InhabitedPredicate::instantiate`]
fn inhabited_predicate_adt(tcx: TyCtxt<'_>, def_id: DefId) -> InhabitedPredicate<'_> { fn inhabited_predicate_adt(tcx: TyCtxt<'_>, def_id: DefId) -> InhabitedPredicate<'_> {
if let Some(def_id) = def_id.as_local() { if let Some(def_id) = def_id.as_local() {
let _ = tcx.check_representability(def_id); tcx.ensure_ok().check_representability(def_id);
} }
let adt = tcx.adt_def(def_id); let adt = tcx.adt_def(def_id);
@@ -96,30 +96,23 @@ pub(crate) fn Metadata<'tcx>() -> DepKindVTable<'tcx> {
/// Shared implementation of the [`DepKindVTable`] constructor for queries. /// Shared implementation of the [`DepKindVTable`] constructor for queries.
/// Called from macro-generated code for each query. /// Called from macro-generated code for each query.
pub(crate) fn make_dep_kind_vtable_for_query<'tcx, Q>( pub(crate) fn make_dep_kind_vtable_for_query<'tcx, Q>(
is_anon: bool,
is_cache_on_disk: bool, is_cache_on_disk: bool,
is_eval_always: bool, is_eval_always: bool,
is_no_force: bool,
) -> DepKindVTable<'tcx> ) -> DepKindVTable<'tcx>
where where
Q: GetQueryVTable<'tcx>, Q: GetQueryVTable<'tcx>,
{ {
let key_fingerprint_style = if is_anon {
KeyFingerprintStyle::Opaque
} else {
<Q::Cache as QueryCache>::Key::key_fingerprint_style()
};
// A query dep-node can only be forced or promoted if it can recover a key // A query dep-node can only be forced or promoted if it can recover a key
// from its key fingerprint. // from its key fingerprint.
let key_fingerprint_style = <Q::Cache as QueryCache>::Key::key_fingerprint_style();
let can_recover = key_fingerprint_style.is_maybe_recoverable(); let can_recover = key_fingerprint_style.is_maybe_recoverable();
if is_anon {
assert!(!can_recover);
}
DepKindVTable { DepKindVTable {
is_eval_always, is_eval_always,
key_fingerprint_style, key_fingerprint_style,
force_from_dep_node_fn: can_recover.then_some(force_from_dep_node_inner::<Q>), force_from_dep_node_fn: (can_recover && !is_no_force)
.then_some(force_from_dep_node_inner::<Q>),
promote_from_disk_fn: (can_recover && is_cache_on_disk) promote_from_disk_fn: (can_recover && is_cache_on_disk)
.then_some(promote_from_disk_inner::<Q>), .then_some(promote_from_disk_inner::<Q>),
} }
@@ -133,12 +126,12 @@ macro_rules! define_dep_kind_vtables {
fn $name:ident($K:ty) -> $V:ty fn $name:ident($K:ty) -> $V:ty
{ {
// Search for (QMODLIST) to find all occurrences of this query modifier list. // Search for (QMODLIST) to find all occurrences of this query modifier list.
anon: $anon:literal,
arena_cache: $arena_cache:literal, arena_cache: $arena_cache:literal,
cache_on_disk: $cache_on_disk:literal, cache_on_disk: $cache_on_disk:literal,
depth_limit: $depth_limit:literal, depth_limit: $depth_limit:literal,
eval_always: $eval_always:literal, eval_always: $eval_always:literal,
feedable: $feedable:literal, feedable: $feedable: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,
separate_provide_extern: $separate_provide_extern:literal, separate_provide_extern: $separate_provide_extern:literal,
@@ -165,9 +158,9 @@ fn $name:ident($K:ty) -> $V:ty
$crate::dep_kind_vtables::make_dep_kind_vtable_for_query::< $crate::dep_kind_vtables::make_dep_kind_vtable_for_query::<
$crate::query_impl::$name::VTableGetter, $crate::query_impl::$name::VTableGetter,
>( >(
$anon,
$cache_on_disk, $cache_on_disk,
$eval_always, $eval_always,
$no_force,
) )
),* ),*
]; ];
+1 -13
View File
@@ -424,7 +424,7 @@ fn execute_job_incr<'tcx, C: QueryCache>(
let dep_graph_data = let dep_graph_data =
tcx.dep_graph.data().expect("should always be present in incremental mode"); tcx.dep_graph.data().expect("should always be present in incremental mode");
if !query.anon && !query.eval_always { if !query.eval_always {
// `to_dep_node` is expensive for some `DepKind`s. // `to_dep_node` is expensive for some `DepKind`s.
let dep_node = let dep_node =
dep_node_opt.get_or_insert_with(|| DepNode::construct(tcx, query.dep_kind, &key)); dep_node_opt.get_or_insert_with(|| DepNode::construct(tcx, query.dep_kind, &key));
@@ -451,13 +451,6 @@ fn execute_job_incr<'tcx, C: QueryCache>(
let prof_timer = tcx.prof.query_provider(); let prof_timer = tcx.prof.query_provider();
let (result, dep_node_index) = start_query(job_id, query.depth_limit, || { let (result, dep_node_index) = start_query(job_id, query.depth_limit, || {
if query.anon {
// Call the query provider inside an anon task.
return dep_graph_data.with_anon_task_inner(tcx, query.dep_kind, || {
(query.invoke_provider_fn)(tcx, key)
});
}
// `to_dep_node` is expensive for some `DepKind`s. // `to_dep_node` is expensive for some `DepKind`s.
let dep_node = let dep_node =
dep_node_opt.unwrap_or_else(|| DepNode::construct(tcx, query.dep_kind, &key)); dep_node_opt.unwrap_or_else(|| DepNode::construct(tcx, query.dep_kind, &key));
@@ -601,9 +594,6 @@ fn check_if_ensure_can_skip_execution<'tcx, C: QueryCache>(
return EnsureCanSkip { skip_execution: false, dep_node: None }; return EnsureCanSkip { skip_execution: false, dep_node: None };
} }
// Ensuring an anonymous query makes no sense
assert!(!query.anon);
let dep_node = DepNode::construct(tcx, query.dep_kind, &key); let dep_node = DepNode::construct(tcx, query.dep_kind, &key);
let serialized_dep_node_index = match tcx.dep_graph.try_mark_green(tcx, &dep_node) { let serialized_dep_node_index = match tcx.dep_graph.try_mark_green(tcx, &dep_node) {
@@ -703,8 +693,6 @@ pub(crate) fn force_query<'tcx, C: QueryCache>(
return; return;
} }
debug_assert!(!query.anon);
ensure_sufficient_stack(|| { ensure_sufficient_stack(|| {
try_execute_query::<C, true>(query, tcx, DUMMY_SP, key, Some(dep_node)) try_execute_query::<C, true>(query, tcx, DUMMY_SP, key, Some(dep_node))
}); });
+1 -2
View File
@@ -16,12 +16,12 @@ macro_rules! define_queries {
fn $name:ident($K:ty) -> $V:ty fn $name:ident($K:ty) -> $V:ty
{ {
// Search for (QMODLIST) to find all occurrences of this query modifier list. // Search for (QMODLIST) to find all occurrences of this query modifier list.
anon: $anon:literal,
arena_cache: $arena_cache:literal, arena_cache: $arena_cache:literal,
cache_on_disk: $cache_on_disk:literal, cache_on_disk: $cache_on_disk:literal,
depth_limit: $depth_limit:literal, depth_limit: $depth_limit:literal,
eval_always: $eval_always:literal, eval_always: $eval_always:literal,
feedable: $feedable:literal, feedable: $feedable: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,
separate_provide_extern: $separate_provide_extern:literal, separate_provide_extern: $separate_provide_extern:literal,
@@ -132,7 +132,6 @@ pub(crate) fn make_query_vtable<'tcx>(incremental: bool)
QueryVTable { QueryVTable {
name: stringify!($name), name: stringify!($name),
anon: $anon,
eval_always: $eval_always, eval_always: $eval_always,
depth_limit: $depth_limit, depth_limit: $depth_limit,
feedable: $feedable, feedable: $feedable,
@@ -19,7 +19,7 @@ fn check_representability(tcx: TyCtxt<'_>, def_id: LocalDefId) {
DefKind::Struct | DefKind::Union | DefKind::Enum => { DefKind::Struct | DefKind::Union | DefKind::Enum => {
for variant in tcx.adt_def(def_id).variants() { for variant in tcx.adt_def(def_id).variants() {
for field in variant.fields.iter() { for field in variant.fields.iter() {
let _ = tcx.check_representability(field.did.expect_local()); tcx.ensure_ok().check_representability(field.did.expect_local());
} }
} }
} }
@@ -35,7 +35,7 @@ fn check_representability_ty<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) {
// This one must be a query rather than a vanilla `check_representability_adt_ty` call. See // This one must be a query rather than a vanilla `check_representability_adt_ty` call. See
// the comment on `check_representability_adt_ty` below for why. // the comment on `check_representability_adt_ty` below for why.
ty::Adt(..) => { ty::Adt(..) => {
let _ = tcx.check_representability_adt_ty(ty); tcx.ensure_ok().check_representability_adt_ty(ty);
} }
// FIXME(#11924) allow zero-length arrays? // FIXME(#11924) allow zero-length arrays?
ty::Array(ty, _) => { ty::Array(ty, _) => {
@@ -69,7 +69,7 @@ fn check_representability_ty<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) {
fn check_representability_adt_ty<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) { fn check_representability_adt_ty<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) {
let ty::Adt(adt, args) = ty.kind() else { bug!("expected adt") }; let ty::Adt(adt, args) = ty.kind() else { bug!("expected adt") };
if let Some(def_id) = adt.did().as_local() { if let Some(def_id) = adt.did().as_local() {
let _ = tcx.check_representability(def_id); tcx.ensure_ok().check_representability(def_id);
} }
// At this point, we know that the item of the ADT type is representable; // At this point, we know that the item of the ADT type is representable;
// but the type parameters may cause a cycle with an upstream type // but the type parameters may cause a cycle with an upstream type
+1 -1
View File
@@ -117,7 +117,7 @@ fn adt_sizedness_constraint<'tcx>(
(def_id, sizedness): (DefId, SizedTraitKind), (def_id, sizedness): (DefId, SizedTraitKind),
) -> Option<ty::EarlyBinder<'tcx, Ty<'tcx>>> { ) -> Option<ty::EarlyBinder<'tcx, Ty<'tcx>>> {
if let Some(def_id) = def_id.as_local() { if let Some(def_id) = def_id.as_local() {
let _ = tcx.check_representability(def_id); tcx.ensure_ok().check_representability(def_id);
} }
let def = tcx.adt_def(def_id); let def = tcx.adt_def(def_id);
@@ -418,6 +418,13 @@ deal with all of the above but so far that seemed like more trouble than it woul
## Query modifiers ## Query modifiers
> FIXME: Make [`rustc_middle::query::modifiers`] the home for query modifier documentation,
> and migrate all other useful modifier docs there after verifying that they are still accurate.
[`rustc_middle::query::modifiers`]:
https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/query/modifiers/index.html
The query system allows for applying [modifiers][mod] to queries. The query system allows for applying [modifiers][mod] to queries.
These modifiers affect certain aspects of how the system treats the query with These modifiers affect certain aspects of how the system treats the query with
respect to incremental compilation: respect to incremental compilation:
@@ -437,6 +444,9 @@ respect to incremental compilation:
as an optimization because the system can skip recording dependencies in as an optimization because the system can skip recording dependencies in
the first place. the first place.
- `no_force` - Never "force" the dep nodes for this query, even if the query's
key type is recoverable.
- `no_hash` - Applying `no_hash` to a query tells the system to not compute - `no_hash` - Applying `no_hash` to a query tells the system to not compute
the fingerprint of the query's result. the fingerprint of the query's result.
This has two consequences: This has two consequences:
@@ -475,13 +485,6 @@ respect to incremental compilation:
For example, it makes no sense to store values from upstream For example, it makes no sense to store values from upstream
crates in the cache because they are already available in the upstream crate's metadata. crates in the cache because they are already available in the upstream crate's metadata.
- `anon` - This attribute makes the system use "anonymous" dep-nodes for the given query.
An anonymous dep-node is not identified by the corresponding query key.
Instead, its ID is computed from the IDs of its dependencies.
This allows the red-green system to do its change detection even if there is no
query key available for a given dep-node -- something which is needed for
handling trait selection because it is not based on queries.
[mod]: ../query.html#adding-a-new-kind-of-query [mod]: ../query.html#adding-a-new-kind-of-query