Skip to content

Commit 70a665a

Browse files
authored
Rollup merge of #107150 - Nilstrieb:thread-local-cleanups, r=cjgillot
`ty::tls` cleanups Pull it out into a separate file, make the conditional compilation more obvious and give the internal functions better names. Pulled out of #106311 r? cjgillot
2 parents e8c17de + db305d0 commit 70a665a

File tree

3 files changed

+190
-178
lines changed

3 files changed

+190
-178
lines changed

compiler/rustc_middle/src/lib.rs

+1
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@
4343
#![feature(min_specialization)]
4444
#![feature(trusted_len)]
4545
#![feature(type_alias_impl_trait)]
46+
#![feature(strict_provenance)]
4647
#![feature(associated_type_bounds)]
4748
#![feature(rustc_attrs)]
4849
#![feature(control_flow_enum)]

compiler/rustc_middle/src/ty/context.rs

+2-178
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@
22
33
#![allow(rustc::usage_of_ty_tykind)]
44

5+
pub mod tls;
6+
57
use crate::arena::Arena;
68
use crate::dep_graph::{DepGraph, DepKindStruct};
79
use crate::infer::canonical::{CanonicalVarInfo, CanonicalVarInfos};
@@ -1212,178 +1214,6 @@ CloneLiftImpls! { for<'tcx> {
12121214
Constness, traits::WellFormedLoc, ImplPolarity, crate::mir::ReturnConstraint,
12131215
} }
12141216

1215-
pub mod tls {
1216-
use super::{ptr_eq, GlobalCtxt, TyCtxt};
1217-
1218-
use crate::dep_graph::TaskDepsRef;
1219-
use crate::ty::query;
1220-
use rustc_data_structures::sync::{self, Lock};
1221-
use rustc_errors::Diagnostic;
1222-
use std::mem;
1223-
use thin_vec::ThinVec;
1224-
1225-
#[cfg(not(parallel_compiler))]
1226-
use std::cell::Cell;
1227-
1228-
#[cfg(parallel_compiler)]
1229-
use rustc_rayon_core as rayon_core;
1230-
1231-
/// This is the implicit state of rustc. It contains the current
1232-
/// `TyCtxt` and query. It is updated when creating a local interner or
1233-
/// executing a new query. Whenever there's a `TyCtxt` value available
1234-
/// you should also have access to an `ImplicitCtxt` through the functions
1235-
/// in this module.
1236-
#[derive(Clone)]
1237-
pub struct ImplicitCtxt<'a, 'tcx> {
1238-
/// The current `TyCtxt`.
1239-
pub tcx: TyCtxt<'tcx>,
1240-
1241-
/// The current query job, if any. This is updated by `JobOwner::start` in
1242-
/// `ty::query::plumbing` when executing a query.
1243-
pub query: Option<query::QueryJobId>,
1244-
1245-
/// Where to store diagnostics for the current query job, if any.
1246-
/// This is updated by `JobOwner::start` in `ty::query::plumbing` when executing a query.
1247-
pub diagnostics: Option<&'a Lock<ThinVec<Diagnostic>>>,
1248-
1249-
/// Used to prevent queries from calling too deeply.
1250-
pub query_depth: usize,
1251-
1252-
/// The current dep graph task. This is used to add dependencies to queries
1253-
/// when executing them.
1254-
pub task_deps: TaskDepsRef<'a>,
1255-
}
1256-
1257-
impl<'a, 'tcx> ImplicitCtxt<'a, 'tcx> {
1258-
pub fn new(gcx: &'tcx GlobalCtxt<'tcx>) -> Self {
1259-
let tcx = TyCtxt { gcx };
1260-
ImplicitCtxt {
1261-
tcx,
1262-
query: None,
1263-
diagnostics: None,
1264-
query_depth: 0,
1265-
task_deps: TaskDepsRef::Ignore,
1266-
}
1267-
}
1268-
}
1269-
1270-
/// Sets Rayon's thread-local variable, which is preserved for Rayon jobs
1271-
/// to `value` during the call to `f`. It is restored to its previous value after.
1272-
/// This is used to set the pointer to the new `ImplicitCtxt`.
1273-
#[cfg(parallel_compiler)]
1274-
#[inline]
1275-
fn set_tlv<F: FnOnce() -> R, R>(value: usize, f: F) -> R {
1276-
rayon_core::tlv::with(value, f)
1277-
}
1278-
1279-
/// Gets Rayon's thread-local variable, which is preserved for Rayon jobs.
1280-
/// This is used to get the pointer to the current `ImplicitCtxt`.
1281-
#[cfg(parallel_compiler)]
1282-
#[inline]
1283-
pub fn get_tlv() -> usize {
1284-
rayon_core::tlv::get()
1285-
}
1286-
1287-
#[cfg(not(parallel_compiler))]
1288-
thread_local! {
1289-
/// A thread local variable that stores a pointer to the current `ImplicitCtxt`.
1290-
static TLV: Cell<usize> = const { Cell::new(0) };
1291-
}
1292-
1293-
/// Sets TLV to `value` during the call to `f`.
1294-
/// It is restored to its previous value after.
1295-
/// This is used to set the pointer to the new `ImplicitCtxt`.
1296-
#[cfg(not(parallel_compiler))]
1297-
#[inline]
1298-
fn set_tlv<F: FnOnce() -> R, R>(value: usize, f: F) -> R {
1299-
let old = get_tlv();
1300-
let _reset = rustc_data_structures::OnDrop(move || TLV.with(|tlv| tlv.set(old)));
1301-
TLV.with(|tlv| tlv.set(value));
1302-
f()
1303-
}
1304-
1305-
/// Gets the pointer to the current `ImplicitCtxt`.
1306-
#[cfg(not(parallel_compiler))]
1307-
#[inline]
1308-
fn get_tlv() -> usize {
1309-
TLV.with(|tlv| tlv.get())
1310-
}
1311-
1312-
/// Sets `context` as the new current `ImplicitCtxt` for the duration of the function `f`.
1313-
#[inline]
1314-
pub fn enter_context<'a, 'tcx, F, R>(context: &ImplicitCtxt<'a, 'tcx>, f: F) -> R
1315-
where
1316-
F: FnOnce(&ImplicitCtxt<'a, 'tcx>) -> R,
1317-
{
1318-
set_tlv(context as *const _ as usize, || f(&context))
1319-
}
1320-
1321-
/// Allows access to the current `ImplicitCtxt` in a closure if one is available.
1322-
#[inline]
1323-
pub fn with_context_opt<F, R>(f: F) -> R
1324-
where
1325-
F: for<'a, 'tcx> FnOnce(Option<&ImplicitCtxt<'a, 'tcx>>) -> R,
1326-
{
1327-
let context = get_tlv();
1328-
if context == 0 {
1329-
f(None)
1330-
} else {
1331-
// We could get an `ImplicitCtxt` pointer from another thread.
1332-
// Ensure that `ImplicitCtxt` is `Sync`.
1333-
sync::assert_sync::<ImplicitCtxt<'_, '_>>();
1334-
1335-
unsafe { f(Some(&*(context as *const ImplicitCtxt<'_, '_>))) }
1336-
}
1337-
}
1338-
1339-
/// Allows access to the current `ImplicitCtxt`.
1340-
/// Panics if there is no `ImplicitCtxt` available.
1341-
#[inline]
1342-
pub fn with_context<F, R>(f: F) -> R
1343-
where
1344-
F: for<'a, 'tcx> FnOnce(&ImplicitCtxt<'a, 'tcx>) -> R,
1345-
{
1346-
with_context_opt(|opt_context| f(opt_context.expect("no ImplicitCtxt stored in tls")))
1347-
}
1348-
1349-
/// Allows access to the current `ImplicitCtxt` whose tcx field is the same as the tcx argument
1350-
/// passed in. This means the closure is given an `ImplicitCtxt` with the same `'tcx` lifetime
1351-
/// as the `TyCtxt` passed in.
1352-
/// This will panic if you pass it a `TyCtxt` which is different from the current
1353-
/// `ImplicitCtxt`'s `tcx` field.
1354-
#[inline]
1355-
pub fn with_related_context<'tcx, F, R>(tcx: TyCtxt<'tcx>, f: F) -> R
1356-
where
1357-
F: FnOnce(&ImplicitCtxt<'_, 'tcx>) -> R,
1358-
{
1359-
with_context(|context| unsafe {
1360-
assert!(ptr_eq(context.tcx.gcx, tcx.gcx));
1361-
let context: &ImplicitCtxt<'_, '_> = mem::transmute(context);
1362-
f(context)
1363-
})
1364-
}
1365-
1366-
/// Allows access to the `TyCtxt` in the current `ImplicitCtxt`.
1367-
/// Panics if there is no `ImplicitCtxt` available.
1368-
#[inline]
1369-
pub fn with<F, R>(f: F) -> R
1370-
where
1371-
F: for<'tcx> FnOnce(TyCtxt<'tcx>) -> R,
1372-
{
1373-
with_context(|context| f(context.tcx))
1374-
}
1375-
1376-
/// Allows access to the `TyCtxt` in the current `ImplicitCtxt`.
1377-
/// The closure is passed None if there is no `ImplicitCtxt` available.
1378-
#[inline]
1379-
pub fn with_opt<F, R>(f: F) -> R
1380-
where
1381-
F: for<'tcx> FnOnce(Option<TyCtxt<'tcx>>) -> R,
1382-
{
1383-
with_context_opt(|opt_context| f(opt_context.map(|context| context.tcx)))
1384-
}
1385-
}
1386-
13871217
macro_rules! sty_debug_print {
13881218
($fmt: expr, $ctxt: expr, $($variant: ident),*) => {{
13891219
// Curious inner module to allow variant names to be used as
@@ -2416,12 +2246,6 @@ pub struct DeducedParamAttrs {
24162246
pub read_only: bool,
24172247
}
24182248

2419-
// We are comparing types with different invariant lifetimes, so `ptr::eq`
2420-
// won't work for us.
2421-
fn ptr_eq<T, U>(t: *const T, u: *const U) -> bool {
2422-
t as *const () == u as *const ()
2423-
}
2424-
24252249
pub fn provide(providers: &mut ty::query::Providers) {
24262250
providers.module_reexports =
24272251
|tcx, id| tcx.resolutions(()).reexport_map.get(&id).map(|v| &v[..]);
+187
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,187 @@
1+
use super::{GlobalCtxt, TyCtxt};
2+
3+
use crate::dep_graph::TaskDepsRef;
4+
use crate::ty::query;
5+
use rustc_data_structures::sync::{self, Lock};
6+
use rustc_errors::Diagnostic;
7+
use std::mem;
8+
use std::ptr;
9+
use thin_vec::ThinVec;
10+
11+
/// This is the implicit state of rustc. It contains the current
12+
/// `TyCtxt` and query. It is updated when creating a local interner or
13+
/// executing a new query. Whenever there's a `TyCtxt` value available
14+
/// you should also have access to an `ImplicitCtxt` through the functions
15+
/// in this module.
16+
#[derive(Clone)]
17+
pub struct ImplicitCtxt<'a, 'tcx> {
18+
/// The current `TyCtxt`.
19+
pub tcx: TyCtxt<'tcx>,
20+
21+
/// The current query job, if any. This is updated by `JobOwner::start` in
22+
/// `ty::query::plumbing` when executing a query.
23+
pub query: Option<query::QueryJobId>,
24+
25+
/// Where to store diagnostics for the current query job, if any.
26+
/// This is updated by `JobOwner::start` in `ty::query::plumbing` when executing a query.
27+
pub diagnostics: Option<&'a Lock<ThinVec<Diagnostic>>>,
28+
29+
/// Used to prevent queries from calling too deeply.
30+
pub query_depth: usize,
31+
32+
/// The current dep graph task. This is used to add dependencies to queries
33+
/// when executing them.
34+
pub task_deps: TaskDepsRef<'a>,
35+
}
36+
37+
impl<'a, 'tcx> ImplicitCtxt<'a, 'tcx> {
38+
pub fn new(gcx: &'tcx GlobalCtxt<'tcx>) -> Self {
39+
let tcx = TyCtxt { gcx };
40+
ImplicitCtxt {
41+
tcx,
42+
query: None,
43+
diagnostics: None,
44+
query_depth: 0,
45+
task_deps: TaskDepsRef::Ignore,
46+
}
47+
}
48+
}
49+
50+
#[cfg(parallel_compiler)]
51+
mod tlv {
52+
use rustc_rayon_core as rayon_core;
53+
use std::ptr;
54+
55+
/// Gets Rayon's thread-local variable, which is preserved for Rayon jobs.
56+
/// This is used to get the pointer to the current `ImplicitCtxt`.
57+
#[inline]
58+
pub(super) fn get_tlv() -> *const () {
59+
ptr::from_exposed_addr(rayon_core::tlv::get())
60+
}
61+
62+
/// Sets Rayon's thread-local variable, which is preserved for Rayon jobs
63+
/// to `value` during the call to `f`. It is restored to its previous value after.
64+
/// This is used to set the pointer to the new `ImplicitCtxt`.
65+
#[inline]
66+
pub(super) fn with_tlv<F: FnOnce() -> R, R>(value: *const (), f: F) -> R {
67+
rayon_core::tlv::with(value.expose_addr(), f)
68+
}
69+
}
70+
71+
#[cfg(not(parallel_compiler))]
72+
mod tlv {
73+
use std::cell::Cell;
74+
use std::ptr;
75+
76+
thread_local! {
77+
/// A thread local variable that stores a pointer to the current `ImplicitCtxt`.
78+
static TLV: Cell<*const ()> = const { Cell::new(ptr::null()) };
79+
}
80+
81+
/// Gets the pointer to the current `ImplicitCtxt`.
82+
#[inline]
83+
pub(super) fn get_tlv() -> *const () {
84+
TLV.with(|tlv| tlv.get())
85+
}
86+
87+
/// Sets TLV to `value` during the call to `f`.
88+
/// It is restored to its previous value after.
89+
/// This is used to set the pointer to the new `ImplicitCtxt`.
90+
#[inline]
91+
pub(super) fn with_tlv<F: FnOnce() -> R, R>(value: *const (), f: F) -> R {
92+
let old = get_tlv();
93+
let _reset = rustc_data_structures::OnDrop(move || TLV.with(|tlv| tlv.set(old)));
94+
TLV.with(|tlv| tlv.set(value));
95+
f()
96+
}
97+
}
98+
99+
#[inline]
100+
fn erase(context: &ImplicitCtxt<'_, '_>) -> *const () {
101+
context as *const _ as *const ()
102+
}
103+
104+
#[inline]
105+
unsafe fn downcast<'a, 'tcx>(context: *const ()) -> &'a ImplicitCtxt<'a, 'tcx> {
106+
&*(context as *const ImplicitCtxt<'a, 'tcx>)
107+
}
108+
109+
/// Sets `context` as the new current `ImplicitCtxt` for the duration of the function `f`.
110+
#[inline]
111+
pub fn enter_context<'a, 'tcx, F, R>(context: &ImplicitCtxt<'a, 'tcx>, f: F) -> R
112+
where
113+
F: FnOnce(&ImplicitCtxt<'a, 'tcx>) -> R,
114+
{
115+
tlv::with_tlv(erase(context), || f(&context))
116+
}
117+
118+
/// Allows access to the current `ImplicitCtxt` in a closure if one is available.
119+
#[inline]
120+
pub fn with_context_opt<F, R>(f: F) -> R
121+
where
122+
F: for<'a, 'tcx> FnOnce(Option<&ImplicitCtxt<'a, 'tcx>>) -> R,
123+
{
124+
let context = tlv::get_tlv();
125+
if context.is_null() {
126+
f(None)
127+
} else {
128+
// We could get an `ImplicitCtxt` pointer from another thread.
129+
// Ensure that `ImplicitCtxt` is `Sync`.
130+
sync::assert_sync::<ImplicitCtxt<'_, '_>>();
131+
132+
unsafe { f(Some(downcast(context))) }
133+
}
134+
}
135+
136+
/// Allows access to the current `ImplicitCtxt`.
137+
/// Panics if there is no `ImplicitCtxt` available.
138+
#[inline]
139+
pub fn with_context<F, R>(f: F) -> R
140+
where
141+
F: for<'a, 'tcx> FnOnce(&ImplicitCtxt<'a, 'tcx>) -> R,
142+
{
143+
with_context_opt(|opt_context| f(opt_context.expect("no ImplicitCtxt stored in tls")))
144+
}
145+
146+
/// Allows access to the current `ImplicitCtxt` whose tcx field is the same as the tcx argument
147+
/// passed in. This means the closure is given an `ImplicitCtxt` with the same `'tcx` lifetime
148+
/// as the `TyCtxt` passed in.
149+
/// This will panic if you pass it a `TyCtxt` which is different from the current
150+
/// `ImplicitCtxt`'s `tcx` field.
151+
#[inline]
152+
pub fn with_related_context<'tcx, F, R>(tcx: TyCtxt<'tcx>, f: F) -> R
153+
where
154+
F: FnOnce(&ImplicitCtxt<'_, 'tcx>) -> R,
155+
{
156+
with_context(|context| {
157+
// The two gcx have different invariant lifetimes, so we need to erase them for the comparison.
158+
assert!(ptr::eq(
159+
context.tcx.gcx as *const _ as *const (),
160+
tcx.gcx as *const _ as *const ()
161+
));
162+
163+
let context: &ImplicitCtxt<'_, '_> = unsafe { mem::transmute(context) };
164+
165+
f(context)
166+
})
167+
}
168+
169+
/// Allows access to the `TyCtxt` in the current `ImplicitCtxt`.
170+
/// Panics if there is no `ImplicitCtxt` available.
171+
#[inline]
172+
pub fn with<F, R>(f: F) -> R
173+
where
174+
F: for<'tcx> FnOnce(TyCtxt<'tcx>) -> R,
175+
{
176+
with_context(|context| f(context.tcx))
177+
}
178+
179+
/// Allows access to the `TyCtxt` in the current `ImplicitCtxt`.
180+
/// The closure is passed None if there is no `ImplicitCtxt` available.
181+
#[inline]
182+
pub fn with_opt<F, R>(f: F) -> R
183+
where
184+
F: for<'tcx> FnOnce(Option<TyCtxt<'tcx>>) -> R,
185+
{
186+
with_context_opt(|opt_context| f(opt_context.map(|context| context.tcx)))
187+
}

0 commit comments

Comments
 (0)