Skip to content

Commit 15c6e6e

Browse files
committed
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.
1 parent d913766 commit 15c6e6e

8 files changed

Lines changed: 74 additions & 37 deletions

File tree

compiler/rustc_macros/src/query.rs

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -142,6 +142,7 @@ struct QueryModifiers {
142142
desc: Desc,
143143
eval_always: Option<Ident>,
144144
feedable: Option<Ident>,
145+
handle_cycle_error: Option<Ident>,
145146
no_force: Option<Ident>,
146147
no_hash: Option<Ident>,
147148
separate_provide_extern: Option<Ident>,
@@ -156,6 +157,7 @@ fn parse_query_modifiers(input: ParseStream<'_>) -> Result<QueryModifiers> {
156157
let mut desc = None;
157158
let mut eval_always = None;
158159
let mut feedable = None;
160+
let mut handle_cycle_error = None;
159161
let mut no_force = None;
160162
let mut no_hash = None;
161163
let mut separate_provide_extern = None;
@@ -190,6 +192,8 @@ fn parse_query_modifiers(input: ParseStream<'_>) -> Result<QueryModifiers> {
190192
try_insert!(eval_always = modifier);
191193
} else if modifier == "feedable" {
192194
try_insert!(feedable = modifier);
195+
} else if modifier == "handle_cycle_error" {
196+
try_insert!(handle_cycle_error = modifier);
193197
} else if modifier == "no_force" {
194198
try_insert!(no_force = modifier);
195199
} else if modifier == "no_hash" {
@@ -211,6 +215,7 @@ fn parse_query_modifiers(input: ParseStream<'_>) -> Result<QueryModifiers> {
211215
desc,
212216
eval_always,
213217
feedable,
218+
handle_cycle_error,
214219
no_force,
215220
no_hash,
216221
separate_provide_extern,
@@ -246,6 +251,7 @@ fn make_modifiers_stream(query: &Query) -> proc_macro2::TokenStream {
246251
desc,
247252
eval_always,
248253
feedable,
254+
handle_cycle_error,
249255
no_force,
250256
no_hash,
251257
separate_provide_extern,
@@ -270,6 +276,7 @@ fn make_modifiers_stream(query: &Query) -> proc_macro2::TokenStream {
270276
};
271277
let eval_always = eval_always.is_some();
272278
let feedable = feedable.is_some();
279+
let handle_cycle_error = handle_cycle_error.is_some();
273280
let no_force = no_force.is_some();
274281
let no_hash = no_hash.is_some();
275282
let returns_error_guaranteed = returns_error_guaranteed(&query.return_ty);
@@ -290,6 +297,7 @@ fn make_modifiers_stream(query: &Query) -> proc_macro2::TokenStream {
290297
desc: #desc,
291298
eval_always: #eval_always,
292299
feedable: #feedable,
300+
handle_cycle_error: #handle_cycle_error,
293301
no_force: #no_force,
294302
no_hash: #no_hash,
295303
returns_error_guaranteed: #returns_error_guaranteed,
@@ -358,6 +366,7 @@ fn add_to_analyzer_stream(query: &Query, analyzer_stream: &mut proc_macro2::Toke
358366
// `desc` is handled above
359367
eval_always,
360368
feedable,
369+
handle_cycle_error,
361370
no_force,
362371
no_hash,
363372
separate_provide_extern,

compiler/rustc_middle/src/queries.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -583,6 +583,7 @@ rustc_queries! {
583583
// messages about cycles that then abort.)
584584
query check_representability(key: LocalDefId) {
585585
desc { "checking if `{}` is representable", tcx.def_path_str(key) }
586+
handle_cycle_error
586587
// We don't want recursive representability calls to be forced with
587588
// incremental compilation because, if a cycle occurs, we need the
588589
// entire cycle to be in memory for diagnostics.
@@ -593,6 +594,7 @@ rustc_queries! {
593594
/// details, particularly on the modifiers.
594595
query check_representability_adt_ty(key: Ty<'tcx>) {
595596
desc { "checking if `{}` is representable", key }
597+
handle_cycle_error
596598
no_force
597599
}
598600

@@ -1032,6 +1034,7 @@ rustc_queries! {
10321034
query variances_of(def_id: DefId) -> &'tcx [ty::Variance] {
10331035
desc { "computing the variances of `{}`", tcx.def_path_str(def_id) }
10341036
cache_on_disk
1037+
handle_cycle_error
10351038
separate_provide_extern
10361039
}
10371040

@@ -1164,6 +1167,7 @@ rustc_queries! {
11641167
query fn_sig(key: DefId) -> ty::EarlyBinder<'tcx, ty::PolyFnSig<'tcx>> {
11651168
desc { "computing function signature of `{}`", tcx.def_path_str(key) }
11661169
cache_on_disk
1170+
handle_cycle_error
11671171
separate_provide_extern
11681172
}
11691173

@@ -1756,6 +1760,7 @@ rustc_queries! {
17561760
) -> Result<ty::layout::TyAndLayout<'tcx>, &'tcx ty::layout::LayoutError<'tcx>> {
17571761
depth_limit
17581762
desc { "computing layout of `{}`", key.value }
1763+
handle_cycle_error
17591764
}
17601765

17611766
/// Compute a `FnAbi` suitable for indirect calls, i.e. to `fn` pointers.

compiler/rustc_middle/src/query/modifiers.rs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,14 @@ pub(crate) struct eval_always;
5858
/// Generate a `feed` method to set the query's value from another query.
5959
pub(crate) struct feedable;
6060

61+
/// # `handle_cycle_error` query modifier
62+
///
63+
/// The default behaviour for a query cycle is to emit a cycle error and halt
64+
/// compilation. Queries with this modifier will instead use a custom handler,
65+
/// which must be provided at `rustc_query_impl::handle_cycle_error::$name`,
66+
/// where `$name` is the query name.
67+
pub(crate) struct handle_cycle_error;
68+
6169
/// # `no_force` query modifier
6270
///
6371
/// Dep nodes of queries with this modifier will never be "forced" when trying

compiler/rustc_middle/src/query/plumbing.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -304,6 +304,7 @@ macro_rules! define_callbacks {
304304
desc: $desc:expr,
305305
eval_always: $eval_always:literal,
306306
feedable: $feedable:literal,
307+
handle_cycle_error: $handle_cycle_error:literal,
307308
no_force: $no_force:literal,
308309
no_hash: $no_hash:literal,
309310
returns_error_guaranteed: $returns_error_guaranteed:literal,

compiler/rustc_query_impl/src/dep_kind_vtables.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -138,6 +138,7 @@ macro_rules! define_dep_kind_vtables {
138138
desc: $desc:expr,
139139
eval_always: $eval_always:literal,
140140
feedable: $feedable:literal,
141+
handle_cycle_error: $handle_cycle_error:literal,
141142
no_force: $no_force:literal,
142143
no_hash: $no_hash:literal,
143144
returns_error_guaranteed: $returns_error_guaranteed:literal,

compiler/rustc_query_impl/src/handle_cycle_error.rs

Lines changed: 41 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -9,48 +9,29 @@ use rustc_errors::{Applicability, Diag, MultiSpan, pluralize, struct_span_code_e
99
use rustc_hir as hir;
1010
use rustc_hir::def::{DefKind, Res};
1111
use rustc_middle::bug;
12-
use rustc_middle::queries::{QueryVTables, TaggedQueryKey};
12+
use rustc_middle::queries::TaggedQueryKey;
1313
use rustc_middle::query::Cycle;
14-
use rustc_middle::query::erase::erase_val;
1514
use rustc_middle::ty::{self, Ty, TyCtxt};
1615
use rustc_span::def_id::{DefId, LocalDefId};
1716
use rustc_span::{ErrorGuaranteed, Span};
1817

1918
use crate::job::create_cycle_error;
2019

21-
pub(crate) fn specialize_query_vtables<'tcx>(vtables: &mut QueryVTables<'tcx>) {
22-
vtables.fn_sig.handle_cycle_error_fn = |tcx, key, _, err| {
23-
let guar = err.delay_as_bug();
24-
erase_val(fn_sig(tcx, key, guar))
25-
};
26-
27-
vtables.check_representability.handle_cycle_error_fn =
28-
|tcx, _, cycle, _err| check_representability(tcx, cycle);
29-
30-
vtables.check_representability_adt_ty.handle_cycle_error_fn =
31-
|tcx, _, cycle, _err| check_representability(tcx, cycle);
32-
33-
vtables.variances_of.handle_cycle_error_fn = |tcx, key, _, err| {
34-
let _guar = err.delay_as_bug();
35-
erase_val(variances_of(tcx, key))
36-
};
37-
38-
vtables.layout_of.handle_cycle_error_fn = |tcx, _, cycle, err| {
39-
let _guar = err.delay_as_bug();
40-
erase_val(Err(layout_of(tcx, cycle)))
41-
}
42-
}
43-
20+
// Default cycle handler used for all queries that don't use the `handle_cycle_error` query
21+
// modifier.
4422
pub(crate) fn default(err: Diag<'_>) -> ! {
4523
let guar = err.emit();
4624
guar.raise_fatal()
4725
}
4826

49-
fn fn_sig<'tcx>(
27+
pub(crate) fn fn_sig<'tcx>(
5028
tcx: TyCtxt<'tcx>,
5129
def_id: DefId,
52-
guar: ErrorGuaranteed,
30+
_: Cycle<'tcx>,
31+
err: Diag<'_>,
5332
) -> ty::EarlyBinder<'tcx, ty::PolyFnSig<'tcx>> {
33+
let guar = err.delay_as_bug();
34+
5435
let err = Ty::new_error(tcx, guar);
5536

5637
let arity = if let Some(node) = tcx.hir_get_if_local(def_id)
@@ -71,7 +52,25 @@ fn fn_sig<'tcx>(
7152
)))
7253
}
7354

74-
fn check_representability<'tcx>(tcx: TyCtxt<'tcx>, cycle: Cycle<'tcx>) -> ! {
55+
pub(crate) fn check_representability<'tcx>(
56+
tcx: TyCtxt<'tcx>,
57+
_key: LocalDefId,
58+
cycle: Cycle<'tcx>,
59+
_err: Diag<'_>,
60+
) {
61+
check_representability_inner(tcx, cycle);
62+
}
63+
64+
pub(crate) fn check_representability_adt_ty<'tcx>(
65+
tcx: TyCtxt<'tcx>,
66+
_key: Ty<'tcx>,
67+
cycle: Cycle<'tcx>,
68+
_err: Diag<'_>,
69+
) {
70+
check_representability_inner(tcx, cycle);
71+
}
72+
73+
fn check_representability_inner<'tcx>(tcx: TyCtxt<'tcx>, cycle: Cycle<'tcx>) -> ! {
7574
let mut item_and_field_ids = Vec::new();
7675
let mut representable_ids = FxHashSet::default();
7776
for frame in &cycle.frames {
@@ -102,7 +101,13 @@ fn check_representability<'tcx>(tcx: TyCtxt<'tcx>, cycle: Cycle<'tcx>) -> ! {
102101
guar.raise_fatal()
103102
}
104103

105-
fn variances_of<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId) -> &'tcx [ty::Variance] {
104+
pub(crate) fn variances_of<'tcx>(
105+
tcx: TyCtxt<'tcx>,
106+
def_id: DefId,
107+
_cycle: Cycle<'tcx>,
108+
err: Diag<'_>,
109+
) -> &'tcx [ty::Variance] {
110+
let _guar = err.delay_as_bug();
106111
let n = tcx.generics_of(def_id).own_params.len();
107112
tcx.arena.alloc_from_iter(iter::repeat_n(ty::Bivariant, n))
108113
}
@@ -126,7 +131,13 @@ fn search_for_cycle_permutation<Q, T>(
126131
otherwise()
127132
}
128133

129-
fn layout_of<'tcx>(tcx: TyCtxt<'tcx>, cycle: Cycle<'tcx>) -> &'tcx ty::layout::LayoutError<'tcx> {
134+
pub(crate) fn layout_of<'tcx>(
135+
tcx: TyCtxt<'tcx>,
136+
_key: ty::PseudoCanonicalInput<'tcx, Ty<'tcx>>,
137+
cycle: Cycle<'tcx>,
138+
err: Diag<'_>,
139+
) -> Result<ty::layout::TyAndLayout<'tcx>, &'tcx ty::layout::LayoutError<'tcx>> {
140+
let _guar = err.delay_as_bug();
130141
let diag = search_for_cycle_permutation(
131142
&cycle.frames,
132143
|frames| {

compiler/rustc_query_impl/src/lib.rs

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -48,11 +48,9 @@ pub fn query_system<'tcx>(
4848
on_disk_cache: Option<OnDiskCache>,
4949
incremental: bool,
5050
) -> QuerySystem<'tcx> {
51-
let mut query_vtables = query_impl::make_query_vtables(incremental);
52-
handle_cycle_error::specialize_query_vtables(&mut query_vtables);
5351
QuerySystem {
5452
arenas: Default::default(),
55-
query_vtables,
53+
query_vtables: query_impl::make_query_vtables(incremental),
5654
side_effects: Default::default(),
5755
on_disk_cache,
5856
local_providers,

compiler/rustc_query_impl/src/query_impl.rs

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ macro_rules! define_queries {
2222
desc: $desc:expr,
2323
eval_always: $eval_always:literal,
2424
feedable: $feedable:literal,
25+
handle_cycle_error: $handle_cycle_error:literal,
2526
no_force: $no_force:literal,
2627
no_hash: $no_hash:literal,
2728
returns_error_guaranteed: $returns_error_guaranteed:literal,
@@ -144,7 +145,6 @@ macro_rules! define_queries {
144145
-> QueryVTable<'tcx, rustc_middle::queries::$name::Cache<'tcx>>
145146
{
146147
use rustc_middle::queries::$name::Value;
147-
148148
QueryVTable {
149149
name: stringify!($name),
150150
eval_always: $eval_always,
@@ -177,9 +177,13 @@ macro_rules! define_queries {
177177
#[cfg(not($cache_on_disk))]
178178
try_load_from_disk_fn: |_tcx, _key, _prev_index, _index| None,
179179

180-
// The default just emits `err` and then aborts.
181-
// `handle_cycle_error::specialize_query_vtables` overwrites this default
182-
// for certain queries.
180+
#[cfg($handle_cycle_error)]
181+
handle_cycle_error_fn: |tcx, key, cycle, err| {
182+
use rustc_middle::query::erase::erase_val;
183+
184+
erase_val($crate::handle_cycle_error::$name(tcx, key, cycle, err))
185+
},
186+
#[cfg(not($handle_cycle_error))]
183187
handle_cycle_error_fn: |_tcx, _key, _cycle, err| {
184188
$crate::handle_cycle_error::default(err)
185189
},

0 commit comments

Comments
 (0)