Skip to content

Commit c7aa468

Browse files
committed
Don't use queries when printing the query stack
1 parent 5e9d3d8 commit c7aa468

File tree

10 files changed

+329
-109
lines changed

10 files changed

+329
-109
lines changed

compiler/rustc_interface/src/util.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -193,7 +193,7 @@ pub(crate) fn run_in_thread_pool_with_globals<F: FnOnce() -> R + Send, R: Send>(
193193
// locals to it. The new thread runs the deadlock handler.
194194
let query_map = tls::with(|tcx| {
195195
QueryCtxt::new(tcx)
196-
.try_collect_active_jobs()
196+
.try_collect_active_jobs(true)
197197
.expect("active jobs shouldn't be locked in deadlock handler")
198198
});
199199
let registry = rayon_core::Registry::current();

compiler/rustc_macros/src/query.rs

+8-4
Original file line numberDiff line numberDiff line change
@@ -273,11 +273,15 @@ fn add_query_desc_cached_impl(
273273

274274
let desc = quote! {
275275
#[allow(unused_variables)]
276-
pub fn #name<'tcx>(tcx: TyCtxt<'tcx>, key: crate::query::queries::#name::Key<'tcx>) -> String {
277-
let (#tcx, #key) = (tcx, key);
278-
::rustc_middle::ty::print::with_no_trimmed_paths!(
276+
pub fn #name<'tcx>(
277+
tcx: TyCtxt<'tcx>,
278+
key: crate::query::queries::#name::Key<'tcx>,
279+
use_queries: bool
280+
) -> String {
281+
::rustc_middle::query::print::run(tcx, use_queries, |ctx| {
282+
let (#tcx, #key) = (ctx, ctx.arg(key));
279283
format!(#desc)
280-
)
284+
})
281285
}
282286
};
283287

compiler/rustc_middle/src/query/mod.rs

+79-79
Large diffs are not rendered by default.
+181
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,181 @@
1+
use crate::mir::interpret::GlobalId;
2+
use crate::query::IntoQueryParam;
3+
use crate::query::TyCtxt;
4+
use crate::ty;
5+
use rustc_hir::def_id::CrateNum;
6+
use rustc_hir::def_id::DefId;
7+
use rustc_span::Symbol;
8+
use std::fmt;
9+
use std::fmt::Debug;
10+
use std::fmt::Display;
11+
12+
/// This is used to print query keys without giving them access to `TyCtxt`.
13+
/// This enables more reliable printing when printing the query stack on panics.
14+
#[derive(Copy, Clone)]
15+
pub struct PrintContext<'tcx> {
16+
tcx: TyCtxt<'tcx>,
17+
use_queries: bool,
18+
}
19+
20+
impl<'tcx> PrintContext<'tcx> {
21+
pub fn arg<T>(&self, arg: T) -> PrintArg<'tcx, T> {
22+
PrintArg { arg: Some(arg), ctx: *self }
23+
}
24+
25+
pub fn def_path_str(&self, def_id: PrintArg<'tcx, impl IntoQueryParam<DefId>>) -> String {
26+
def_id.print(|arg| {
27+
let def_id = arg.into_query_param();
28+
if self.use_queries {
29+
self.tcx.def_path_str(def_id)
30+
} else {
31+
self.tcx.safe_def_path_str_untracked(def_id)
32+
}
33+
})
34+
}
35+
}
36+
37+
/// This runs some code in a printing context. If `use_queries` is false this function should
38+
/// ensure that no queries are run.
39+
pub fn run<'tcx, R>(
40+
tcx: TyCtxt<'tcx>,
41+
use_queries: bool,
42+
print: impl FnOnce(PrintContext<'tcx>) -> R,
43+
) -> R {
44+
let ctx = PrintContext { tcx, use_queries };
45+
if use_queries { ty::print::with_no_trimmed_paths!(print(ctx)) } else { print(ctx) }
46+
}
47+
48+
const INACCESSIBLE: &'static str = "<inaccessible>";
49+
50+
/// This wraps a value that we want to print without giving access to the regular types
51+
/// and their Display and Debug impls. `map` and `map_with_tcx` gives access to the inner
52+
/// type, but erases the value for the no query path.
53+
#[derive(Copy, Clone)]
54+
pub struct PrintArg<'tcx, T> {
55+
arg: Option<T>,
56+
ctx: PrintContext<'tcx>,
57+
}
58+
59+
impl<'tcx, T> PrintArg<'tcx, T> {
60+
fn print(self, f: impl FnOnce(T) -> String) -> String {
61+
self.arg.map(f).unwrap_or_else(|| INACCESSIBLE.to_owned())
62+
}
63+
64+
fn fmt_map(
65+
&self,
66+
f: &mut fmt::Formatter<'_>,
67+
map: impl FnOnce(&mut fmt::Formatter<'_>, &T) -> fmt::Result,
68+
) -> fmt::Result {
69+
match &self.arg {
70+
Some(arg) => map(f, arg),
71+
_ => write!(f, "{}", INACCESSIBLE),
72+
}
73+
}
74+
75+
fn fmt_with_queries(
76+
&self,
77+
f: &mut fmt::Formatter<'_>,
78+
map: impl FnOnce(&mut fmt::Formatter<'_>, &T) -> fmt::Result,
79+
) -> fmt::Result {
80+
match &self.arg {
81+
Some(arg) if self.ctx.use_queries => map(f, arg),
82+
_ => write!(f, "{}", INACCESSIBLE),
83+
}
84+
}
85+
86+
pub fn ctx(&self) -> PrintContext<'tcx> {
87+
self.ctx
88+
}
89+
90+
/// Maps the argument where `f` is known to not call queries.
91+
fn map_unchecked<R>(self, f: impl FnOnce(T) -> R) -> PrintArg<'tcx, R> {
92+
PrintArg { arg: self.arg.map(f), ctx: self.ctx }
93+
}
94+
95+
pub fn map<R>(self, f: impl FnOnce(T) -> R) -> PrintArg<'tcx, R> {
96+
self.map_with_tcx(|_, arg| f(arg))
97+
}
98+
99+
pub fn map_with_tcx<R>(self, f: impl FnOnce(TyCtxt<'tcx>, T) -> R) -> PrintArg<'tcx, R> {
100+
PrintArg {
101+
arg: if self.ctx.use_queries { self.arg.map(|arg| f(self.ctx.tcx, arg)) } else { None },
102+
ctx: self.ctx,
103+
}
104+
}
105+
106+
pub fn describe_as_module(&self) -> String
107+
where
108+
T: IntoQueryParam<DefId> + Copy,
109+
{
110+
self.print(|arg| {
111+
let def_id: DefId = arg.into_query_param();
112+
if def_id.is_top_level_module() {
113+
"top-level module".to_string()
114+
} else {
115+
format!("module `{}`", self.ctx.def_path_str(*self))
116+
}
117+
})
118+
}
119+
}
120+
121+
impl<'tcx, T0, T1> PrintArg<'tcx, (T0, T1)> {
122+
pub fn i_0(self) -> PrintArg<'tcx, T0> {
123+
self.map_unchecked(|arg| arg.0)
124+
}
125+
pub fn i_1(self) -> PrintArg<'tcx, T1> {
126+
self.map_unchecked(|arg| arg.1)
127+
}
128+
}
129+
130+
impl<'tcx, T> PrintArg<'tcx, ty::ParamEnvAnd<'tcx, T>> {
131+
pub fn value(self) -> PrintArg<'tcx, T> {
132+
self.map_unchecked(|arg| arg.value)
133+
}
134+
}
135+
136+
impl<'tcx> PrintArg<'tcx, GlobalId<'tcx>> {
137+
pub fn display(self) -> String {
138+
self.print(|arg| {
139+
if self.ctx.use_queries {
140+
arg.display(self.ctx.tcx)
141+
} else {
142+
let instance_name = self.ctx.def_path_str(self.ctx.arg(arg.instance.def.def_id()));
143+
if let Some(promoted) = arg.promoted {
144+
format!("{instance_name}::{promoted:?}")
145+
} else {
146+
instance_name
147+
}
148+
}
149+
})
150+
}
151+
}
152+
153+
impl<T: Debug> Debug for PrintArg<'_, T> {
154+
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
155+
self.fmt_with_queries(f, |f, arg| arg.fmt(f))
156+
}
157+
}
158+
159+
impl<T: Display> Display for PrintArg<'_, T> {
160+
default fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
161+
self.fmt_with_queries(f, |f, arg| arg.fmt(f))
162+
}
163+
}
164+
165+
impl Display for PrintArg<'_, CrateNum> {
166+
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
167+
self.fmt_map(f, |f, arg| {
168+
if self.ctx.use_queries {
169+
write!(f, "`{}`", arg)
170+
} else {
171+
write!(f, "`{}`", self.ctx.tcx.safe_crate_str_untracked(*arg))
172+
}
173+
})
174+
}
175+
}
176+
177+
impl Display for PrintArg<'_, Symbol> {
178+
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
179+
self.fmt_map(f, |f, arg| fmt::Display::fmt(arg, f))
180+
}
181+
}

compiler/rustc_middle/src/ty/context.rs

+25
Original file line numberDiff line numberDiff line change
@@ -888,6 +888,31 @@ impl<'tcx> TyCtxt<'tcx> {
888888
}
889889
}
890890

891+
/// Prints a CrateNum without using queries.
892+
pub fn safe_crate_str_untracked(self, krate: CrateNum) -> String {
893+
if krate == LOCAL_CRATE {
894+
"crate".to_owned()
895+
} else {
896+
let cstore = &*self.cstore_untracked();
897+
cstore.crate_name(krate).as_str().to_owned()
898+
}
899+
}
900+
901+
/// Prints a DefId without using queries.
902+
pub fn safe_def_path_str_untracked(self, def_id: DefId) -> String {
903+
if def_id.is_local() {
904+
let format = self.def_path(def_id).to_string_no_crate_verbose();
905+
// Strip `::` from the formatted def path if present
906+
format.strip_prefix("::").map(|stripped| stripped.to_owned()).unwrap_or(format)
907+
} else {
908+
format!(
909+
"{}{}",
910+
self.safe_crate_str_untracked(def_id.krate),
911+
self.def_path(def_id).to_string_no_crate_verbose()
912+
)
913+
}
914+
}
915+
891916
pub fn def_path_debug_str(self, def_id: DefId) -> String {
892917
// We are explicitly not going through queries here in order to get
893918
// crate name and stable crate id since this code is called from debug!()

compiler/rustc_middle/src/ty/print/mod.rs

+1-11
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ use crate::ty::{self, Ty, TyCtxt};
33

44
use rustc_data_structures::fx::FxHashSet;
55
use rustc_data_structures::sso::SsoHashSet;
6-
use rustc_hir::def_id::{CrateNum, DefId, LocalDefId};
6+
use rustc_hir::def_id::{CrateNum, DefId};
77
use rustc_hir::definitions::{DefPathData, DisambiguatedDefPathData};
88

99
// `pretty` is a separate module only for organization.
@@ -327,13 +327,3 @@ impl<'tcx, P: Printer<'tcx>> Print<'tcx, P> for ty::Const<'tcx> {
327327
cx.print_const(*self)
328328
}
329329
}
330-
331-
// This is only used by query descriptions
332-
pub fn describe_as_module(def_id: impl Into<LocalDefId>, tcx: TyCtxt<'_>) -> String {
333-
let def_id = def_id.into();
334-
if def_id.is_top_level_module() {
335-
"top-level module".to_string()
336-
} else {
337-
format!("module `{}`", tcx.def_path_str(def_id))
338-
}
339-
}

compiler/rustc_query_impl/src/plumbing.rs

+28-9
Original file line numberDiff line numberDiff line change
@@ -78,11 +78,11 @@ impl QueryContext for QueryCtxt<'_> {
7878
tls::with_related_context(self.tcx, |icx| icx.query)
7979
}
8080

81-
fn try_collect_active_jobs(self) -> Option<QueryMap<DepKind>> {
81+
fn try_collect_active_jobs(self, can_call_queries: bool) -> Option<QueryMap<DepKind>> {
8282
let mut jobs = QueryMap::default();
8383

8484
for collect in super::TRY_COLLECT_ACTIVE_JOBS.iter() {
85-
collect(self.tcx, &mut jobs);
85+
collect(self.tcx, &mut jobs, can_call_queries);
8686
}
8787

8888
Some(jobs)
@@ -153,7 +153,7 @@ impl QueryContext for QueryCtxt<'_> {
153153
fn depth_limit_error(self, job: QueryJobId) {
154154
let mut span = None;
155155
let mut layout_of_depth = None;
156-
if let Some(map) = self.try_collect_active_jobs() {
156+
if let Some(map) = self.try_collect_active_jobs(true) {
157157
if let Some((info, depth)) = job.try_find_layout_root(map) {
158158
span = Some(info.job.span);
159159
layout_of_depth = Some(LayoutOfDepth { desc: info.query.description, depth });
@@ -296,18 +296,25 @@ pub(crate) fn create_query_frame<
296296
K: Copy + Key + for<'a> HashStable<StableHashingContext<'a>>,
297297
>(
298298
tcx: TyCtxt<'tcx>,
299-
do_describe: fn(TyCtxt<'tcx>, K) -> String,
299+
do_describe: fn(TyCtxt<'tcx>, K, bool) -> String,
300300
key: K,
301301
kind: DepKind,
302302
name: &'static str,
303+
can_call_queries: bool,
303304
) -> QueryStackFrame<DepKind> {
305+
if !can_call_queries {
306+
// Return a minimal query frame if we can't call queries
307+
let description = do_describe(tcx, key, false);
308+
return QueryStackFrame::new(description, None, None, None, kind, None, || Hash64::ZERO);
309+
}
310+
304311
// Avoid calling queries while formatting the description
305312
let description = ty::print::with_no_queries!(
306313
// Disable visible paths printing for performance reasons.
307314
// Showing visible path instead of any path is not that important in production.
308315
ty::print::with_no_visible_paths!(
309316
// Force filename-line mode to avoid invoking `type_of` query.
310-
ty::print::with_forced_impl_filename_line!(do_describe(tcx, key))
317+
ty::print::with_forced_impl_filename_line!(do_describe(tcx, key, true))
311318
)
312319
);
313320
let description =
@@ -650,16 +657,28 @@ macro_rules! define_queries {
650657
}
651658
}
652659

653-
pub fn try_collect_active_jobs<'tcx>(tcx: TyCtxt<'tcx>, qmap: &mut QueryMap<DepKind>) {
654-
let make_query = |tcx, key| {
660+
pub fn try_collect_active_jobs<'tcx>(
661+
tcx: TyCtxt<'tcx>,
662+
qmap: &mut QueryMap<DepKind>,
663+
can_call_queries: bool,
664+
) {
665+
let make_query = |tcx, key, can_call_queries| {
655666
let kind = rustc_middle::dep_graph::DepKind::$name;
656667
let name = stringify!($name);
657-
$crate::plumbing::create_query_frame(tcx, rustc_middle::query::descs::$name, key, kind, name)
668+
$crate::plumbing::create_query_frame(
669+
tcx,
670+
rustc_middle::query::descs::$name,
671+
key,
672+
kind,
673+
name,
674+
can_call_queries,
675+
)
658676
};
659677
tcx.query_system.states.$name.try_collect_active_jobs(
660678
tcx,
661679
make_query,
662680
qmap,
681+
can_call_queries,
663682
).unwrap();
664683
}
665684

@@ -710,7 +729,7 @@ macro_rules! define_queries {
710729

711730
// These arrays are used for iteration and can't be indexed by `DepKind`.
712731

713-
const TRY_COLLECT_ACTIVE_JOBS: &[for<'tcx> fn(TyCtxt<'tcx>, &mut QueryMap<DepKind>)] =
732+
const TRY_COLLECT_ACTIVE_JOBS: &[for<'tcx> fn(TyCtxt<'tcx>, &mut QueryMap<DepKind>, can_call_queries: bool)] =
714733
&[$(query_impl::$name::try_collect_active_jobs),*];
715734

716735
const ALLOC_SELF_PROFILE_QUERY_STRINGS: &[

compiler/rustc_query_system/src/query/job.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -628,7 +628,7 @@ pub fn print_query_stack<Qcx: QueryContext>(
628628
// state if it was responsible for triggering the panic.
629629
let mut count_printed = 0;
630630
let mut count_total = 0;
631-
let query_map = qcx.try_collect_active_jobs();
631+
let query_map = qcx.try_collect_active_jobs(false);
632632

633633
if let Some(ref mut file) = file {
634634
let _ = writeln!(file, "\n\nquery stack during panic:");

compiler/rustc_query_system/src/query/mod.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -106,7 +106,7 @@ pub trait QueryContext: HasDepContext {
106106
/// Get the query information from the TLS context.
107107
fn current_query_job(self) -> Option<QueryJobId>;
108108

109-
fn try_collect_active_jobs(self) -> Option<QueryMap<Self::DepKind>>;
109+
fn try_collect_active_jobs(self, can_call_queries: bool) -> Option<QueryMap<Self::DepKind>>;
110110

111111
/// Load side effects associated to the node in the previous session.
112112
fn load_side_effects(self, prev_dep_node_index: SerializedDepNodeIndex) -> QuerySideEffects;

0 commit comments

Comments
 (0)