]> git.proxmox.com Git - rustc.git/blame - compiler/rustc_middle/src/ty/context/tls.rs
New upstream version 1.70.0+dfsg1
[rustc.git] / compiler / rustc_middle / src / ty / context / tls.rs
CommitLineData
9ffffee4
FG
1use super::{GlobalCtxt, TyCtxt};
2
3use crate::dep_graph::TaskDepsRef;
4use crate::ty::query;
5use rustc_data_structures::sync::{self, Lock};
6use rustc_errors::Diagnostic;
353b0b11
FG
7#[cfg(not(parallel_compiler))]
8use std::cell::Cell;
9ffffee4
FG
9use std::mem;
10use std::ptr;
11use thin_vec::ThinVec;
12
13/// This is the implicit state of rustc. It contains the current
14/// `TyCtxt` and query. It is updated when creating a local interner or
15/// executing a new query. Whenever there's a `TyCtxt` value available
16/// you should also have access to an `ImplicitCtxt` through the functions
17/// in this module.
18#[derive(Clone)]
19pub struct ImplicitCtxt<'a, 'tcx> {
20 /// The current `TyCtxt`.
21 pub tcx: TyCtxt<'tcx>,
22
23 /// The current query job, if any. This is updated by `JobOwner::start` in
24 /// `ty::query::plumbing` when executing a query.
25 pub query: Option<query::QueryJobId>,
26
27 /// Where to store diagnostics for the current query job, if any.
28 /// This is updated by `JobOwner::start` in `ty::query::plumbing` when executing a query.
29 pub diagnostics: Option<&'a Lock<ThinVec<Diagnostic>>>,
30
31 /// Used to prevent queries from calling too deeply.
32 pub query_depth: usize,
33
34 /// The current dep graph task. This is used to add dependencies to queries
35 /// when executing them.
36 pub task_deps: TaskDepsRef<'a>,
37}
38
39impl<'a, 'tcx> ImplicitCtxt<'a, 'tcx> {
40 pub fn new(gcx: &'tcx GlobalCtxt<'tcx>) -> Self {
41 let tcx = TyCtxt { gcx };
42 ImplicitCtxt {
43 tcx,
44 query: None,
45 diagnostics: None,
46 query_depth: 0,
47 task_deps: TaskDepsRef::Ignore,
48 }
49 }
50}
51
353b0b11 52// Import the thread-local variable from Rayon, which is preserved for Rayon jobs.
9ffffee4 53#[cfg(parallel_compiler)]
353b0b11 54use rayon_core::tlv::TLV;
9ffffee4 55
353b0b11 56// Otherwise define our own
9ffffee4 57#[cfg(not(parallel_compiler))]
353b0b11
FG
58thread_local! {
59 /// A thread local variable that stores a pointer to the current `ImplicitCtxt`.
60 static TLV: Cell<*const ()> = const { Cell::new(ptr::null()) };
9ffffee4
FG
61}
62
63#[inline]
64fn erase(context: &ImplicitCtxt<'_, '_>) -> *const () {
65 context as *const _ as *const ()
66}
67
68#[inline]
69unsafe fn downcast<'a, 'tcx>(context: *const ()) -> &'a ImplicitCtxt<'a, 'tcx> {
70 &*(context as *const ImplicitCtxt<'a, 'tcx>)
71}
72
73/// Sets `context` as the new current `ImplicitCtxt` for the duration of the function `f`.
74#[inline]
75pub fn enter_context<'a, 'tcx, F, R>(context: &ImplicitCtxt<'a, 'tcx>, f: F) -> R
76where
77 F: FnOnce() -> R,
78{
353b0b11
FG
79 TLV.with(|tlv| {
80 let old = tlv.replace(erase(context));
81 let _reset = rustc_data_structures::OnDrop(move || tlv.set(old));
82 f()
83 })
9ffffee4
FG
84}
85
86/// Allows access to the current `ImplicitCtxt` in a closure if one is available.
87#[inline]
88pub fn with_context_opt<F, R>(f: F) -> R
89where
90 F: for<'a, 'tcx> FnOnce(Option<&ImplicitCtxt<'a, 'tcx>>) -> R,
91{
353b0b11 92 let context = TLV.get();
9ffffee4
FG
93 if context.is_null() {
94 f(None)
95 } else {
96 // We could get an `ImplicitCtxt` pointer from another thread.
97 // Ensure that `ImplicitCtxt` is `Sync`.
98 sync::assert_sync::<ImplicitCtxt<'_, '_>>();
99
100 unsafe { f(Some(downcast(context))) }
101 }
102}
103
104/// Allows access to the current `ImplicitCtxt`.
105/// Panics if there is no `ImplicitCtxt` available.
106#[inline]
107pub fn with_context<F, R>(f: F) -> R
108where
109 F: for<'a, 'tcx> FnOnce(&ImplicitCtxt<'a, 'tcx>) -> R,
110{
111 with_context_opt(|opt_context| f(opt_context.expect("no ImplicitCtxt stored in tls")))
112}
113
114/// Allows access to the current `ImplicitCtxt` whose tcx field is the same as the tcx argument
115/// passed in. This means the closure is given an `ImplicitCtxt` with the same `'tcx` lifetime
116/// as the `TyCtxt` passed in.
117/// This will panic if you pass it a `TyCtxt` which is different from the current
118/// `ImplicitCtxt`'s `tcx` field.
119#[inline]
120pub fn with_related_context<'tcx, F, R>(tcx: TyCtxt<'tcx>, f: F) -> R
121where
122 F: FnOnce(&ImplicitCtxt<'_, 'tcx>) -> R,
123{
124 with_context(|context| {
125 // The two gcx have different invariant lifetimes, so we need to erase them for the comparison.
126 assert!(ptr::eq(
127 context.tcx.gcx as *const _ as *const (),
128 tcx.gcx as *const _ as *const ()
129 ));
130
131 let context: &ImplicitCtxt<'_, '_> = unsafe { mem::transmute(context) };
132
133 f(context)
134 })
135}
136
137/// Allows access to the `TyCtxt` in the current `ImplicitCtxt`.
138/// Panics if there is no `ImplicitCtxt` available.
139#[inline]
140pub fn with<F, R>(f: F) -> R
141where
142 F: for<'tcx> FnOnce(TyCtxt<'tcx>) -> R,
143{
144 with_context(|context| f(context.tcx))
145}
146
147/// Allows access to the `TyCtxt` in the current `ImplicitCtxt`.
148/// The closure is passed None if there is no `ImplicitCtxt` available.
149#[inline]
150pub fn with_opt<F, R>(f: F) -> R
151where
152 F: for<'tcx> FnOnce(Option<TyCtxt<'tcx>>) -> R,
153{
154 with_context_opt(|opt_context| f(opt_context.map(|context| context.tcx)))
155}