From 3e3e70d529d8c7d7c4d7bc4fefc9f109393b9245 Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Wed, 17 Apr 2024 14:19:43 +0200 Subject: Merging upstream version 1.69.0+dfsg1. Signed-off-by: Daniel Baumann --- compiler/rustc_middle/src/ty/context/tls.rs | 186 ++++++++++++++++++++++++++++ 1 file changed, 186 insertions(+) create mode 100644 compiler/rustc_middle/src/ty/context/tls.rs (limited to 'compiler/rustc_middle/src/ty/context/tls.rs') diff --git a/compiler/rustc_middle/src/ty/context/tls.rs b/compiler/rustc_middle/src/ty/context/tls.rs new file mode 100644 index 000000000..5426ac8d7 --- /dev/null +++ b/compiler/rustc_middle/src/ty/context/tls.rs @@ -0,0 +1,186 @@ +use super::{GlobalCtxt, TyCtxt}; + +use crate::dep_graph::TaskDepsRef; +use crate::ty::query; +use rustc_data_structures::sync::{self, Lock}; +use rustc_errors::Diagnostic; +use std::mem; +use std::ptr; +use thin_vec::ThinVec; + +/// This is the implicit state of rustc. It contains the current +/// `TyCtxt` and query. It is updated when creating a local interner or +/// executing a new query. Whenever there's a `TyCtxt` value available +/// you should also have access to an `ImplicitCtxt` through the functions +/// in this module. +#[derive(Clone)] +pub struct ImplicitCtxt<'a, 'tcx> { + /// The current `TyCtxt`. + pub tcx: TyCtxt<'tcx>, + + /// The current query job, if any. This is updated by `JobOwner::start` in + /// `ty::query::plumbing` when executing a query. + pub query: Option, + + /// Where to store diagnostics for the current query job, if any. + /// This is updated by `JobOwner::start` in `ty::query::plumbing` when executing a query. + pub diagnostics: Option<&'a Lock>>, + + /// Used to prevent queries from calling too deeply. + pub query_depth: usize, + + /// The current dep graph task. This is used to add dependencies to queries + /// when executing them. + pub task_deps: TaskDepsRef<'a>, +} + +impl<'a, 'tcx> ImplicitCtxt<'a, 'tcx> { + pub fn new(gcx: &'tcx GlobalCtxt<'tcx>) -> Self { + let tcx = TyCtxt { gcx }; + ImplicitCtxt { + tcx, + query: None, + diagnostics: None, + query_depth: 0, + task_deps: TaskDepsRef::Ignore, + } + } +} + +#[cfg(parallel_compiler)] +mod tlv { + use rustc_rayon_core as rayon_core; + use std::ptr; + + /// Gets Rayon's thread-local variable, which is preserved for Rayon jobs. + /// This is used to get the pointer to the current `ImplicitCtxt`. + #[inline] + pub(super) fn get_tlv() -> *const () { + ptr::from_exposed_addr(rayon_core::tlv::get()) + } + + /// Sets Rayon's thread-local variable, which is preserved for Rayon jobs + /// to `value` during the call to `f`. It is restored to its previous value after. + /// This is used to set the pointer to the new `ImplicitCtxt`. + #[inline] + pub(super) fn with_tlv R, R>(value: *const (), f: F) -> R { + rayon_core::tlv::with(value.expose_addr(), f) + } +} + +#[cfg(not(parallel_compiler))] +mod tlv { + use std::cell::Cell; + use std::ptr; + + thread_local! { + /// A thread local variable that stores a pointer to the current `ImplicitCtxt`. + static TLV: Cell<*const ()> = const { Cell::new(ptr::null()) }; + } + + /// Gets the pointer to the current `ImplicitCtxt`. + #[inline] + pub(super) fn get_tlv() -> *const () { + TLV.with(|tlv| tlv.get()) + } + + /// Sets TLV to `value` during the call to `f`. + /// It is restored to its previous value after. + /// This is used to set the pointer to the new `ImplicitCtxt`. + #[inline] + pub(super) fn with_tlv R, R>(value: *const (), f: F) -> R { + let old = TLV.replace(value); + let _reset = rustc_data_structures::OnDrop(move || TLV.set(old)); + f() + } +} + +#[inline] +fn erase(context: &ImplicitCtxt<'_, '_>) -> *const () { + context as *const _ as *const () +} + +#[inline] +unsafe fn downcast<'a, 'tcx>(context: *const ()) -> &'a ImplicitCtxt<'a, 'tcx> { + &*(context as *const ImplicitCtxt<'a, 'tcx>) +} + +/// Sets `context` as the new current `ImplicitCtxt` for the duration of the function `f`. +#[inline] +pub fn enter_context<'a, 'tcx, F, R>(context: &ImplicitCtxt<'a, 'tcx>, f: F) -> R +where + F: FnOnce() -> R, +{ + tlv::with_tlv(erase(context), f) +} + +/// Allows access to the current `ImplicitCtxt` in a closure if one is available. +#[inline] +pub fn with_context_opt(f: F) -> R +where + F: for<'a, 'tcx> FnOnce(Option<&ImplicitCtxt<'a, 'tcx>>) -> R, +{ + let context = tlv::get_tlv(); + if context.is_null() { + f(None) + } else { + // We could get an `ImplicitCtxt` pointer from another thread. + // Ensure that `ImplicitCtxt` is `Sync`. + sync::assert_sync::>(); + + unsafe { f(Some(downcast(context))) } + } +} + +/// Allows access to the current `ImplicitCtxt`. +/// Panics if there is no `ImplicitCtxt` available. +#[inline] +pub fn with_context(f: F) -> R +where + F: for<'a, 'tcx> FnOnce(&ImplicitCtxt<'a, 'tcx>) -> R, +{ + with_context_opt(|opt_context| f(opt_context.expect("no ImplicitCtxt stored in tls"))) +} + +/// Allows access to the current `ImplicitCtxt` whose tcx field is the same as the tcx argument +/// passed in. This means the closure is given an `ImplicitCtxt` with the same `'tcx` lifetime +/// as the `TyCtxt` passed in. +/// This will panic if you pass it a `TyCtxt` which is different from the current +/// `ImplicitCtxt`'s `tcx` field. +#[inline] +pub fn with_related_context<'tcx, F, R>(tcx: TyCtxt<'tcx>, f: F) -> R +where + F: FnOnce(&ImplicitCtxt<'_, 'tcx>) -> R, +{ + with_context(|context| { + // The two gcx have different invariant lifetimes, so we need to erase them for the comparison. + assert!(ptr::eq( + context.tcx.gcx as *const _ as *const (), + tcx.gcx as *const _ as *const () + )); + + let context: &ImplicitCtxt<'_, '_> = unsafe { mem::transmute(context) }; + + f(context) + }) +} + +/// Allows access to the `TyCtxt` in the current `ImplicitCtxt`. +/// Panics if there is no `ImplicitCtxt` available. +#[inline] +pub fn with(f: F) -> R +where + F: for<'tcx> FnOnce(TyCtxt<'tcx>) -> R, +{ + with_context(|context| f(context.tcx)) +} + +/// Allows access to the `TyCtxt` in the current `ImplicitCtxt`. +/// The closure is passed None if there is no `ImplicitCtxt` available. +#[inline] +pub fn with_opt(f: F) -> R +where + F: for<'tcx> FnOnce(Option>) -> R, +{ + with_context_opt(|opt_context| f(opt_context.map(|context| context.tcx))) +} -- cgit v1.2.3