Skip to content

Conversation

@Kobzol
Copy link
Member

@Kobzol Kobzol commented Aug 13, 2025

This is a revival of #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 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

@rustbot rustbot added the S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. label Aug 13, 2025
@rustbot
Copy link
Collaborator

rustbot commented Aug 13, 2025

These commits modify the Cargo.lock file. Unintentional changes to Cargo.lock can be introduced when switching branches and rebasing PRs.

If this was unintentional then you should revert the changes before this PR is merged.
Otherwise, you can ignore this comment.

@rustbot rustbot added the T-compiler Relevant to the compiler team, which will review and decide on the PR/issue. label Aug 13, 2025
@Kobzol
Copy link
Member Author

Kobzol commented Aug 13, 2025

@bors try @rust-timer queue

@rust-timer

This comment has been minimized.

@rust-bors

This comment has been minimized.

rust-bors bot added a commit that referenced this pull request Aug 13, 2025
Cache derive proc macro expansion with incremental query
@rustbot rustbot added the S-waiting-on-perf Status: Waiting on a perf run to be completed. label Aug 13, 2025
@petrochenkov petrochenkov removed the S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. label Aug 13, 2025
@cjgillot cjgillot self-assigned this Aug 13, 2025
@rust-log-analyzer

This comment has been minimized.

@rust-bors

This comment was marked as resolved.

@rust-log-analyzer

This comment has been minimized.

@Kobzol
Copy link
Member Author

Kobzol commented Aug 13, 2025

@bors try

@rust-bors

This comment has been minimized.

rust-bors bot added a commit that referenced this pull request Aug 13, 2025
Cache derive proc macro expansion with incremental query
@rust-log-analyzer

This comment has been minimized.

@rust-log-analyzer

This comment has been minimized.

@rust-bors

This comment was marked as resolved.

@Kobzol
Copy link
Member Author

Kobzol commented Aug 15, 2025

I looked into the benchmark failure on diesel, seems like I hold queries wrong somehow :) Any suggestions on what could be the case? Maybe the derived Hash impl for TokenStream does not correspond to the manual Eq impl? 🤔

thread 'rustc' panicked at /projects/personal/rust/rust/compiler/rustc_query_system/src/query/plumbing.rs:191:23:
active query job entry
stack backtrace:
   0: __rustc::rust_begin_unwind
   1: core::panicking::panic_fmt
   2: core::option::expect_failed
   3: <rustc_query_system::query::plumbing::JobOwner<(rustc_span::hygiene::LocalExpnId, rustc_data_structures::svh::Svh, &rustc_ast::tokenstream::TokenStream), rustc_query_system::query::QueryStackDeferred>>::complete::<rustc_query_system::query::caches::DefaultCache<(rustc_span::hygiene::LocalExpnId, rustc_data_structures::svh::Svh, &rustc_ast::tokenstream::TokenStream), rustc_middle::query::erase::Erased<[u8; 8]>>>
   4: rustc_query_system::query::plumbing::try_execute_query::<rustc_query_impl::DynamicConfig<rustc_query_system::query::caches::DefaultCache<(rustc_span::hygiene::LocalExpnId, rustc_data_structures::svh::Svh, &rustc_ast::tokenstream::TokenStream), rustc_middle::query::erase::Erased<[u8; 8]>>, false, false, false>, rustc_query_impl::plumbing::QueryCtxt, true>
   5: <scoped_tls::ScopedKey<rustc_expand::proc_macro::QueryDeriveExpandCtx>>::set::<<rustc_expand::proc_macro::QueryDeriveExpandCtx>::enter<<rustc_expand::proc_macro::DeriveProcMacro as rustc_expand::base::MultiItemModifier>::expand::{closure#1}::{closure#0}, core::result::Result<rustc_ast::tokenstream::TokenStream, ()>>::{closure#0}, core::result::Result<rustc_ast::tokenstream::TokenStream, ()>>
   6: <rustc_expand::proc_macro::QueryDeriveExpandCtx>::enter::<<rustc_expand::proc_macro::DeriveProcMacro as rustc_expand::base::MultiItemModifier>::expand::{closure#1}::{closure#0}, core::result::Result<rustc_ast::tokenstream::TokenStream, ()>>
   7: <rustc_expand::proc_macro::DeriveProcMacro as rustc_expand::base::MultiItemModifier>::expand
   8: <rustc_expand::expand::MacroExpander>::expand_invoc
   9: <rustc_expand::expand::MacroExpander>::fully_expand_fragment
  10: <rustc_expand::expand::MacroExpander>::expand_crate
  11: <rustc_session::session::Session>::time::<rustc_ast::ast::Crate, rustc_interface::passes::configure_and_expand::{closure#1}>
  12: rustc_interface::passes::resolver_for_lowering_raw
      [... omitted 6 frames ...]
  13: <rustc_middle::ty::context::TyCtxt>::resolver_for_lowering
  14: <std::thread::local::LocalKey<core::cell::Cell<*const ()>>>::with::<rustc_middle::ty::context::tls::enter_context<<rustc_middle::ty::context::GlobalCtxt>::enter<rustc_interface::passes::create_and_enter_global_ctxt<core::option::Option<rustc_interface::queries::Linker>, rustc_driver_impl::run_compiler::{closure#0}::{closure#2}>::{closure#2}::{closure#0}, core::option::Option<rustc_interface::queries::Linker>>::{closure#1}, core::option::Option<rustc_interface::queries::Linker>>::{closure#0}, core::option::Option<rustc_interface::queries::Linker>>
  15: <rustc_middle::ty::context::TyCtxt>::create_global_ctxt::<core::option::Option<rustc_interface::queries::Linker>, rustc_interface::passes::create_and_enter_global_ctxt<core::option::Option<rustc_interface::queries::Linker>, rustc_driver_impl::run_compiler::{closure#0}::{closure#2}>::{closure#2}::{closure#0}>
  16: <rustc_interface::passes::create_and_enter_global_ctxt<core::option::Option<rustc_interface::queries::Linker>, rustc_driver_impl::run_compiler::{closure#0}::{closure#2}>::{closure#2} as core::ops::function::FnOnce<(&rustc_session::session::Session, rustc_middle::ty::context::CurrentGcx, alloc::sync::Arc<rustc_data_structures::jobserver::Proxy>, &std::sync::once_lock::OnceLock<rustc_middle::ty::context::GlobalCtxt>, &rustc_data_structures::sync::worker_local::WorkerLocal<rustc_middle::arena::Arena>, &rustc_data_structures::sync::worker_local::WorkerLocal<rustc_hir::Arena>, rustc_driver_impl::run_compiler::{closure#0}::{closure#2})>>::call_once::{shim:vtable#0}
  17: <alloc::boxed::Box<dyn for<'a> core::ops::function::FnOnce<(&'a rustc_session::session::Session, rustc_middle::ty::context::CurrentGcx, alloc::sync::Arc<rustc_data_structures::jobserver::Proxy>, &'a std::sync::once_lock::OnceLock<rustc_middle::ty::context::GlobalCtxt<'a>>, &'a rustc_data_structures::sync::worker_local::WorkerLocal<rustc_middle::arena::Arena<'a>>, &'a rustc_data_structures::sync::worker_local::WorkerLocal<rustc_hir::Arena<'a>>, rustc_driver_impl::run_compiler::{closure#0}::{closure#2}), Output = core::option::Option<rustc_interface::queries::Linker>>> as core::ops::function::FnOnce<(&rustc_session::session::Session, rustc_middle::ty::context::CurrentGcx, alloc::sync::Arc<rustc_data_structures::jobserver::Proxy>, &std::sync::once_lock::OnceLock<rustc_middle::ty::context::GlobalCtxt>, &rustc_data_structures::sync::worker_local::WorkerLocal<rustc_middle::arena::Arena>, &rustc_data_structures::sync::worker_local::WorkerLocal<rustc_hir::Arena>, rustc_driver_impl::run_compiler::{closure#0}::{closure#2})>>::call_once
  18: rustc_interface::passes::create_and_enter_global_ctxt::<core::option::Option<rustc_interface::queries::Linker>, rustc_driver_impl::run_compiler::{closure#0}::{closure#2}>
  19: std::panic::catch_unwind::<core::panic::unwind_safe::AssertUnwindSafe<rustc_interface::interface::run_compiler<(), rustc_driver_impl::run_compiler::{closure#0}>::{closure#1}::{closure#0}>, ()>
  20: <scoped_tls::ScopedKey<rustc_span::SessionGlobals>>::set::<rustc_interface::util::run_in_thread_with_globals<rustc_interface::util::run_in_thread_pool_with_globals<rustc_interface::interface::run_compiler<(), rustc_driver_impl::run_compiler::{closure#0}>::{closure#1}, ()>::{closure#0}, ()>::{closure#0}::{closure#0}::{closure#0}, ()>
  21: rustc_span::create_session_globals_then::<(), rustc_interface::util::run_in_thread_with_globals<rustc_interface::util::run_in_thread_pool_with_globals<rustc_interface::interface::run_compiler<(), rustc_driver_impl::run_compiler::{closure#0}>::{closure#1}, ()>::{closure#0}, ()>::{closure#0}::{closure#0}::{closure#0}>
note: Some details are omitted, run with `RUST_BACKTRACE=full` for a verbose backtrace

@Kobzol
Copy link
Member Author

Kobzol commented Aug 25, 2025

Ok I did a bit of debugging, and found a fun fact: TokenStream == TokenStream is (or at least can be) false. So that has to be fixed before we can use token streams as query keys.. :)

@Kobzol
Copy link
Member Author

Kobzol commented Aug 25, 2025

Ok I found it, it's this. @nnethercote Do you think it's possible to make TokenStreams comparable?

@petrochenkov
Copy link
Contributor

petrochenkov commented Aug 25, 2025

Technically, removing that PartialEq for InvisibleOrigin is a language change.
But this PR can be unblocked without the lang team involvement by migrating the macro_rules matching logic specifically from PartialEq to a custom comparison function.

I'm not actually sure where else PartialEq for TokenStream is used, besides the matching and now also queries.
UPD: Nowhere.
UPD2: I think (Partial)Eq for TokenStream can also be derived now.

@Kobzol
Copy link
Member Author

Kobzol commented Aug 25, 2025

Could you please specify what do you mean by "macro rules matching logic"? I tried removing PartialEq from InvisibleOrigin, which required removing it from Delimiter and TokenKind, and that makes a bunch of places in code not compile, because they use == on these types (approx. 13 usages across 4 files). All of that should be migrated to a custom trait?

I also thought that another alternative would be to wrap TokenStream in a newtype and implement Eq for that newtype, which would delegate to a custom comparison trait for the query key logic (so basically an inverse of what you proposed).

Zalathar added a commit to Zalathar/rust that referenced this pull request Sep 4, 2025
…ochenkov

Derive `PartialEq` for `InvisibleOrigin`

For rust-lang#145354, we need `PartialEq` for `TokenStream` to "just work". However, due to the special comparison implementation that was used for `InvisibleOrigin`, this wasn't the case.

So I derived `PartialEq` for `InvisibleOrigin`, and used the previous special comparison logic only on the single place where it was actually required.

r? `````````@petrochenkov`````````
rust-timer added a commit that referenced this pull request Sep 4, 2025
Rollup merge of #146090 - Kobzol:invisible-origin-eq, r=petrochenkov

Derive `PartialEq` for `InvisibleOrigin`

For #145354, we need `PartialEq` for `TokenStream` to "just work". However, due to the special comparison implementation that was used for `InvisibleOrigin`, this wasn't the case.

So I derived `PartialEq` for `InvisibleOrigin`, and used the previous special comparison logic only on the single place where it was actually required.

r? `````````@petrochenkov`````````
@Kobzol Kobzol force-pushed the cache-proc-derive-macros branch from 8540970 to 356d426 Compare September 4, 2025 06:36
@rustbot

This comment has been minimized.

@rust-log-analyzer

This comment has been minimized.

@Kobzol
Copy link
Member Author

Kobzol commented Sep 4, 2025

#146090 has been merged. I'm still unsure how to properly test this though (as per the PR description).

github-actions bot pushed a commit to rust-lang/miri that referenced this pull request Sep 5, 2025
Derive `PartialEq` for `InvisibleOrigin`

For rust-lang/rust#145354, we need `PartialEq` for `TokenStream` to "just work". However, due to the special comparison implementation that was used for `InvisibleOrigin`, this wasn't the case.

So I derived `PartialEq` for `InvisibleOrigin`, and used the previous special comparison logic only on the single place where it was actually required.

r? `````````@petrochenkov`````````
@bors

This comment was marked as resolved.

@Kobzol Kobzol force-pushed the cache-proc-derive-macros branch from 356d426 to f3a462a Compare January 2, 2026 15:13
@rustbot rustbot added the A-query-system Area: The rustc query system (https://rustc-dev-guide.rust-lang.org/query.html) label Jan 2, 2026
@rustbot

This comment has been minimized.

@Kobzol
Copy link
Member Author

Kobzol commented Jan 2, 2026

Ok, it's not super pretty, but I managed to put together some super simple test infra for checking if a query that has a unit/opaque hash has been loaded from disk.

@rustbot ready

@rustbot rustbot added S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. and removed S-waiting-on-author Status: This is awaiting some action (such as code changes or more information) from the author. labels Jan 2, 2026
@rust-log-analyzer

This comment has been minimized.

@petrochenkov
Copy link
Contributor

CI is also failing.
@rustbot author

@rustbot rustbot added S-waiting-on-author Status: This is awaiting some action (such as code changes or more information) from the author. and removed S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. labels Jan 14, 2026
@rust-bors
Copy link
Contributor

rust-bors bot commented Jan 14, 2026

☔ The latest upstream changes (presumably #151107) made this pull request unmergeable. Please resolve the merge conflicts.

@Kobzol Kobzol force-pushed the cache-proc-derive-macros branch from f3a462a to 05781ca Compare January 15, 2026 13:05
@rustbot
Copy link
Collaborator

rustbot commented Jan 15, 2026

This PR was rebased onto a different main commit. Here's a range-diff highlighting what actually changed.

Rebasing is a normal part of keeping PRs up to date, so no action is needed—this note is just to help reviewers.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

A-query-system Area: The rustc query system (https://rustc-dev-guide.rust-lang.org/query.html) perf-regression Performance regression. S-waiting-on-author Status: This is awaiting some action (such as code changes or more information) from the author. T-compiler Relevant to the compiler team, which will review and decide on the PR/issue.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

9 participants