rustc_interface/
callbacks.rs

1//! Throughout the compiler tree, there are several places which want to have
2//! access to state or queries while being inside crates that are dependencies
3//! of `rustc_middle`. To facilitate this, we have the
4//! `rustc_data_structures::AtomicRef` type, which allows us to setup a global
5//! static which can then be set in this file at program startup.
6//!
7//! See `SPAN_TRACK` for an example of how to set things up.
8//!
9//! The functions in this file should fall back to the default set in their
10//! origin crate when the `TyCtxt` is not present in TLS.
11
12use std::fmt;
13
14use rustc_errors::{DiagInner, TRACK_DIAGNOSTIC};
15use rustc_middle::dep_graph::{DepNodeExt, TaskDepsRef};
16use rustc_middle::ty::tls;
17use rustc_query_impl::QueryCtxt;
18use rustc_query_system::dep_graph::dep_node::default_dep_kind_debug;
19use rustc_query_system::dep_graph::{DepContext, DepKind, DepNode};
20
21fn track_span_parent(def_id: rustc_span::def_id::LocalDefId) {
22    tls::with_context_opt(|icx| {
23        if let Some(icx) = icx {
24            // `track_span_parent` gets called a lot from HIR lowering code.
25            // Skip doing anything if we aren't tracking dependencies.
26            let tracks_deps = match icx.task_deps {
27                TaskDepsRef::Allow(..) => true,
28                TaskDepsRef::EvalAlways | TaskDepsRef::Ignore | TaskDepsRef::Forbid => false,
29            };
30            if tracks_deps {
31                let _span = icx.tcx.source_span(def_id);
32                // Sanity check: relative span's parent must be an absolute span.
33                debug_assert_eq!(_span.data_untracked().parent, None);
34            }
35        }
36    })
37}
38
39/// This is a callback from `rustc_errors` as it cannot access the implicit state
40/// in `rustc_middle` otherwise. It is used when diagnostic messages are
41/// emitted and stores them in the current query, if there is one.
42fn track_diagnostic<R>(diagnostic: DiagInner, f: &mut dyn FnMut(DiagInner) -> R) -> R {
43    tls::with_context_opt(|icx| {
44        if let Some(icx) = icx {
45            icx.tcx.dep_graph.record_diagnostic(QueryCtxt::new(icx.tcx), &diagnostic);
46
47            // Diagnostics are tracked, we can ignore the dependency.
48            let icx = tls::ImplicitCtxt { task_deps: TaskDepsRef::Ignore, ..icx.clone() };
49            tls::enter_context(&icx, move || (*f)(diagnostic))
50        } else {
51            // In any other case, invoke diagnostics anyway.
52            (*f)(diagnostic)
53        }
54    })
55}
56
57/// This is a callback from `rustc_hir` as it cannot access the implicit state
58/// in `rustc_middle` otherwise.
59fn def_id_debug(def_id: rustc_hir::def_id::DefId, f: &mut fmt::Formatter<'_>) -> fmt::Result {
60    write!(f, "DefId({}:{}", def_id.krate, def_id.index.index())?;
61    tls::with_opt(|opt_tcx| {
62        if let Some(tcx) = opt_tcx {
63            write!(f, " ~ {}", tcx.def_path_debug_str(def_id))?;
64        }
65        Ok(())
66    })?;
67    write!(f, ")")
68}
69
70/// This is a callback from `rustc_query_system` as it cannot access the implicit state
71/// in `rustc_middle` otherwise.
72pub fn dep_kind_debug(kind: DepKind, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
73    tls::with_opt(|opt_tcx| {
74        if let Some(tcx) = opt_tcx {
75            write!(f, "{}", tcx.dep_kind_info(kind).name)
76        } else {
77            default_dep_kind_debug(kind, f)
78        }
79    })
80}
81
82/// This is a callback from `rustc_query_system` as it cannot access the implicit state
83/// in `rustc_middle` otherwise.
84pub fn dep_node_debug(node: DepNode, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
85    write!(f, "{:?}(", node.kind)?;
86
87    tls::with_opt(|opt_tcx| {
88        if let Some(tcx) = opt_tcx {
89            if let Some(def_id) = node.extract_def_id(tcx) {
90                write!(f, "{}", tcx.def_path_debug_str(def_id))?;
91            } else if let Some(ref s) = tcx.dep_graph.dep_node_debug_str(node) {
92                write!(f, "{s}")?;
93            } else {
94                write!(f, "{}", node.hash)?;
95            }
96        } else {
97            write!(f, "{}", node.hash)?;
98        }
99        Ok(())
100    })?;
101
102    write!(f, ")")
103}
104
105/// Sets up the callbacks in prior crates which we want to refer to the
106/// TyCtxt in.
107pub fn setup_callbacks() {
108    rustc_span::SPAN_TRACK.swap(&(track_span_parent as fn(_)));
109    rustc_hir::def_id::DEF_ID_DEBUG.swap(&(def_id_debug as fn(_, &mut fmt::Formatter<'_>) -> _));
110    rustc_query_system::dep_graph::dep_node::DEP_KIND_DEBUG
111        .swap(&(dep_kind_debug as fn(_, &mut fmt::Formatter<'_>) -> _));
112    rustc_query_system::dep_graph::dep_node::DEP_NODE_DEBUG
113        .swap(&(dep_node_debug as fn(_, &mut fmt::Formatter<'_>) -> _));
114    TRACK_DIAGNOSTIC.swap(&(track_diagnostic as _));
115}
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy