Rollup merge of #145354 - cache-proc-derive-macros, r=petrochenkov
Cache derive proc macro expansion with incremental query
This is a revival of https://github.com/rust-lang/rust/pull/129102, originally implemented by @futile. Since it looks like they are not active currently, I'd like to push this work forward.
The first commit is squashed and rebased work from the original PR, with author attribution to futile. The rest of the commits are some additional comments that I created mostly for myself to understand what happens here. I also did some cleanups based on Vadim's review comments on the original PR, plus I refactored the TLS access a bit using `scoped_tls`.
The biggest issue, as usually, are tests... I tried using `#[rustc_clean(..., loaded_from_disk = "derive_macro_expansion")]`, but the problem is that since this query cannot recover the original key from its hash, and thus its fingerprintstyle is `FingerprintStyle::Opaque`, [this](2fef0a30ae/compiler/rustc_incremental/src/persist/dirty_clean.rs (L388)) crashes when I try to use `loaded_from_disk`. Any suggestions from someone who actually understands the query system would be welcome 😅
TODO: document the new unstable flag
On a no-op change re-check of `octocrab 0.49` (which has a ton of `serde` derive proc macro invocations), this saves ~0.6s out of ~6s (so a ~10% win) on my PC.
r? @petrochenkov
This commit is contained in:
commit
81cc29a425
21 changed files with 284 additions and 72 deletions
|
|
@ -3348,7 +3348,8 @@ impl UseTree {
|
|||
/// Distinguishes between `Attribute`s that decorate items and Attributes that
|
||||
/// are contained as statements within items. These two cases need to be
|
||||
/// distinguished for pretty-printing.
|
||||
#[derive(Clone, PartialEq, Encodable, Decodable, Debug, Copy, HashStable_Generic, Walkable)]
|
||||
#[derive(Clone, PartialEq, Eq, Hash, Debug, Copy)]
|
||||
#[derive(Encodable, Decodable, HashStable_Generic, Walkable)]
|
||||
pub enum AttrStyle {
|
||||
Outer,
|
||||
Inner,
|
||||
|
|
|
|||
|
|
@ -40,13 +40,13 @@ impl DocFragmentKind {
|
|||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, PartialEq, Eq, Encodable, Decodable, Debug, HashStable_Generic)]
|
||||
#[derive(Clone, Copy, PartialEq, Eq, Hash, Encodable, Decodable, Debug, HashStable_Generic)]
|
||||
pub enum CommentKind {
|
||||
Line,
|
||||
Block,
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, PartialEq, Debug, Encodable, Decodable, HashStable_Generic)]
|
||||
#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug, Encodable, Decodable, HashStable_Generic)]
|
||||
pub enum InvisibleOrigin {
|
||||
// From the expansion of a metavariable in a declarative macro.
|
||||
MetaVar(MetaVarKind),
|
||||
|
|
@ -123,7 +123,7 @@ impl fmt::Display for MetaVarKind {
|
|||
/// Describes how a sequence of token trees is delimited.
|
||||
/// Cannot use `proc_macro::Delimiter` directly because this
|
||||
/// structure should implement some additional traits.
|
||||
#[derive(Copy, Clone, Debug, PartialEq, Encodable, Decodable, HashStable_Generic)]
|
||||
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Encodable, Decodable, HashStable_Generic)]
|
||||
pub enum Delimiter {
|
||||
/// `( ... )`
|
||||
Parenthesis,
|
||||
|
|
@ -186,7 +186,7 @@ impl Delimiter {
|
|||
// type. This means that float literals like `1f32` are classified by this type
|
||||
// as `Int`. Only upon conversion to `ast::LitKind` will such a literal be
|
||||
// given the `Float` kind.
|
||||
#[derive(Clone, Copy, PartialEq, Encodable, Decodable, Debug, HashStable_Generic)]
|
||||
#[derive(Clone, Copy, PartialEq, Eq, Hash, Encodable, Decodable, Debug, HashStable_Generic)]
|
||||
pub enum LitKind {
|
||||
Bool, // AST only, must never appear in a `Token`
|
||||
Byte,
|
||||
|
|
@ -203,7 +203,7 @@ pub enum LitKind {
|
|||
}
|
||||
|
||||
/// A literal token.
|
||||
#[derive(Clone, Copy, PartialEq, Encodable, Decodable, Debug, HashStable_Generic)]
|
||||
#[derive(Clone, Copy, PartialEq, Eq, Hash, Encodable, Decodable, Debug, HashStable_Generic)]
|
||||
pub struct Lit {
|
||||
pub kind: LitKind,
|
||||
pub symbol: Symbol,
|
||||
|
|
@ -349,7 +349,7 @@ fn ident_can_begin_type(name: Symbol, span: Span, is_raw: IdentIsRaw) -> bool {
|
|||
.contains(&name)
|
||||
}
|
||||
|
||||
#[derive(PartialEq, Encodable, Decodable, Debug, Copy, Clone, HashStable_Generic)]
|
||||
#[derive(PartialEq, Eq, Encodable, Decodable, Hash, Debug, Copy, Clone, HashStable_Generic)]
|
||||
pub enum IdentIsRaw {
|
||||
No,
|
||||
Yes,
|
||||
|
|
@ -376,7 +376,7 @@ impl From<bool> for IdentIsRaw {
|
|||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, PartialEq, Encodable, Decodable, Debug, HashStable_Generic)]
|
||||
#[derive(Clone, Copy, PartialEq, Eq, Hash, Encodable, Decodable, Debug, HashStable_Generic)]
|
||||
pub enum TokenKind {
|
||||
/* Expression-operator symbols. */
|
||||
/// `=`
|
||||
|
|
@ -526,7 +526,7 @@ pub enum TokenKind {
|
|||
Eof,
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, PartialEq, Encodable, Decodable, Debug, HashStable_Generic)]
|
||||
#[derive(Clone, Copy, PartialEq, Eq, Hash, Encodable, Decodable, Debug, HashStable_Generic)]
|
||||
pub struct Token {
|
||||
pub kind: TokenKind,
|
||||
pub span: Span,
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@
|
|||
//! which are themselves a single [`Token`] or a `Delimited` subsequence of tokens.
|
||||
|
||||
use std::borrow::Cow;
|
||||
use std::hash::Hash;
|
||||
use std::ops::Range;
|
||||
use std::sync::Arc;
|
||||
use std::{cmp, fmt, iter, mem};
|
||||
|
|
@ -22,7 +23,7 @@ use crate::token::{self, Delimiter, Token, TokenKind};
|
|||
use crate::{AttrVec, Attribute};
|
||||
|
||||
/// Part of a `TokenStream`.
|
||||
#[derive(Debug, Clone, PartialEq, Encodable, Decodable, HashStable_Generic)]
|
||||
#[derive(Debug, Clone, PartialEq, Eq, Hash, Encodable, Decodable, HashStable_Generic)]
|
||||
pub enum TokenTree {
|
||||
/// A single token. Should never be `OpenDelim` or `CloseDelim`, because
|
||||
/// delimiters are implicitly represented by `Delimited`.
|
||||
|
|
@ -538,7 +539,7 @@ pub struct AttrsTarget {
|
|||
/// compound token. Used for conversions to `proc_macro::Spacing`. Also used to
|
||||
/// guide pretty-printing, which is where the `JointHidden` value (which isn't
|
||||
/// part of `proc_macro::Spacing`) comes in useful.
|
||||
#[derive(Clone, Copy, Debug, PartialEq, Encodable, Decodable, HashStable_Generic)]
|
||||
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, Encodable, Decodable, HashStable_Generic)]
|
||||
pub enum Spacing {
|
||||
/// The token cannot join with the following token to form a compound
|
||||
/// token.
|
||||
|
|
@ -595,7 +596,7 @@ pub enum Spacing {
|
|||
}
|
||||
|
||||
/// A `TokenStream` is an abstract sequence of tokens, organized into [`TokenTree`]s.
|
||||
#[derive(Clone, Debug, Default, Encodable, Decodable)]
|
||||
#[derive(Clone, Debug, Default, PartialEq, Eq, Hash, Encodable, Decodable)]
|
||||
pub struct TokenStream(pub(crate) Arc<Vec<TokenTree>>);
|
||||
|
||||
impl TokenStream {
|
||||
|
|
@ -811,14 +812,6 @@ impl TokenStream {
|
|||
}
|
||||
}
|
||||
|
||||
impl PartialEq<TokenStream> for TokenStream {
|
||||
fn eq(&self, other: &TokenStream) -> bool {
|
||||
self.iter().eq(other.iter())
|
||||
}
|
||||
}
|
||||
|
||||
impl Eq for TokenStream {}
|
||||
|
||||
impl FromIterator<TokenTree> for TokenStream {
|
||||
fn from_iter<I: IntoIterator<Item = TokenTree>>(iter: I) -> Self {
|
||||
TokenStream::new(iter.into_iter().collect::<Vec<TokenTree>>())
|
||||
|
|
@ -970,7 +963,8 @@ impl TokenCursor {
|
|||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Copy, Clone, PartialEq, Encodable, Decodable, HashStable_Generic, Walkable)]
|
||||
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
|
||||
#[derive(Encodable, Decodable, HashStable_Generic, Walkable)]
|
||||
pub struct DelimSpan {
|
||||
pub open: Span,
|
||||
pub close: Span,
|
||||
|
|
@ -994,7 +988,7 @@ impl DelimSpan {
|
|||
}
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug, PartialEq, Encodable, Decodable, HashStable_Generic)]
|
||||
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Encodable, Decodable, HashStable_Generic)]
|
||||
pub struct DelimSpacing {
|
||||
pub open: Spacing,
|
||||
pub close: Spacing,
|
||||
|
|
|
|||
|
|
@ -21,6 +21,7 @@ rustc_hir = { path = "../rustc_hir" }
|
|||
rustc_lexer = { path = "../rustc_lexer" }
|
||||
rustc_lint_defs = { path = "../rustc_lint_defs" }
|
||||
rustc_macros = { path = "../rustc_macros" }
|
||||
rustc_middle = { path = "../rustc_middle" }
|
||||
rustc_parse = { path = "../rustc_parse" }
|
||||
# We must use the proc_macro version that we will compile proc-macros against,
|
||||
# not the one from our own sysroot.
|
||||
|
|
@ -28,6 +29,7 @@ rustc_proc_macro = { path = "../rustc_proc_macro" }
|
|||
rustc_serialize = { path = "../rustc_serialize" }
|
||||
rustc_session = { path = "../rustc_session" }
|
||||
rustc_span = { path = "../rustc_span" }
|
||||
scoped-tls = "1.0"
|
||||
smallvec = { version = "1.8.1", features = ["union", "may_dangle"] }
|
||||
thin-vec = "0.2.12"
|
||||
tracing = "0.1"
|
||||
|
|
|
|||
|
|
@ -29,4 +29,8 @@ pub mod module;
|
|||
#[allow(rustc::untranslatable_diagnostic)]
|
||||
pub mod proc_macro;
|
||||
|
||||
pub fn provide(providers: &mut rustc_middle::query::Providers) {
|
||||
providers.derive_macro_expansion = proc_macro::provide_derive_macro_expansion;
|
||||
}
|
||||
|
||||
rustc_fluent_macro::fluent_messages! { "../messages.ftl" }
|
||||
|
|
|
|||
|
|
@ -1,9 +1,11 @@
|
|||
use rustc_ast::tokenstream::TokenStream;
|
||||
use rustc_errors::ErrorGuaranteed;
|
||||
use rustc_middle::ty::{self, TyCtxt};
|
||||
use rustc_parse::parser::{ForceCollect, Parser};
|
||||
use rustc_session::Session;
|
||||
use rustc_session::config::ProcMacroExecutionStrategy;
|
||||
use rustc_span::Span;
|
||||
use rustc_span::profiling::SpannedEventArgRecorder;
|
||||
use rustc_span::{LocalExpnId, Span};
|
||||
use {rustc_ast as ast, rustc_proc_macro as pm};
|
||||
|
||||
use crate::base::{self, *};
|
||||
|
|
@ -30,9 +32,9 @@ impl<T> pm::bridge::server::MessagePipe<T> for MessagePipe<T> {
|
|||
}
|
||||
}
|
||||
|
||||
fn exec_strategy(ecx: &ExtCtxt<'_>) -> impl pm::bridge::server::ExecutionStrategy + 'static {
|
||||
fn exec_strategy(sess: &Session) -> impl pm::bridge::server::ExecutionStrategy + 'static {
|
||||
pm::bridge::server::MaybeCrossThread::<MessagePipe<_>>::new(
|
||||
ecx.sess.opts.unstable_opts.proc_macro_execution_strategy
|
||||
sess.opts.unstable_opts.proc_macro_execution_strategy
|
||||
== ProcMacroExecutionStrategy::CrossThread,
|
||||
)
|
||||
}
|
||||
|
|
@ -54,7 +56,7 @@ impl base::BangProcMacro for BangProcMacro {
|
|||
});
|
||||
|
||||
let proc_macro_backtrace = ecx.ecfg.proc_macro_backtrace;
|
||||
let strategy = exec_strategy(ecx);
|
||||
let strategy = exec_strategy(ecx.sess);
|
||||
let server = proc_macro_server::Rustc::new(ecx);
|
||||
self.client.run(&strategy, server, input, proc_macro_backtrace).map_err(|e| {
|
||||
ecx.dcx().emit_err(errors::ProcMacroPanicked {
|
||||
|
|
@ -85,7 +87,7 @@ impl base::AttrProcMacro for AttrProcMacro {
|
|||
});
|
||||
|
||||
let proc_macro_backtrace = ecx.ecfg.proc_macro_backtrace;
|
||||
let strategy = exec_strategy(ecx);
|
||||
let strategy = exec_strategy(ecx.sess);
|
||||
let server = proc_macro_server::Rustc::new(ecx);
|
||||
self.client.run(&strategy, server, annotation, annotated, proc_macro_backtrace).map_err(
|
||||
|e| {
|
||||
|
|
@ -101,7 +103,7 @@ impl base::AttrProcMacro for AttrProcMacro {
|
|||
}
|
||||
|
||||
pub struct DeriveProcMacro {
|
||||
pub client: pm::bridge::client::Client<pm::TokenStream, pm::TokenStream>,
|
||||
pub client: DeriveClient,
|
||||
}
|
||||
|
||||
impl MultiItemModifier for DeriveProcMacro {
|
||||
|
|
@ -113,6 +115,13 @@ impl MultiItemModifier for DeriveProcMacro {
|
|||
item: Annotatable,
|
||||
_is_derive_const: bool,
|
||||
) -> ExpandResult<Vec<Annotatable>, Annotatable> {
|
||||
let _timer = ecx.sess.prof.generic_activity_with_arg_recorder(
|
||||
"expand_derive_proc_macro_outer",
|
||||
|recorder| {
|
||||
recorder.record_arg_with_span(ecx.sess.source_map(), ecx.expansion_descr(), span);
|
||||
},
|
||||
);
|
||||
|
||||
// We need special handling for statement items
|
||||
// (e.g. `fn foo() { #[derive(Debug)] struct Bar; }`)
|
||||
let is_stmt = matches!(item, Annotatable::Stmt(..));
|
||||
|
|
@ -123,36 +132,31 @@ impl MultiItemModifier for DeriveProcMacro {
|
|||
// altogether. See #73345.
|
||||
crate::base::ann_pretty_printing_compatibility_hack(&item, &ecx.sess.psess);
|
||||
let input = item.to_tokens();
|
||||
let stream = {
|
||||
let _timer =
|
||||
ecx.sess.prof.generic_activity_with_arg_recorder("expand_proc_macro", |recorder| {
|
||||
recorder.record_arg_with_span(
|
||||
ecx.sess.source_map(),
|
||||
ecx.expansion_descr(),
|
||||
span,
|
||||
);
|
||||
});
|
||||
let proc_macro_backtrace = ecx.ecfg.proc_macro_backtrace;
|
||||
let strategy = exec_strategy(ecx);
|
||||
let server = proc_macro_server::Rustc::new(ecx);
|
||||
match self.client.run(&strategy, server, input, proc_macro_backtrace) {
|
||||
Ok(stream) => stream,
|
||||
Err(e) => {
|
||||
ecx.dcx().emit_err({
|
||||
errors::ProcMacroDerivePanicked {
|
||||
span,
|
||||
message: e.as_str().map(|message| {
|
||||
errors::ProcMacroDerivePanickedHelp { message: message.into() }
|
||||
}),
|
||||
}
|
||||
});
|
||||
return ExpandResult::Ready(vec![]);
|
||||
}
|
||||
}
|
||||
|
||||
let invoc_id = ecx.current_expansion.id;
|
||||
|
||||
let res = if ecx.sess.opts.incremental.is_some()
|
||||
&& ecx.sess.opts.unstable_opts.cache_proc_macros
|
||||
{
|
||||
ty::tls::with(|tcx| {
|
||||
let input = &*tcx.arena.alloc(input);
|
||||
let key: (LocalExpnId, &TokenStream) = (invoc_id, input);
|
||||
|
||||
QueryDeriveExpandCtx::enter(ecx, self.client, move || {
|
||||
tcx.derive_macro_expansion(key).cloned()
|
||||
})
|
||||
})
|
||||
} else {
|
||||
expand_derive_macro(invoc_id, input, ecx, self.client)
|
||||
};
|
||||
|
||||
let Ok(output) = res else {
|
||||
// error will already have been emitted
|
||||
return ExpandResult::Ready(vec![]);
|
||||
};
|
||||
|
||||
let error_count_before = ecx.dcx().err_count();
|
||||
let mut parser = Parser::new(&ecx.sess.psess, stream, Some("proc-macro derive"));
|
||||
let mut parser = Parser::new(&ecx.sess.psess, output, Some("proc-macro derive"));
|
||||
let mut items = vec![];
|
||||
|
||||
loop {
|
||||
|
|
@ -180,3 +184,101 @@ impl MultiItemModifier for DeriveProcMacro {
|
|||
ExpandResult::Ready(items)
|
||||
}
|
||||
}
|
||||
|
||||
/// Provide a query for computing the output of a derive macro.
|
||||
pub(super) fn provide_derive_macro_expansion<'tcx>(
|
||||
tcx: TyCtxt<'tcx>,
|
||||
key: (LocalExpnId, &'tcx TokenStream),
|
||||
) -> Result<&'tcx TokenStream, ()> {
|
||||
let (invoc_id, input) = key;
|
||||
|
||||
// Make sure that we invalidate the query when the crate defining the proc macro changes
|
||||
let _ = tcx.crate_hash(invoc_id.expn_data().macro_def_id.unwrap().krate);
|
||||
|
||||
QueryDeriveExpandCtx::with(|ecx, client| {
|
||||
expand_derive_macro(invoc_id, input.clone(), ecx, client).map(|ts| &*tcx.arena.alloc(ts))
|
||||
})
|
||||
}
|
||||
|
||||
type DeriveClient = pm::bridge::client::Client<pm::TokenStream, pm::TokenStream>;
|
||||
|
||||
fn expand_derive_macro(
|
||||
invoc_id: LocalExpnId,
|
||||
input: TokenStream,
|
||||
ecx: &mut ExtCtxt<'_>,
|
||||
client: DeriveClient,
|
||||
) -> Result<TokenStream, ()> {
|
||||
let _timer =
|
||||
ecx.sess.prof.generic_activity_with_arg_recorder("expand_proc_macro", |recorder| {
|
||||
let invoc_expn_data = invoc_id.expn_data();
|
||||
let span = invoc_expn_data.call_site;
|
||||
let event_arg = invoc_expn_data.kind.descr();
|
||||
recorder.record_arg_with_span(ecx.sess.source_map(), event_arg.clone(), span);
|
||||
});
|
||||
|
||||
let proc_macro_backtrace = ecx.ecfg.proc_macro_backtrace;
|
||||
let strategy = exec_strategy(ecx.sess);
|
||||
let server = proc_macro_server::Rustc::new(ecx);
|
||||
|
||||
match client.run(&strategy, server, input, proc_macro_backtrace) {
|
||||
Ok(stream) => Ok(stream),
|
||||
Err(e) => {
|
||||
let invoc_expn_data = invoc_id.expn_data();
|
||||
let span = invoc_expn_data.call_site;
|
||||
ecx.dcx().emit_err({
|
||||
errors::ProcMacroDerivePanicked {
|
||||
span,
|
||||
message: e.as_str().map(|message| errors::ProcMacroDerivePanickedHelp {
|
||||
message: message.into(),
|
||||
}),
|
||||
}
|
||||
});
|
||||
Err(())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Stores the context necessary to expand a derive proc macro via a query.
|
||||
struct QueryDeriveExpandCtx {
|
||||
/// Type-erased version of `&mut ExtCtxt`
|
||||
expansion_ctx: *mut (),
|
||||
client: DeriveClient,
|
||||
}
|
||||
|
||||
impl QueryDeriveExpandCtx {
|
||||
/// Store the extension context and the client into the thread local value.
|
||||
/// It will be accessible via the `with` method while `f` is active.
|
||||
fn enter<F, R>(ecx: &mut ExtCtxt<'_>, client: DeriveClient, f: F) -> R
|
||||
where
|
||||
F: FnOnce() -> R,
|
||||
{
|
||||
// We need erasure to get rid of the lifetime
|
||||
let ctx = Self { expansion_ctx: ecx as *mut _ as *mut (), client };
|
||||
DERIVE_EXPAND_CTX.set(&ctx, || f())
|
||||
}
|
||||
|
||||
/// Accesses the thread local value of the derive expansion context.
|
||||
/// Must be called while the `enter` function is active.
|
||||
fn with<F, R>(f: F) -> R
|
||||
where
|
||||
F: for<'a, 'b> FnOnce(&'b mut ExtCtxt<'a>, DeriveClient) -> R,
|
||||
{
|
||||
DERIVE_EXPAND_CTX.with(|ctx| {
|
||||
let ectx = {
|
||||
let casted = ctx.expansion_ctx.cast::<ExtCtxt<'_>>();
|
||||
// SAFETY: We can only get the value from `with` while the `enter` function
|
||||
// is active (on the callstack), and that function's signature ensures that the
|
||||
// lifetime is valid.
|
||||
// If `with` is called at some other time, it will panic due to usage of
|
||||
// `scoped_tls::with`.
|
||||
unsafe { casted.as_mut().unwrap() }
|
||||
};
|
||||
|
||||
f(ectx, ctx.client)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// When we invoke a query to expand a derive proc macro, we need to provide it with the expansion
|
||||
// context and derive Client. We do that using a thread-local.
|
||||
scoped_tls::scoped_thread_local!(static DERIVE_EXPAND_CTX: QueryDeriveExpandCtx);
|
||||
|
|
|
|||
|
|
@ -26,7 +26,7 @@ use rustc_hir::def_id::LocalDefId;
|
|||
use rustc_hir::{
|
||||
Attribute, ImplItemKind, ItemKind as HirItem, Node as HirNode, TraitItemKind, intravisit,
|
||||
};
|
||||
use rustc_middle::dep_graph::{DepNode, DepNodeExt, label_strs};
|
||||
use rustc_middle::dep_graph::{DepNode, DepNodeExt, dep_kind_from_label, label_strs};
|
||||
use rustc_middle::hir::nested_filter;
|
||||
use rustc_middle::ty::TyCtxt;
|
||||
use rustc_span::{Span, Symbol, sym};
|
||||
|
|
@ -357,17 +357,6 @@ impl<'tcx> DirtyCleanVisitor<'tcx> {
|
|||
}
|
||||
}
|
||||
|
||||
fn assert_loaded_from_disk(&self, item_span: Span, dep_node: DepNode) {
|
||||
debug!("assert_loaded_from_disk({:?})", dep_node);
|
||||
|
||||
if !self.tcx.dep_graph.debug_was_loaded_from_disk(dep_node) {
|
||||
let dep_node_str = self.dep_node_str(&dep_node);
|
||||
self.tcx
|
||||
.dcx()
|
||||
.emit_err(errors::NotLoaded { span: item_span, dep_node_str: &dep_node_str });
|
||||
}
|
||||
}
|
||||
|
||||
fn check_item(&mut self, item_id: LocalDefId) {
|
||||
let item_span = self.tcx.def_span(item_id.to_def_id());
|
||||
let def_path_hash = self.tcx.def_path_hash(item_id.to_def_id());
|
||||
|
|
@ -385,8 +374,27 @@ impl<'tcx> DirtyCleanVisitor<'tcx> {
|
|||
self.assert_dirty(item_span, dep_node);
|
||||
}
|
||||
for label in assertion.loaded_from_disk.items().into_sorted_stable_ord() {
|
||||
let dep_node = DepNode::from_label_string(self.tcx, label, def_path_hash).unwrap();
|
||||
self.assert_loaded_from_disk(item_span, dep_node);
|
||||
match DepNode::from_label_string(self.tcx, label, def_path_hash) {
|
||||
Ok(dep_node) => {
|
||||
if !self.tcx.dep_graph.debug_was_loaded_from_disk(dep_node) {
|
||||
let dep_node_str = self.dep_node_str(&dep_node);
|
||||
self.tcx.dcx().emit_err(errors::NotLoaded {
|
||||
span: item_span,
|
||||
dep_node_str: &dep_node_str,
|
||||
});
|
||||
}
|
||||
}
|
||||
// Opaque/unit hash, we only know the dep kind
|
||||
Err(()) => {
|
||||
let dep_kind = dep_kind_from_label(label);
|
||||
if !self.tcx.dep_graph.debug_dep_kind_was_loaded_from_disk(dep_kind) {
|
||||
self.tcx.dcx().emit_err(errors::NotLoaded {
|
||||
span: item_span,
|
||||
dep_node_str: &label,
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -889,6 +889,7 @@ pub static DEFAULT_QUERY_PROVIDERS: LazyLock<Providers> = LazyLock::new(|| {
|
|||
providers.queries.env_var_os = env_var_os;
|
||||
limits::provide(&mut providers.queries);
|
||||
proc_macro_decls::provide(&mut providers.queries);
|
||||
rustc_expand::provide(&mut providers.queries);
|
||||
rustc_const_eval::provide(providers);
|
||||
rustc_middle::hir::provide(&mut providers.queries);
|
||||
rustc_borrowck::provide(&mut providers.queries);
|
||||
|
|
|
|||
|
|
@ -119,6 +119,7 @@ macro_rules! arena_types {
|
|||
[decode] specialization_graph: rustc_middle::traits::specialization_graph::Graph,
|
||||
[] crate_inherent_impls: rustc_middle::ty::CrateInherentImpls,
|
||||
[] hir_owner_nodes: rustc_hir::OwnerNodes<'tcx>,
|
||||
[decode] token_stream: rustc_ast::tokenstream::TokenStream,
|
||||
]);
|
||||
)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -176,6 +176,12 @@ impl DepNodeExt for DepNode {
|
|||
}
|
||||
}
|
||||
|
||||
/// Maps a query label to its DepKind. Panics if a query with the given label does not exist.
|
||||
pub fn dep_kind_from_label(label: &str) -> DepKind {
|
||||
dep_kind_from_label_string(label)
|
||||
.unwrap_or_else(|_| panic!("Query label {label} does not exist"))
|
||||
}
|
||||
|
||||
impl<'tcx> DepNodeParams<TyCtxt<'tcx>> for () {
|
||||
#[inline(always)]
|
||||
fn fingerprint_style() -> FingerprintStyle {
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@ use crate::ty::{self, TyCtxt};
|
|||
#[macro_use]
|
||||
mod dep_node;
|
||||
|
||||
pub use dep_node::{DepKind, DepNode, DepNodeExt, dep_kinds, label_strs};
|
||||
pub use dep_node::{DepKind, DepNode, DepNodeExt, dep_kind_from_label, dep_kinds, label_strs};
|
||||
pub(crate) use dep_node::{make_compile_codegen_unit, make_compile_mono_item, make_metadata};
|
||||
pub use rustc_query_system::dep_graph::debug::{DepNodeFilter, EdgeFilter};
|
||||
pub use rustc_query_system::dep_graph::{
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@ use std::ffi::OsStr;
|
|||
use std::intrinsics::transmute_unchecked;
|
||||
use std::mem::MaybeUninit;
|
||||
|
||||
use rustc_ast::tokenstream::TokenStream;
|
||||
use rustc_span::ErrorGuaranteed;
|
||||
use rustc_span::source_map::Spanned;
|
||||
|
||||
|
|
@ -188,6 +189,10 @@ impl EraseType
|
|||
>()];
|
||||
}
|
||||
|
||||
impl EraseType for Result<&'_ TokenStream, ()> {
|
||||
type Result = [u8; size_of::<Result<&'static TokenStream, ()>>()];
|
||||
}
|
||||
|
||||
impl<T> EraseType for Option<&'_ T> {
|
||||
type Result = [u8; size_of::<Option<&'static ()>>()];
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,11 +2,12 @@
|
|||
|
||||
use std::ffi::OsStr;
|
||||
|
||||
use rustc_ast::tokenstream::TokenStream;
|
||||
use rustc_hir::def_id::{CrateNum, DefId, LOCAL_CRATE, LocalDefId, LocalModDefId, ModDefId};
|
||||
use rustc_hir::hir_id::{HirId, OwnerId};
|
||||
use rustc_query_system::dep_graph::DepNodeIndex;
|
||||
use rustc_query_system::query::{DefIdCache, DefaultCache, SingleCache, VecCache};
|
||||
use rustc_span::{DUMMY_SP, Ident, Span, Symbol};
|
||||
use rustc_span::{DUMMY_SP, Ident, LocalExpnId, Span, Symbol};
|
||||
|
||||
use crate::infer::canonical::CanonicalQueryInput;
|
||||
use crate::mir::mono::CollectionMode;
|
||||
|
|
@ -616,6 +617,19 @@ impl Key for (LocalDefId, HirId) {
|
|||
}
|
||||
}
|
||||
|
||||
impl<'tcx> Key for (LocalExpnId, &'tcx TokenStream) {
|
||||
type Cache<V> = DefaultCache<Self, V>;
|
||||
|
||||
fn default_span(&self, _tcx: TyCtxt<'_>) -> Span {
|
||||
self.0.expn_data().call_site
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn key_as_def_id(&self) -> Option<DefId> {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> Key for (ValidityRequirement, ty::PseudoCanonicalInput<'tcx, Ty<'tcx>>) {
|
||||
type Cache<V> = DefaultCache<Self, V>;
|
||||
|
||||
|
|
|
|||
|
|
@ -70,6 +70,7 @@ use std::sync::Arc;
|
|||
use rustc_abi::Align;
|
||||
use rustc_arena::TypedArena;
|
||||
use rustc_ast::expand::allocator::AllocatorKind;
|
||||
use rustc_ast::tokenstream::TokenStream;
|
||||
use rustc_data_structures::fx::{FxIndexMap, FxIndexSet};
|
||||
use rustc_data_structures::sorted_map::SortedMap;
|
||||
use rustc_data_structures::steal::Steal;
|
||||
|
|
@ -96,7 +97,7 @@ use rustc_session::cstore::{
|
|||
use rustc_session::lint::LintExpectationId;
|
||||
use rustc_span::def_id::LOCAL_CRATE;
|
||||
use rustc_span::source_map::Spanned;
|
||||
use rustc_span::{DUMMY_SP, Span, Symbol};
|
||||
use rustc_span::{DUMMY_SP, LocalExpnId, Span, Symbol};
|
||||
use rustc_target::spec::PanicStrategy;
|
||||
use {rustc_abi as abi, rustc_ast as ast, rustc_hir as hir};
|
||||
|
||||
|
|
@ -163,6 +164,17 @@ pub mod plumbing;
|
|||
// Queries marked with `fatal_cycle` do not need the latter implementation,
|
||||
// as they will raise an fatal error on query cycles instead.
|
||||
rustc_queries! {
|
||||
/// Caches the expansion of a derive proc macro, e.g. `#[derive(Serialize)]`.
|
||||
/// The key is:
|
||||
/// - A unique key corresponding to the invocation of a macro.
|
||||
/// - Token stream which serves as an input to the macro.
|
||||
///
|
||||
/// The output is the token stream generated by the proc macro.
|
||||
query derive_macro_expansion(key: (LocalExpnId, &'tcx TokenStream)) -> Result<&'tcx TokenStream, ()> {
|
||||
desc { "expanding a derive (proc) macro" }
|
||||
cache_on_disk_if { true }
|
||||
}
|
||||
|
||||
/// This exists purely for testing the interactions between delayed bugs and incremental.
|
||||
query trigger_delayed_bug(key: DefId) {
|
||||
desc { "triggering a delayed bug for testing incremental" }
|
||||
|
|
|
|||
|
|
@ -785,6 +785,13 @@ impl<'a, 'tcx> Decodable<CacheDecoder<'a, 'tcx>>
|
|||
}
|
||||
}
|
||||
|
||||
impl<'a, 'tcx> Decodable<CacheDecoder<'a, 'tcx>> for &'tcx rustc_ast::tokenstream::TokenStream {
|
||||
#[inline]
|
||||
fn decode(d: &mut CacheDecoder<'a, 'tcx>) -> Self {
|
||||
RefDecodable::decode(d)
|
||||
}
|
||||
}
|
||||
|
||||
macro_rules! impl_ref_decoder {
|
||||
(<$tcx:tt> $($ty:ty,)*) => {
|
||||
$(impl<'a, $tcx> Decodable<CacheDecoder<'a, $tcx>> for &$tcx [$ty] {
|
||||
|
|
|
|||
|
|
@ -795,6 +795,18 @@ impl<D: Deps> DepGraph<D> {
|
|||
self.data.as_ref().unwrap().debug_loaded_from_disk.lock().contains(&dep_node)
|
||||
}
|
||||
|
||||
pub fn debug_dep_kind_was_loaded_from_disk(&self, dep_kind: DepKind) -> bool {
|
||||
// We only check if we have a dep node corresponding to the given dep kind.
|
||||
#[allow(rustc::potential_query_instability)]
|
||||
self.data
|
||||
.as_ref()
|
||||
.unwrap()
|
||||
.debug_loaded_from_disk
|
||||
.lock()
|
||||
.iter()
|
||||
.any(|node| node.kind == dep_kind)
|
||||
}
|
||||
|
||||
#[cfg(debug_assertions)]
|
||||
#[inline(always)]
|
||||
pub(crate) fn register_dep_node_debug_str<F>(&self, dep_node: DepNode, debug_str_gen: F)
|
||||
|
|
|
|||
|
|
@ -2278,6 +2278,8 @@ options! {
|
|||
"set options for branch target identification and pointer authentication on AArch64"),
|
||||
build_sdylib_interface: bool = (false, parse_bool, [UNTRACKED],
|
||||
"whether the stable interface is being built"),
|
||||
cache_proc_macros: bool = (false, parse_bool, [TRACKED],
|
||||
"cache the results of derive proc macro invocations (potentially unsound!) (default: no"),
|
||||
cf_protection: CFProtection = (CFProtection::None, parse_cfprotection, [TRACKED],
|
||||
"instrument control-flow architecture protection"),
|
||||
check_cfg_all_expected: bool = (false, parse_bool, [UNTRACKED],
|
||||
|
|
|
|||
|
|
@ -1571,3 +1571,9 @@ impl<CTX: HashStableContext> HashStable<CTX> for ExpnId {
|
|||
hash.hash_stable(ctx, hasher);
|
||||
}
|
||||
}
|
||||
|
||||
impl<CTX: HashStableContext> HashStable<CTX> for LocalExpnId {
|
||||
fn hash_stable(&self, hcx: &mut CTX, hasher: &mut StableHasher) {
|
||||
self.to_expn_id().hash_stable(hcx, hasher);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue