Skip to content

Commit 353dbdf

Browse files
committed
Move query TLS to rustc_query_system.
1 parent 4b3745f commit 353dbdf

File tree

21 files changed

+309
-312
lines changed

21 files changed

+309
-312
lines changed

Cargo.lock

+1
Original file line numberDiff line numberDiff line change
@@ -3883,6 +3883,7 @@ dependencies = [
38833883
"rustc_plugin_impl",
38843884
"rustc_privacy",
38853885
"rustc_query_impl",
3886+
"rustc_query_system",
38863887
"rustc_resolve",
38873888
"rustc_serialize",
38883889
"rustc_session",

compiler/rustc_interface/Cargo.toml

+1
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@ rustc_lint = { path = "../rustc_lint" }
4343
rustc_errors = { path = "../rustc_errors" }
4444
rustc_plugin_impl = { path = "../rustc_plugin_impl" }
4545
rustc_privacy = { path = "../rustc_privacy" }
46+
rustc_query_system = { path = "../rustc_query_system" }
4647
rustc_query_impl = { path = "../rustc_query_impl" }
4748
rustc_resolve = { path = "../rustc_resolve" }
4849
rustc_trait_selection = { path = "../rustc_trait_selection" }

compiler/rustc_interface/src/callbacks.rs

+1-16
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,6 @@
99
//! The functions in this file should fall back to the default set in their
1010
//! origin crate when the `TyCtxt` is not present in TLS.
1111
12-
use rustc_errors::{Diagnostic, TRACK_DIAGNOSTICS};
1312
use rustc_middle::ty::tls;
1413
use std::fmt;
1514

@@ -23,20 +22,6 @@ fn track_span_parent(def_id: rustc_span::def_id::LocalDefId) {
2322
})
2423
}
2524

26-
/// This is a callback from `rustc_ast` as it cannot access the implicit state
27-
/// in `rustc_middle` otherwise. It is used to when diagnostic messages are
28-
/// emitted and stores them in the current query, if there is one.
29-
fn track_diagnostic(diagnostic: &Diagnostic) {
30-
tls::with_context_opt(|icx| {
31-
if let Some(icx) = icx {
32-
if let Some(diagnostics) = icx.diagnostics {
33-
let mut diagnostics = diagnostics.lock();
34-
diagnostics.extend(Some(diagnostic.clone()));
35-
}
36-
}
37-
})
38-
}
39-
4025
/// This is a callback from `rustc_hir` as it cannot access the implicit state
4126
/// in `rustc_middle` otherwise.
4227
fn def_id_debug(def_id: rustc_hir::def_id::DefId, f: &mut fmt::Formatter<'_>) -> fmt::Result {
@@ -55,5 +40,5 @@ fn def_id_debug(def_id: rustc_hir::def_id::DefId, f: &mut fmt::Formatter<'_>) ->
5540
pub fn setup_callbacks() {
5641
rustc_span::SPAN_TRACK.swap(&(track_span_parent as fn(_)));
5742
rustc_hir::def_id::DEF_ID_DEBUG.swap(&(def_id_debug as fn(_, &mut fmt::Formatter<'_>) -> _));
58-
TRACK_DIAGNOSTICS.swap(&(track_diagnostic as fn(&_)));
43+
rustc_errors::TRACK_DIAGNOSTICS.swap(&(rustc_query_system::tls::track_diagnostic as fn(&_)));
5944
}

compiler/rustc_interface/src/interface.rs

+3-3
Original file line numberDiff line numberDiff line change
@@ -344,9 +344,9 @@ pub fn try_print_query_stack(handler: &Handler, num_frames: Option<usize>) {
344344
// Be careful relying on global state here: this code is called from
345345
// a panic hook, which means that the global `Handler` may be in a weird
346346
// state if it was responsible for triggering the panic.
347-
let i = ty::tls::with_context_opt(|icx| {
348-
if let Some(icx) = icx {
349-
QueryCtxt::from_tcx(icx.tcx).try_print_query_stack(icx.query, handler, num_frames)
347+
let i = ty::tls::with_opt(|tcx| {
348+
if let Some(tcx) = tcx {
349+
QueryCtxt::from_tcx(tcx).try_print_query_stack(handler, num_frames)
350350
} else {
351351
0
352352
}

compiler/rustc_interface/src/passes.rs

+3-4
Original file line numberDiff line numberDiff line change
@@ -806,13 +806,12 @@ pub struct QueryContext<'tcx> {
806806
gcx: &'tcx GlobalCtxt<'tcx>,
807807
}
808808

809-
impl<'tcx> QueryContext<'tcx> {
809+
impl<'gcx> QueryContext<'gcx> {
810810
pub fn enter<F, R>(&mut self, f: F) -> R
811811
where
812-
F: FnOnce(TyCtxt<'tcx>) -> R,
812+
F: for<'tcx> FnOnce(TyCtxt<'tcx>) -> R,
813813
{
814-
let icx = ty::tls::ImplicitCtxt::new(self.gcx);
815-
ty::tls::enter_context(&icx, |_| f(icx.tcx))
814+
ty::tls::enter_context(self.gcx, f)
816815
}
817816
}
818817

compiler/rustc_interface/src/util.rs

+12-10
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ use rustc_data_structures::jobserver;
77
use rustc_data_structures::sync::Lrc;
88
use rustc_errors::registry::Registry;
99
#[cfg(parallel_compiler)]
10-
use rustc_middle::ty::tls;
10+
use rustc_middle::ty::{tls, GlobalCtxt};
1111
use rustc_parse::validate_attr;
1212
#[cfg(parallel_compiler)]
1313
use rustc_query_impl::QueryCtxt;
@@ -166,19 +166,21 @@ pub fn run_in_thread_pool_with_globals<F: FnOnce() -> R + Send, R: Send>(
166166
unsafe fn handle_deadlock() {
167167
let registry = rustc_rayon_core::Registry::current();
168168

169-
let context = tls::get_tlv();
170-
assert!(context != 0);
171-
rustc_data_structures::sync::assert_sync::<tls::ImplicitCtxt<'_, '_>>();
172-
let icx: &tls::ImplicitCtxt<'_, '_> = &*(context as *const tls::ImplicitCtxt<'_, '_>);
169+
// We do not need to copy the query ImplicitCtxt since this deadlock handler is not part of a
170+
// normal query invocation.
173171

174172
let session_globals = rustc_span::with_session_globals(|sg| sg as *const _);
175173
let session_globals = &*session_globals;
174+
175+
// Extend the lifetime of the GlobalCtxt so the new thread can know of it.
176+
// The current thread will not free it, it is deadlocked.
177+
let tcx: &'static GlobalCtxt<'static> =
178+
tls::with(|tcx| &*(*tcx as *const GlobalCtxt<'_>).cast());
179+
176180
thread::spawn(move || {
177-
tls::enter_context(icx, |_| {
178-
rustc_span::set_session_globals_then(session_globals, || {
179-
tls::with(|tcx| QueryCtxt::from_tcx(tcx).deadlock(&registry))
180-
})
181-
});
181+
rustc_span::set_session_globals_then(session_globals, || {
182+
tls::enter_context(tcx, |tcx| QueryCtxt::from_tcx(tcx).deadlock(&registry))
183+
})
182184
});
183185
}
184186

compiler/rustc_middle/src/dep_graph/dep_node.rs

+2
Original file line numberDiff line numberDiff line change
@@ -216,6 +216,8 @@ static_assert_size!(DepNode, 18);
216216
#[cfg(not(any(target_arch = "x86", target_arch = "x86_64")))]
217217
static_assert_size!(DepNode, 24);
218218

219+
static_assert_size!(DepKind, 2);
220+
219221
pub trait DepNodeExt: Sized {
220222
/// Construct a DepNode from the given DepKind and DefPathHash. This
221223
/// method will assert that the given DepKind actually requires a

compiler/rustc_middle/src/dep_graph/mod.rs

-21
Original file line numberDiff line numberDiff line change
@@ -44,27 +44,6 @@ impl rustc_query_system::dep_graph::DepKind for DepKind {
4444

4545
write!(f, ")")
4646
}
47-
48-
fn with_deps<OP, R>(task_deps: TaskDepsRef<'_>, op: OP) -> R
49-
where
50-
OP: FnOnce() -> R,
51-
{
52-
ty::tls::with_context(|icx| {
53-
let icx = ty::tls::ImplicitCtxt { task_deps, ..icx.clone() };
54-
55-
ty::tls::enter_context(&icx, |_| op())
56-
})
57-
}
58-
59-
fn read_deps<OP>(op: OP)
60-
where
61-
OP: for<'a> FnOnce(TaskDepsRef<'a>),
62-
{
63-
ty::tls::with_context_opt(|icx| {
64-
let Some(icx) = icx else { return };
65-
op(icx.task_deps)
66-
})
67-
}
6847
}
6948

7049
impl<'tcx> DepContext for TyCtxt<'tcx> {

compiler/rustc_middle/src/hir/map/mod.rs

+2-12
Original file line numberDiff line numberDiff line change
@@ -1156,18 +1156,8 @@ fn hir_id_to_string(map: Map<'_>, id: HirId) -> String {
11561156
let id_str = format!(" (hir_id={})", id);
11571157

11581158
let path_str = || {
1159-
// This functionality is used for debugging, try to use `TyCtxt` to get
1160-
// the user-friendly path, otherwise fall back to stringifying `DefPath`.
1161-
crate::ty::tls::with_opt(|tcx| {
1162-
if let Some(tcx) = tcx {
1163-
let def_id = map.local_def_id(id);
1164-
tcx.def_path_str(def_id.to_def_id())
1165-
} else if let Some(path) = map.def_path_from_hir_id(id) {
1166-
path.data.into_iter().map(|elem| elem.to_string()).collect::<Vec<_>>().join("::")
1167-
} else {
1168-
String::from("<missing path>")
1169-
}
1170-
})
1159+
let def_id = map.local_def_id(id);
1160+
map.tcx.def_path_str(def_id.to_def_id())
11711161
};
11721162

11731163
let span_str = || map.tcx.sess.source_map().span_to_snippet(map.span(id)).unwrap_or_default();

compiler/rustc_middle/src/ty/context.rs

+32-126
Original file line numberDiff line numberDiff line change
@@ -1682,155 +1682,61 @@ CloneLiftImpls! { for<'tcx> { Constness, traits::WellFormedLoc, } }
16821682

16831683
pub mod tls {
16841684
use super::{GlobalCtxt, TyCtxt};
1685-
1686-
use crate::dep_graph::TaskDepsRef;
1687-
use crate::ty::query;
1688-
use rustc_data_structures::sync::{self, Lock};
1689-
use rustc_data_structures::thin_vec::ThinVec;
1690-
use rustc_errors::Diagnostic;
1691-
1692-
#[cfg(not(parallel_compiler))]
1685+
use rustc_data_structures::sync;
16931686
use std::cell::Cell;
16941687

1695-
#[cfg(parallel_compiler)]
1696-
use rustc_rayon_core as rayon_core;
1697-
1698-
/// This is the implicit state of rustc. It contains the current
1699-
/// `TyCtxt` and query. It is updated when creating a local interner or
1700-
/// executing a new query. Whenever there's a `TyCtxt` value available
1701-
/// you should also have access to an `ImplicitCtxt` through the functions
1702-
/// in this module.
1703-
#[derive(Clone)]
1704-
pub struct ImplicitCtxt<'a, 'tcx> {
1705-
/// The current `TyCtxt`.
1706-
pub tcx: TyCtxt<'tcx>,
1707-
1708-
/// The current query job, if any. This is updated by `JobOwner::start` in
1709-
/// `ty::query::plumbing` when executing a query.
1710-
pub query: Option<query::QueryJobId>,
1711-
1712-
/// Where to store diagnostics for the current query job, if any.
1713-
/// This is updated by `JobOwner::start` in `ty::query::plumbing` when executing a query.
1714-
pub diagnostics: Option<&'a Lock<ThinVec<Diagnostic>>>,
1715-
1716-
/// Used to prevent layout from recursing too deeply.
1717-
pub layout_depth: usize,
1718-
1719-
/// The current dep graph task. This is used to add dependencies to queries
1720-
/// when executing them.
1721-
pub task_deps: TaskDepsRef<'a>,
1722-
}
1723-
1724-
impl<'a, 'tcx> ImplicitCtxt<'a, 'tcx> {
1725-
pub fn new(gcx: &'tcx GlobalCtxt<'tcx>) -> Self {
1726-
let tcx = TyCtxt { gcx };
1727-
ImplicitCtxt {
1728-
tcx,
1729-
query: None,
1730-
diagnostics: None,
1731-
layout_depth: 0,
1732-
task_deps: TaskDepsRef::Ignore,
1733-
}
1734-
}
1735-
}
1736-
1737-
/// Sets Rayon's thread-local variable, which is preserved for Rayon jobs
1738-
/// to `value` during the call to `f`. It is restored to its previous value after.
1739-
/// This is used to set the pointer to the new `ImplicitCtxt`.
1740-
#[cfg(parallel_compiler)]
1741-
#[inline]
1742-
fn set_tlv<F: FnOnce() -> R, R>(value: usize, f: F) -> R {
1743-
rayon_core::tlv::with(value, f)
1744-
}
1745-
1746-
/// Gets Rayon's thread-local variable, which is preserved for Rayon jobs.
1747-
/// This is used to get the pointer to the current `ImplicitCtxt`.
1748-
#[cfg(parallel_compiler)]
1749-
#[inline]
1750-
pub fn get_tlv() -> usize {
1751-
rayon_core::tlv::get()
1752-
}
1753-
1754-
#[cfg(not(parallel_compiler))]
17551688
thread_local! {
1756-
/// A thread local variable that stores a pointer to the current `ImplicitCtxt`.
1757-
static TLV: Cell<usize> = const { Cell::new(0) };
1758-
}
1759-
1760-
/// Sets TLV to `value` during the call to `f`.
1761-
/// It is restored to its previous value after.
1762-
/// This is used to set the pointer to the new `ImplicitCtxt`.
1763-
#[cfg(not(parallel_compiler))]
1764-
#[inline]
1765-
fn set_tlv<F: FnOnce() -> R, R>(value: usize, f: F) -> R {
1766-
let old = get_tlv();
1767-
let _reset = rustc_data_structures::OnDrop(move || TLV.with(|tlv| tlv.set(old)));
1768-
TLV.with(|tlv| tlv.set(value));
1769-
f()
1770-
}
1771-
1772-
/// Gets the pointer to the current `ImplicitCtxt`.
1773-
#[cfg(not(parallel_compiler))]
1774-
#[inline]
1775-
fn get_tlv() -> usize {
1776-
TLV.with(|tlv| tlv.get())
1689+
/// This is the implicit state of rustc. It contains the `TyCtxt`. Whenever there's a
1690+
/// `TyCtxt` value available you should also have access to it through the functions in this
1691+
/// module.
1692+
static TLV: Cell<*const GlobalCtxt<'static>> = const { Cell::new(std::ptr::null()) };
17771693
}
17781694

1779-
/// Sets `context` as the new current `ImplicitCtxt` for the duration of the function `f`.
1695+
/// Sets `context` as the new current `TyCtxt` for the duration of the function `f`.
17801696
#[inline]
1781-
pub fn enter_context<'a, 'tcx, F, R>(context: &ImplicitCtxt<'a, 'tcx>, f: F) -> R
1697+
pub fn enter_context<'gcx, F, R>(gcx: &'gcx GlobalCtxt<'gcx>, f: F) -> R
17821698
where
1783-
F: FnOnce(&ImplicitCtxt<'a, 'tcx>) -> R,
1784-
{
1785-
set_tlv(context as *const _ as usize, || f(&context))
1786-
}
1787-
1788-
/// Allows access to the current `ImplicitCtxt` in a closure if one is available.
1789-
#[inline]
1790-
pub fn with_context_opt<F, R>(f: F) -> R
1791-
where
1792-
F: for<'a, 'tcx> FnOnce(Option<&ImplicitCtxt<'a, 'tcx>>) -> R,
1699+
F: for<'tcx> FnOnce(TyCtxt<'tcx>) -> R,
17931700
{
1794-
let context = get_tlv();
1795-
if context == 0 {
1796-
f(None)
1797-
} else {
1798-
// We could get an `ImplicitCtxt` pointer from another thread.
1799-
// Ensure that `ImplicitCtxt` is `Sync`.
1800-
sync::assert_sync::<ImplicitCtxt<'_, '_>>();
1801-
1802-
unsafe { f(Some(&*(context as *const ImplicitCtxt<'_, '_>))) }
1803-
}
1804-
}
1701+
// We are storing `GlobalCtxt` as a global.
1702+
// Ensure that it is `Sync`.
1703+
sync::assert_sync::<GlobalCtxt<'_>>();
18051704

1806-
/// Allows access to the current `ImplicitCtxt`.
1807-
/// Panics if there is no `ImplicitCtxt` available.
1808-
#[inline]
1809-
pub fn with_context<F, R>(f: F) -> R
1810-
where
1811-
F: for<'a, 'tcx> FnOnce(&ImplicitCtxt<'a, 'tcx>) -> R,
1812-
{
1813-
with_context_opt(|opt_context| f(opt_context.expect("no ImplicitCtxt stored in tls")))
1705+
let address = (gcx as *const GlobalCtxt<'_>).cast();
1706+
let old = TLV.with(|tlv| tlv.replace(address));
1707+
let _reset = rustc_data_structures::OnDrop(move || TLV.with(|tlv| tlv.set(old)));
1708+
debug_assert!(
1709+
old == address || old == std::ptr::null(),
1710+
"There can only be one GlobalCtxt."
1711+
);
1712+
f(TyCtxt { gcx })
18141713
}
18151714

1816-
/// Allows access to the `TyCtxt` in the current `ImplicitCtxt`.
1817-
/// Panics if there is no `ImplicitCtxt` available.
1715+
/// Allows access to the current `TyCtxt`.
1716+
/// Panics if there is no `TyCtxt` available.
18181717
#[inline]
18191718
pub fn with<F, R>(f: F) -> R
18201719
where
18211720
F: for<'tcx> FnOnce(TyCtxt<'tcx>) -> R,
18221721
{
1823-
with_context(|context| f(context.tcx))
1722+
with_opt(|opt_tcx| f(opt_tcx.expect("no TyCtxt stored in tls")))
18241723
}
18251724

1826-
/// Allows access to the `TyCtxt` in the current `ImplicitCtxt`.
1827-
/// The closure is passed None if there is no `ImplicitCtxt` available.
1725+
/// Allows access to the current `TyCtxt`.
1726+
/// The closure is passed None if there is no `TyCtxt` available.
18281727
#[inline]
18291728
pub fn with_opt<F, R>(f: F) -> R
18301729
where
18311730
F: for<'tcx> FnOnce(Option<TyCtxt<'tcx>>) -> R,
18321731
{
1833-
with_context_opt(|opt_context| f(opt_context.map(|context| context.tcx)))
1732+
let context = TLV.with(|tlv| tlv.get());
1733+
let tcx = if context == std::ptr::null() {
1734+
None
1735+
} else {
1736+
let gcx = unsafe { &*context.cast::<GlobalCtxt<'_>>() };
1737+
Some(TyCtxt { gcx })
1738+
};
1739+
f(tcx)
18341740
}
18351741
}
18361742

0 commit comments

Comments
 (0)