Skip to content

Introduce for_each_query_vtable! to move more code out of query macros - #153685

Merged
rust-bors[bot] merged 2 commits into
rust-lang:mainfrom
Zalathar:for-each-query
Mar 12, 2026
Merged

Introduce for_each_query_vtable! to move more code out of query macros#153685
rust-bors[bot] merged 2 commits into
rust-lang:mainfrom
Zalathar:for-each-query

Conversation

@Zalathar

@ZalatharZalathar commented Mar 11, 2026

Copy link
Copy Markdown
Member

View all comments

After #153114 moved a few for-each-query functions into the big rustc_query_impl::plumbing macro, I have found that those functions became much harder to navigate and modify, because they no longer have access to ordinary IDE features in rust-analyzer. Even finding the functions is considerably harder, because a plain go-to-definition no longer works smoothly.

This PR therefore tries to move as much of that code back out of the macro as possible, with the aid of a smaller for_each_query_vtable! helper macro. A typical use of that macro looks like this:

for_each_query_vtable!(ALL, tcx, |query| {
query_key_hash_verify(query, tcx);});

The result is an outer function consisting almost entirely of plain Rust code, with all of the usual IDE affordances expected of normal Rust code. Because it uses plain Rust syntax, it can also be formatted automatically by rustfmt.

Adding another layer of macro-defined macros is not something I propose lightly, but in this case I think the improvement is well worth it:

  • The outer functions can once again be defined as “normal” Rust functions, right next to their corresponding inner functions, making navigation and modification much easier.
  • The closure expression is ordinary Rust code that simply gets repeated ~300 times in the expansion, once for each query, in order to account for the variety of key/value/cache types used by different queries. Even within the closure expression, IDE features still mostly work, which is an improvement over the status quo.
  • For future maintainers looking at the call site, the macro's effect should hopefully be pretty obvious and intuitive, reducing the need to even look at the helper macro. And the helper macro itself is largely straightforward, with its biggest complication being that it necessarily uses the $name metavar from the outer macro.

There should be no change to compiler behaviour.

r? nnethercote (or compiler)

@rustbotrustbot added A-query-system Area: The rustc query system (https://rustc-dev-guide.rust-lang.org/query.html) S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. T-compiler Relevant to the compiler team, which will review and decide on the PR/issue. labels Mar 11, 2026
@Zalathar

Copy link
Copy Markdown
MemberAuthor

@Zalathar

Copy link
Copy Markdown
MemberAuthor

I don't expect any perf difference, but I'm curious to see if there's a measurable difference in bootstrap time.

(Though I think that even an extra 1-2 seconds would still be worth the cost, if it came to that.)

@bors try @rust-timer queue

@rust-timer

This comment has been minimized.

@rust-bors

This comment has been minimized.

rust-borsBot pushed a commit that referenced this pull request Mar 11, 2026
Introduce `for_each_query_vtable!` to move more code out of query macros
@rustbotrustbot added the S-waiting-on-perf Status: Waiting on a perf run to be completed. label Mar 11, 2026

@nnethercotennethercote left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I initially thought that splitting it into two macros would be better, to eliminate the ALL and CACHE_ON_DISK, but it probably doesn't make a material difference.

View changes since this review

@nnethercote

Copy link
Copy Markdown
Contributor

I have an item on my todo list to rename all these functions. Currently we have an inconsistent mess:

  • collect_active_jobs_from_all_queries, gather_active_jobs
  • alloc_self_profile_query_strings, alloc_self_profile_query_strings_for_query_cache
  • encode_all_query_results, encode_query_results
  • query_key_hash_verify_all, query_key_hash_verify

I'm considering these:

  • collect_active_jobs_for_{all_queries,one_query}
  • alloc_self_profile_strings_for_{all_queries,one_query}
  • encode_results_for_{all_queries,one_query}
  • verify_key_hashes_for_{all_queries,one_query}

They are long, but each one is only used a small number of times, and I think they score high for consistency and clarity. Shorter alternatives all seemed worse. What do you think?

@nnethercote

Copy link
Copy Markdown
Contributor

(The function renaming would be a follow-up to this PR, of course.)

Comment threadcompiler/rustc_query_impl/src/plumbing.rs Outdated
@Zalathar
Zalatharforce-pushed the for-each-query branch 2 times, most recently from 7d69ab2 to 50d4b2dCompareMarch 11, 2026 03:20
@rustbot

This comment has been minimized.

@Zalathar

Copy link
Copy Markdown
MemberAuthor

They are long, but each one is only used a small number of times, and I think they score high for consistency and clarity. Shorter alternatives all seemed worse. What do you think?

Seems pretty reasonable.

Also note that if we're moving in the direction of referring to query return values as “values” instead of ”results”, then that should probably be encode_values_for_{all_queries,one_query}.

@Zalathar

Copy link
Copy Markdown
MemberAuthor

I initially thought that splitting it into two macros would be better, to eliminate the ALL and CACHE_ON_DISK, but it probably doesn't make a material difference.

I considered a few different variations of how to indicate the filter condition, and having one macro with multiple arms and CONDITION_IN_CAPS felt like the best compromise overall.

@rust-bors

rust-borsBot commented Mar 11, 2026

Copy link
Copy Markdown
Contributor

☀️ Try build successful (CI)
Build commit: 45cd205 (45cd2051c9425da4b293edf8c5152780c9660aab, parent: b49ecc9eb70a51e89f32a7358e790f7b3808ccb3)

@rust-timer

This comment has been minimized.

@rust-timer

Copy link
Copy Markdown
Collaborator

Finished benchmarking commit (45cd205): comparison URL.

Overall result: ❌ regressions - no action needed

Benchmarking this pull request means it may be perf-sensitive – we'll automatically label it not fit for rolling up. You can override this, but we strongly advise not to, due to possible changes in compiler perf.

@bors rollup=never
@rustbot label: -S-waiting-on-perf -perf-regression

Instruction count

Our most reliable metric. Used to determine the overall result above. However, even this metric can be noisy.

meanrangecount
Regressions ❌
(primary)
--0
Regressions ❌
(secondary)
0.3%[0.3%, 0.3%]1
Improvements ✅
(primary)
--0
Improvements ✅
(secondary)
--0
All ❌✅ (primary)--0

Max RSS (memory usage)

Results (primary -0.2%, secondary -1.9%)

A less reliable metric. May be of interest, but not used to determine the overall result above.

meanrangecount
Regressions ❌
(primary)
1.4%[0.7%, 2.0%]3
Regressions ❌
(secondary)
1.9%[1.9%, 1.9%]1
Improvements ✅
(primary)
-1.8%[-2.0%, -1.6%]3
Improvements ✅
(secondary)
-2.9%[-3.5%, -1.9%]4
All ❌✅ (primary)-0.2%[-2.0%, 2.0%]6

Cycles

Results (secondary 1.5%)

A less reliable metric. May be of interest, but not used to determine the overall result above.

meanrangecount
Regressions ❌
(primary)
--0
Regressions ❌
(secondary)
4.1%[3.1%, 5.1%]2
Improvements ✅
(primary)
--0
Improvements ✅
(secondary)
-3.7%[-3.7%, -3.7%]1
All ❌✅ (primary)--0

Binary size

This benchmark run did not return any relevant results for this metric.

Bootstrap: 479.93s -> 483.213s (0.68%)
Artifact size: 396.95 MiB -> 394.92 MiB (-0.51%)

@rustbotrustbot removed the S-waiting-on-perf Status: Waiting on a perf run to be completed. label Mar 11, 2026
@nnethercote

Copy link
Copy Markdown
Contributor

Hmm, +3.3s for bootstrap, I wonder if that's real.

@Zalathar

Copy link
Copy Markdown
MemberAuthor

Based on some local measurements, I think the bootstrap-time regression is real, though the full 3.3 seconds is probably exaggerated.

I have an alternate version that expands into N calls to a single named inner function, instead of N calls to N duplicated closures. I'll push that as a separate commit, to see what you think of the different tradeoffs.

@Zalathar

Copy link
Copy Markdown
MemberAuthor

Let’s see what perf has to say about the function-call version.

@bors try @rust-timer queue

@rust-timer

This comment has been minimized.

@rust-bors

This comment has been minimized.

rust-borsBot pushed a commit that referenced this pull request Mar 11, 2026
Introduce `for_each_query_vtable!` to move more code out of query macros
@nnethercote

Copy link
Copy Markdown
Contributor

@bors r+

@rust-bors

rust-borsBot commented Mar 11, 2026

Copy link
Copy Markdown
Contributor

📌 Commit d066ff7 has been approved by nnethercote

It is now in the queue for this repository.

@rust-borsrust-borsBot added S-waiting-on-bors Status: Waiting on bors to run and complete tests. Bors will change the label on completion. and removed S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. labels Mar 11, 2026
@rust-borsrust-borsBot added the S-waiting-on-author Status: This is awaiting some action (such as code changes or more information) from the author. label Mar 11, 2026
@rust-bors

rust-borsBot commented Mar 11, 2026

Copy link
Copy Markdown
Contributor

⚠️ A new commit 9de761b23281f156a8556f85f0c7456faf4ffc0d was pushed.

This pull request was unapproved.

@rust-borsrust-borsBot removed the S-waiting-on-bors Status: Waiting on bors to run and complete tests. Bors will change the label on completion. label Mar 11, 2026
@Zalathar

Zalathar commented Mar 11, 2026

Copy link
Copy Markdown
MemberAuthor

Ah, after I removed the alternative syntax, I was in the middle of a cosmetic update that makes the modifiers a bit more distinctive.

Thoughts on the changes? I think it's a little nicer, but I'd be happy to revert back to the approved version.

I'll just revert back to the approved version and reapprove.

@Zalathar

Copy link
Copy Markdown
MemberAuthor

To keep things simple, I reverted back to the previously-approved revision.

(No perf changes, and the bootstrap timing change is tiny.)

@bors r=nnethercote rollup=maybe

@rust-bors

rust-borsBot commented Mar 11, 2026

Copy link
Copy Markdown
Contributor

📌 Commit d066ff7 has been approved by nnethercote

It is now in the queue for this repository.

@rust-borsrust-borsBot added S-waiting-on-bors Status: Waiting on bors to run and complete tests. Bors will change the label on completion. and removed S-waiting-on-author Status: This is awaiting some action (such as code changes or more information) from the author. labels Mar 11, 2026
JonathanBrouwer added a commit to JonathanBrouwer/rust that referenced this pull request Mar 11, 2026
…cote
Introduce `for_each_query_vtable!` to move more code out of query macros
After rust-lang#153114 moved a few for-each-query functions into the big `rustc_query_impl::plumbing` macro, I have found that those functions became much harder to navigate and modify, because they no longer have access to ordinary IDE features in rust-analyzer. Even *finding* the functions is considerably harder, because a plain go-to-definition no longer works smoothly.
This PR therefore tries to move as much of that code back out of the macro as possible, with the aid of a smaller `for_each_query_vtable!` helper macro. A typical use of that macro looks like this:
```rust
for_each_query_vtable!(ALL, tcx, |query| {
query_key_hash_verify(query, tcx);
});
```
The result is an outer function consisting almost entirely of plain Rust code, with all of the usual IDE affordances expected of normal Rust code. Because it uses plain Rust syntax, it can also be formatted automatically by rustfmt.
Adding another layer of macro-defined macros is not something I propose lightly, but in this case I think the improvement is well worth it:
- The outer functions can once again be defined as “normal” Rust functions, right next to their corresponding inner functions, making navigation and modification much easier.
- The closure expression is ordinary Rust code that simply gets repeated ~300 times in the expansion, once for each query, in order to account for the variety of key/value/cache types used by different queries. Even within the closure expression, IDE features still *mostly* work, which is an improvement over the status quo.
- For future maintainers looking at the call site, the macro's effect should hopefully be pretty obvious and intuitive, reducing the need to even look at the helper macro. And the helper macro itself is largely straightforward, with its biggest complication being that it necessarily uses the `$name` metavar from the outer macro.
There should be no change to compiler behaviour.
r? nnethercote (or compiler)
rust-borsBot pushed a commit that referenced this pull request Mar 11, 2026
…uwer
Rollup of 4 pull requests
Successful merges:
- #153571 (Avoid ICE when an EII declaration conflicts with a constructor)
- #153581 (Simplify `type_of_opaque`.)
- #153685 (Introduce `for_each_query_vtable!` to move more code out of query macros)
- #153710 (remove `.ftl` checks from tidy)
JonathanBrouwer added a commit to JonathanBrouwer/rust that referenced this pull request Mar 11, 2026
…cote
Introduce `for_each_query_vtable!` to move more code out of query macros
After rust-lang#153114 moved a few for-each-query functions into the big `rustc_query_impl::plumbing` macro, I have found that those functions became much harder to navigate and modify, because they no longer have access to ordinary IDE features in rust-analyzer. Even *finding* the functions is considerably harder, because a plain go-to-definition no longer works smoothly.
This PR therefore tries to move as much of that code back out of the macro as possible, with the aid of a smaller `for_each_query_vtable!` helper macro. A typical use of that macro looks like this:
```rust
for_each_query_vtable!(ALL, tcx, |query| {
query_key_hash_verify(query, tcx);
});
```
The result is an outer function consisting almost entirely of plain Rust code, with all of the usual IDE affordances expected of normal Rust code. Because it uses plain Rust syntax, it can also be formatted automatically by rustfmt.
Adding another layer of macro-defined macros is not something I propose lightly, but in this case I think the improvement is well worth it:
- The outer functions can once again be defined as “normal” Rust functions, right next to their corresponding inner functions, making navigation and modification much easier.
- The closure expression is ordinary Rust code that simply gets repeated ~300 times in the expansion, once for each query, in order to account for the variety of key/value/cache types used by different queries. Even within the closure expression, IDE features still *mostly* work, which is an improvement over the status quo.
- For future maintainers looking at the call site, the macro's effect should hopefully be pretty obvious and intuitive, reducing the need to even look at the helper macro. And the helper macro itself is largely straightforward, with its biggest complication being that it necessarily uses the `$name` metavar from the outer macro.
There should be no change to compiler behaviour.
r? nnethercote (or compiler)
rust-borsBot pushed a commit that referenced this pull request Mar 11, 2026
…uwer
Rollup of 9 pull requests
Successful merges:
- #153571 (Avoid ICE when an EII declaration conflicts with a constructor)
- #153581 (Simplify `type_of_opaque`.)
- #153611 (interpret: go back to regular string interpolation for error messages)
- #153635 (Unify same-span labels in move error diagnostics)
- #153660 (mir-opt: Drop invalid debuginfos after SingleUseConsts.)
- #153685 (Introduce `for_each_query_vtable!` to move more code out of query macros)
- #153671 (Make Enzyme has dependent on LLVM hash)
- #153710 (remove `.ftl` checks from tidy)
- #153720 (doc/rustc: clarify how to contact arm-maintainers)
rust-borsBot pushed a commit that referenced this pull request Mar 11, 2026
…uwer
Rollup of 9 pull requests
Successful merges:
- #153571 (Avoid ICE when an EII declaration conflicts with a constructor)
- #153581 (Simplify `type_of_opaque`.)
- #153611 (interpret: go back to regular string interpolation for error messages)
- #153635 (Unify same-span labels in move error diagnostics)
- #153660 (mir-opt: Drop invalid debuginfos after SingleUseConsts.)
- #153685 (Introduce `for_each_query_vtable!` to move more code out of query macros)
- #153671 (Make Enzyme has dependent on LLVM hash)
- #153710 (remove `.ftl` checks from tidy)
- #153720 (doc/rustc: clarify how to contact arm-maintainers)
rust-borsBot pushed a commit that referenced this pull request Mar 11, 2026
…uwer
Rollup of 9 pull requests
Successful merges:
- #153571 (Avoid ICE when an EII declaration conflicts with a constructor)
- #153581 (Simplify `type_of_opaque`.)
- #153611 (interpret: go back to regular string interpolation for error messages)
- #153635 (Unify same-span labels in move error diagnostics)
- #153660 (mir-opt: Drop invalid debuginfos after SingleUseConsts.)
- #153685 (Introduce `for_each_query_vtable!` to move more code out of query macros)
- #153671 (Make Enzyme has dependent on LLVM hash)
- #153710 (remove `.ftl` checks from tidy)
- #153720 (doc/rustc: clarify how to contact arm-maintainers)
rust-borsBot pushed a commit that referenced this pull request Mar 11, 2026
…uwer
Rollup of 12 pull requests
Successful merges:
- #152569 (Stop using rustc_layout_scalar_valid_range_* in rustc)
- #153421 (Fix ICE in fn_delegation when child segment resolves to a trait)
- #153571 (Avoid ICE when an EII declaration conflicts with a constructor)
- #153581 (Simplify `type_of_opaque`.)
- #153611 (interpret: go back to regular string interpolation for error messages)
- #153635 (Unify same-span labels in move error diagnostics)
- #153660 (mir-opt: Drop invalid debuginfos after SingleUseConsts.)
- #153685 (Introduce `for_each_query_vtable!` to move more code out of query macros)
- #153722 (miri-test-libstd: use --tests and update some comments)
- #153671 (Make Enzyme has dependent on LLVM hash)
- #153710 (remove `.ftl` checks from tidy)
- #153720 (doc/rustc: clarify how to contact arm-maintainers)
@rust-bors
rust-borsBot merged commit 8449503 into rust-lang:mainMar 12, 2026
12 of 22 checks passed
@Zalathar
Zalathar deleted the for-each-query branch March 12, 2026 00:24
github-actionsBot pushed a commit to rust-lang/miri that referenced this pull request Mar 12, 2026
…uwer
Rollup of 12 pull requests
Successful merges:
- rust-lang/rust#152569 (Stop using rustc_layout_scalar_valid_range_* in rustc)
- rust-lang/rust#153421 (Fix ICE in fn_delegation when child segment resolves to a trait)
- rust-lang/rust#153571 (Avoid ICE when an EII declaration conflicts with a constructor)
- rust-lang/rust#153581 (Simplify `type_of_opaque`.)
- rust-lang/rust#153611 (interpret: go back to regular string interpolation for error messages)
- rust-lang/rust#153635 (Unify same-span labels in move error diagnostics)
- rust-lang/rust#153660 (mir-opt: Drop invalid debuginfos after SingleUseConsts.)
- rust-lang/rust#153685 (Introduce `for_each_query_vtable!` to move more code out of query macros)
- rust-lang/rust#153722 (miri-test-libstd: use --tests and update some comments)
- rust-lang/rust#153671 (Make Enzyme has dependent on LLVM hash)
- rust-lang/rust#153710 (remove `.ftl` checks from tidy)
- rust-lang/rust#153720 (doc/rustc: clarify how to contact arm-maintainers)
@cuvipercuviper added this to the 1.96.0 milestone Mar 16, 2026
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

A-query-systemArea: The rustc query system (https://rustc-dev-guide.rust-lang.org/query.html)S-waiting-on-borsStatus: Waiting on bors to run and complete tests. Bors will change the label on completion.T-compilerRelevant 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.

5 participants

@Zalathar@rust-timer@nnethercote@rustbot@cuviper
, 'i'); if (__m === '*' || __re.test(location.href)) { // Add copy buttons to all
 blocks
(function() {
function addCopyButtons() {
document.querySelectorAll('pre code').forEach(function(codeBlock) {
if (codeBlock.parentElement.hasAttribute('data-copy-added')) return;
codeBlock.parentElement.setAttribute('data-copy-added', 'true');
var btn = document.createElement('button');
btn.textContent = 'Copy';
btn.style.cssText = 'position:absolute;top:4px;right:4px;padding:2px 8px;font-size:11px;background:#4ecdc4;border:none;border-radius:4px;color:#1a1a2e;cursor:pointer;opacity:0.7;transition:opacity 0.2s;';
btn.onmouseover = function() { this.style.opacity = '1'; };
btn.onmouseout = function() { this.style.opacity = '0.7'; };
btn.onclick = function() {
navigator.clipboard.writeText(codeBlock.textContent).then(function() {
btn.textContent = 'Copied!';
setTimeout(function() { btn.textContent = 'Copy'; }, 1500);
});
};
codeBlock.parentElement.style.position = 'relative';
codeBlock.parentElement.appendChild(btn);
});
}
addCopyButtons();
// Re-run on dynamic content
var observer = new MutationObserver(addCopyButtons);
observer.observe(document.body, { childList: true, subtree: true });
})();
}
} catch(__e) { console.warn('[Userscript:Add Copy Buttons to Code Blocks]', __e); }
})();
(function(){
try {
var __m = "github.com";
var __re = new RegExp('^' + "github\\.com" + '
Introduce `for_each_query_vtable!` to move more code out of query macros by Zalathar · Pull Request #153685 · rust-lang/rust · GitHub
Skip to content

Introduce for_each_query_vtable! to move more code out of query macros - #153685

Merged
rust-bors[bot] merged 2 commits into
rust-lang:mainfrom
Zalathar:for-each-query
Mar 12, 2026
Merged

Introduce for_each_query_vtable! to move more code out of query macros#153685
rust-bors[bot] merged 2 commits into
rust-lang:mainfrom
Zalathar:for-each-query

Conversation

@Zalathar

@ZalatharZalathar commented Mar 11, 2026

Copy link
Copy Markdown
Member

View all comments

After #153114 moved a few for-each-query functions into the big rustc_query_impl::plumbing macro, I have found that those functions became much harder to navigate and modify, because they no longer have access to ordinary IDE features in rust-analyzer. Even finding the functions is considerably harder, because a plain go-to-definition no longer works smoothly.

This PR therefore tries to move as much of that code back out of the macro as possible, with the aid of a smaller for_each_query_vtable! helper macro. A typical use of that macro looks like this:

for_each_query_vtable!(ALL, tcx, |query| {
query_key_hash_verify(query, tcx);});

The result is an outer function consisting almost entirely of plain Rust code, with all of the usual IDE affordances expected of normal Rust code. Because it uses plain Rust syntax, it can also be formatted automatically by rustfmt.

Adding another layer of macro-defined macros is not something I propose lightly, but in this case I think the improvement is well worth it:

  • The outer functions can once again be defined as “normal” Rust functions, right next to their corresponding inner functions, making navigation and modification much easier.
  • The closure expression is ordinary Rust code that simply gets repeated ~300 times in the expansion, once for each query, in order to account for the variety of key/value/cache types used by different queries. Even within the closure expression, IDE features still mostly work, which is an improvement over the status quo.
  • For future maintainers looking at the call site, the macro's effect should hopefully be pretty obvious and intuitive, reducing the need to even look at the helper macro. And the helper macro itself is largely straightforward, with its biggest complication being that it necessarily uses the $name metavar from the outer macro.

There should be no change to compiler behaviour.

r? nnethercote (or compiler)

@rustbotrustbot added A-query-system Area: The rustc query system (https://rustc-dev-guide.rust-lang.org/query.html) S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. T-compiler Relevant to the compiler team, which will review and decide on the PR/issue. labels Mar 11, 2026
@Zalathar

Copy link
Copy Markdown
MemberAuthor

@Zalathar

Copy link
Copy Markdown
MemberAuthor

I don't expect any perf difference, but I'm curious to see if there's a measurable difference in bootstrap time.

(Though I think that even an extra 1-2 seconds would still be worth the cost, if it came to that.)

@bors try @rust-timer queue

@rust-timer

This comment has been minimized.

@rust-bors

This comment has been minimized.

rust-borsBot pushed a commit that referenced this pull request Mar 11, 2026
Introduce `for_each_query_vtable!` to move more code out of query macros
@rustbotrustbot added the S-waiting-on-perf Status: Waiting on a perf run to be completed. label Mar 11, 2026

@nnethercotennethercote left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I initially thought that splitting it into two macros would be better, to eliminate the ALL and CACHE_ON_DISK, but it probably doesn't make a material difference.

View changes since this review

@nnethercote

Copy link
Copy Markdown
Contributor

I have an item on my todo list to rename all these functions. Currently we have an inconsistent mess:

  • collect_active_jobs_from_all_queries, gather_active_jobs
  • alloc_self_profile_query_strings, alloc_self_profile_query_strings_for_query_cache
  • encode_all_query_results, encode_query_results
  • query_key_hash_verify_all, query_key_hash_verify

I'm considering these:

  • collect_active_jobs_for_{all_queries,one_query}
  • alloc_self_profile_strings_for_{all_queries,one_query}
  • encode_results_for_{all_queries,one_query}
  • verify_key_hashes_for_{all_queries,one_query}

They are long, but each one is only used a small number of times, and I think they score high for consistency and clarity. Shorter alternatives all seemed worse. What do you think?

@nnethercote

Copy link
Copy Markdown
Contributor

(The function renaming would be a follow-up to this PR, of course.)

Comment threadcompiler/rustc_query_impl/src/plumbing.rs Outdated
@Zalathar
Zalatharforce-pushed the for-each-query branch 2 times, most recently from 7d69ab2 to 50d4b2dCompareMarch 11, 2026 03:20
@rustbot

This comment has been minimized.

@Zalathar

Copy link
Copy Markdown
MemberAuthor

They are long, but each one is only used a small number of times, and I think they score high for consistency and clarity. Shorter alternatives all seemed worse. What do you think?

Seems pretty reasonable.

Also note that if we're moving in the direction of referring to query return values as “values” instead of ”results”, then that should probably be encode_values_for_{all_queries,one_query}.

@Zalathar

Copy link
Copy Markdown
MemberAuthor

I initially thought that splitting it into two macros would be better, to eliminate the ALL and CACHE_ON_DISK, but it probably doesn't make a material difference.

I considered a few different variations of how to indicate the filter condition, and having one macro with multiple arms and CONDITION_IN_CAPS felt like the best compromise overall.

@rust-bors

rust-borsBot commented Mar 11, 2026

Copy link
Copy Markdown
Contributor

☀️ Try build successful (CI)
Build commit: 45cd205 (45cd2051c9425da4b293edf8c5152780c9660aab, parent: b49ecc9eb70a51e89f32a7358e790f7b3808ccb3)

@rust-timer

This comment has been minimized.

@rust-timer

Copy link
Copy Markdown
Collaborator

Finished benchmarking commit (45cd205): comparison URL.

Overall result: ❌ regressions - no action needed

Benchmarking this pull request means it may be perf-sensitive – we'll automatically label it not fit for rolling up. You can override this, but we strongly advise not to, due to possible changes in compiler perf.

@bors rollup=never
@rustbot label: -S-waiting-on-perf -perf-regression

Instruction count

Our most reliable metric. Used to determine the overall result above. However, even this metric can be noisy.

meanrangecount
Regressions ❌
(primary)
--0
Regressions ❌
(secondary)
0.3%[0.3%, 0.3%]1
Improvements ✅
(primary)
--0
Improvements ✅
(secondary)
--0
All ❌✅ (primary)--0

Max RSS (memory usage)

Results (primary -0.2%, secondary -1.9%)

A less reliable metric. May be of interest, but not used to determine the overall result above.

meanrangecount
Regressions ❌
(primary)
1.4%[0.7%, 2.0%]3
Regressions ❌
(secondary)
1.9%[1.9%, 1.9%]1
Improvements ✅
(primary)
-1.8%[-2.0%, -1.6%]3
Improvements ✅
(secondary)
-2.9%[-3.5%, -1.9%]4
All ❌✅ (primary)-0.2%[-2.0%, 2.0%]6

Cycles

Results (secondary 1.5%)

A less reliable metric. May be of interest, but not used to determine the overall result above.

meanrangecount
Regressions ❌
(primary)
--0
Regressions ❌
(secondary)
4.1%[3.1%, 5.1%]2
Improvements ✅
(primary)
--0
Improvements ✅
(secondary)
-3.7%[-3.7%, -3.7%]1
All ❌✅ (primary)--0

Binary size

This benchmark run did not return any relevant results for this metric.

Bootstrap: 479.93s -> 483.213s (0.68%)
Artifact size: 396.95 MiB -> 394.92 MiB (-0.51%)

@rustbotrustbot removed the S-waiting-on-perf Status: Waiting on a perf run to be completed. label Mar 11, 2026
@nnethercote

Copy link
Copy Markdown
Contributor

Hmm, +3.3s for bootstrap, I wonder if that's real.

@Zalathar

Copy link
Copy Markdown
MemberAuthor

Based on some local measurements, I think the bootstrap-time regression is real, though the full 3.3 seconds is probably exaggerated.

I have an alternate version that expands into N calls to a single named inner function, instead of N calls to N duplicated closures. I'll push that as a separate commit, to see what you think of the different tradeoffs.

@Zalathar

Copy link
Copy Markdown
MemberAuthor

Let’s see what perf has to say about the function-call version.

@bors try @rust-timer queue

@rust-timer

This comment has been minimized.

@rust-bors

This comment has been minimized.

rust-borsBot pushed a commit that referenced this pull request Mar 11, 2026
Introduce `for_each_query_vtable!` to move more code out of query macros
@nnethercote

Copy link
Copy Markdown
Contributor

@bors r+

@rust-bors

rust-borsBot commented Mar 11, 2026

Copy link
Copy Markdown
Contributor

📌 Commit d066ff7 has been approved by nnethercote

It is now in the queue for this repository.

@rust-borsrust-borsBot added S-waiting-on-bors Status: Waiting on bors to run and complete tests. Bors will change the label on completion. and removed S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. labels Mar 11, 2026
@rust-borsrust-borsBot added the S-waiting-on-author Status: This is awaiting some action (such as code changes or more information) from the author. label Mar 11, 2026
@rust-bors

rust-borsBot commented Mar 11, 2026

Copy link
Copy Markdown
Contributor

⚠️ A new commit 9de761b23281f156a8556f85f0c7456faf4ffc0d was pushed.

This pull request was unapproved.

@rust-borsrust-borsBot removed the S-waiting-on-bors Status: Waiting on bors to run and complete tests. Bors will change the label on completion. label Mar 11, 2026
@Zalathar

Zalathar commented Mar 11, 2026

Copy link
Copy Markdown
MemberAuthor

Ah, after I removed the alternative syntax, I was in the middle of a cosmetic update that makes the modifiers a bit more distinctive.

Thoughts on the changes? I think it's a little nicer, but I'd be happy to revert back to the approved version.

I'll just revert back to the approved version and reapprove.

@Zalathar

Copy link
Copy Markdown
MemberAuthor

To keep things simple, I reverted back to the previously-approved revision.

(No perf changes, and the bootstrap timing change is tiny.)

@bors r=nnethercote rollup=maybe

@rust-bors

rust-borsBot commented Mar 11, 2026

Copy link
Copy Markdown
Contributor

📌 Commit d066ff7 has been approved by nnethercote

It is now in the queue for this repository.

@rust-borsrust-borsBot added S-waiting-on-bors Status: Waiting on bors to run and complete tests. Bors will change the label on completion. and removed S-waiting-on-author Status: This is awaiting some action (such as code changes or more information) from the author. labels Mar 11, 2026
JonathanBrouwer added a commit to JonathanBrouwer/rust that referenced this pull request Mar 11, 2026
…cote
Introduce `for_each_query_vtable!` to move more code out of query macros
After rust-lang#153114 moved a few for-each-query functions into the big `rustc_query_impl::plumbing` macro, I have found that those functions became much harder to navigate and modify, because they no longer have access to ordinary IDE features in rust-analyzer. Even *finding* the functions is considerably harder, because a plain go-to-definition no longer works smoothly.
This PR therefore tries to move as much of that code back out of the macro as possible, with the aid of a smaller `for_each_query_vtable!` helper macro. A typical use of that macro looks like this:
```rust
for_each_query_vtable!(ALL, tcx, |query| {
query_key_hash_verify(query, tcx);
});
```
The result is an outer function consisting almost entirely of plain Rust code, with all of the usual IDE affordances expected of normal Rust code. Because it uses plain Rust syntax, it can also be formatted automatically by rustfmt.
Adding another layer of macro-defined macros is not something I propose lightly, but in this case I think the improvement is well worth it:
- The outer functions can once again be defined as “normal” Rust functions, right next to their corresponding inner functions, making navigation and modification much easier.
- The closure expression is ordinary Rust code that simply gets repeated ~300 times in the expansion, once for each query, in order to account for the variety of key/value/cache types used by different queries. Even within the closure expression, IDE features still *mostly* work, which is an improvement over the status quo.
- For future maintainers looking at the call site, the macro's effect should hopefully be pretty obvious and intuitive, reducing the need to even look at the helper macro. And the helper macro itself is largely straightforward, with its biggest complication being that it necessarily uses the `$name` metavar from the outer macro.
There should be no change to compiler behaviour.
r? nnethercote (or compiler)
rust-borsBot pushed a commit that referenced this pull request Mar 11, 2026
…uwer
Rollup of 4 pull requests
Successful merges:
- #153571 (Avoid ICE when an EII declaration conflicts with a constructor)
- #153581 (Simplify `type_of_opaque`.)
- #153685 (Introduce `for_each_query_vtable!` to move more code out of query macros)
- #153710 (remove `.ftl` checks from tidy)
JonathanBrouwer added a commit to JonathanBrouwer/rust that referenced this pull request Mar 11, 2026
…cote
Introduce `for_each_query_vtable!` to move more code out of query macros
After rust-lang#153114 moved a few for-each-query functions into the big `rustc_query_impl::plumbing` macro, I have found that those functions became much harder to navigate and modify, because they no longer have access to ordinary IDE features in rust-analyzer. Even *finding* the functions is considerably harder, because a plain go-to-definition no longer works smoothly.
This PR therefore tries to move as much of that code back out of the macro as possible, with the aid of a smaller `for_each_query_vtable!` helper macro. A typical use of that macro looks like this:
```rust
for_each_query_vtable!(ALL, tcx, |query| {
query_key_hash_verify(query, tcx);
});
```
The result is an outer function consisting almost entirely of plain Rust code, with all of the usual IDE affordances expected of normal Rust code. Because it uses plain Rust syntax, it can also be formatted automatically by rustfmt.
Adding another layer of macro-defined macros is not something I propose lightly, but in this case I think the improvement is well worth it:
- The outer functions can once again be defined as “normal” Rust functions, right next to their corresponding inner functions, making navigation and modification much easier.
- The closure expression is ordinary Rust code that simply gets repeated ~300 times in the expansion, once for each query, in order to account for the variety of key/value/cache types used by different queries. Even within the closure expression, IDE features still *mostly* work, which is an improvement over the status quo.
- For future maintainers looking at the call site, the macro's effect should hopefully be pretty obvious and intuitive, reducing the need to even look at the helper macro. And the helper macro itself is largely straightforward, with its biggest complication being that it necessarily uses the `$name` metavar from the outer macro.
There should be no change to compiler behaviour.
r? nnethercote (or compiler)
rust-borsBot pushed a commit that referenced this pull request Mar 11, 2026
…uwer
Rollup of 9 pull requests
Successful merges:
- #153571 (Avoid ICE when an EII declaration conflicts with a constructor)
- #153581 (Simplify `type_of_opaque`.)
- #153611 (interpret: go back to regular string interpolation for error messages)
- #153635 (Unify same-span labels in move error diagnostics)
- #153660 (mir-opt: Drop invalid debuginfos after SingleUseConsts.)
- #153685 (Introduce `for_each_query_vtable!` to move more code out of query macros)
- #153671 (Make Enzyme has dependent on LLVM hash)
- #153710 (remove `.ftl` checks from tidy)
- #153720 (doc/rustc: clarify how to contact arm-maintainers)
rust-borsBot pushed a commit that referenced this pull request Mar 11, 2026
…uwer
Rollup of 9 pull requests
Successful merges:
- #153571 (Avoid ICE when an EII declaration conflicts with a constructor)
- #153581 (Simplify `type_of_opaque`.)
- #153611 (interpret: go back to regular string interpolation for error messages)
- #153635 (Unify same-span labels in move error diagnostics)
- #153660 (mir-opt: Drop invalid debuginfos after SingleUseConsts.)
- #153685 (Introduce `for_each_query_vtable!` to move more code out of query macros)
- #153671 (Make Enzyme has dependent on LLVM hash)
- #153710 (remove `.ftl` checks from tidy)
- #153720 (doc/rustc: clarify how to contact arm-maintainers)
rust-borsBot pushed a commit that referenced this pull request Mar 11, 2026
…uwer
Rollup of 9 pull requests
Successful merges:
- #153571 (Avoid ICE when an EII declaration conflicts with a constructor)
- #153581 (Simplify `type_of_opaque`.)
- #153611 (interpret: go back to regular string interpolation for error messages)
- #153635 (Unify same-span labels in move error diagnostics)
- #153660 (mir-opt: Drop invalid debuginfos after SingleUseConsts.)
- #153685 (Introduce `for_each_query_vtable!` to move more code out of query macros)
- #153671 (Make Enzyme has dependent on LLVM hash)
- #153710 (remove `.ftl` checks from tidy)
- #153720 (doc/rustc: clarify how to contact arm-maintainers)
rust-borsBot pushed a commit that referenced this pull request Mar 11, 2026
…uwer
Rollup of 12 pull requests
Successful merges:
- #152569 (Stop using rustc_layout_scalar_valid_range_* in rustc)
- #153421 (Fix ICE in fn_delegation when child segment resolves to a trait)
- #153571 (Avoid ICE when an EII declaration conflicts with a constructor)
- #153581 (Simplify `type_of_opaque`.)
- #153611 (interpret: go back to regular string interpolation for error messages)
- #153635 (Unify same-span labels in move error diagnostics)
- #153660 (mir-opt: Drop invalid debuginfos after SingleUseConsts.)
- #153685 (Introduce `for_each_query_vtable!` to move more code out of query macros)
- #153722 (miri-test-libstd: use --tests and update some comments)
- #153671 (Make Enzyme has dependent on LLVM hash)
- #153710 (remove `.ftl` checks from tidy)
- #153720 (doc/rustc: clarify how to contact arm-maintainers)
@rust-bors
rust-borsBot merged commit 8449503 into rust-lang:mainMar 12, 2026
12 of 22 checks passed
@Zalathar
Zalathar deleted the for-each-query branch March 12, 2026 00:24
github-actionsBot pushed a commit to rust-lang/miri that referenced this pull request Mar 12, 2026
…uwer
Rollup of 12 pull requests
Successful merges:
- rust-lang/rust#152569 (Stop using rustc_layout_scalar_valid_range_* in rustc)
- rust-lang/rust#153421 (Fix ICE in fn_delegation when child segment resolves to a trait)
- rust-lang/rust#153571 (Avoid ICE when an EII declaration conflicts with a constructor)
- rust-lang/rust#153581 (Simplify `type_of_opaque`.)
- rust-lang/rust#153611 (interpret: go back to regular string interpolation for error messages)
- rust-lang/rust#153635 (Unify same-span labels in move error diagnostics)
- rust-lang/rust#153660 (mir-opt: Drop invalid debuginfos after SingleUseConsts.)
- rust-lang/rust#153685 (Introduce `for_each_query_vtable!` to move more code out of query macros)
- rust-lang/rust#153722 (miri-test-libstd: use --tests and update some comments)
- rust-lang/rust#153671 (Make Enzyme has dependent on LLVM hash)
- rust-lang/rust#153710 (remove `.ftl` checks from tidy)
- rust-lang/rust#153720 (doc/rustc: clarify how to contact arm-maintainers)
@cuvipercuviper added this to the 1.96.0 milestone Mar 16, 2026
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

A-query-systemArea: The rustc query system (https://rustc-dev-guide.rust-lang.org/query.html)S-waiting-on-borsStatus: Waiting on bors to run and complete tests. Bors will change the label on completion.T-compilerRelevant 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.

5 participants

@Zalathar@rust-timer@nnethercote@rustbot@cuviper
, 'i'); if (__m === '*' || __re.test(location.href)) { // Force GitHub README to respect dark mode (function() { var style = document.createElement('style'); style.textContent = ' .markdown-body { color-scheme: dark light; } .markdown-body pre { background: #161b22 !important; } .markdown-body code { background: rgba(110, 118, 129, 0.4) !important; } .markdown-body table th, .markdown-body table td { border-color: #30363d !important; } .markdown-body img { background: #0d1117; } .markdown-body blockquote { border-left-color: #8b949e; } .markdown-body hr { border-color: #30363d; } '; document.head.appendChild(style); })(); } } catch(__e) { console.warn('[Userscript:GitHub Dark Mode README Fix]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + ' Introduce `for_each_query_vtable!` to move more code out of query macros by Zalathar · Pull Request #153685 · rust-lang/rust · GitHub
Skip to content

Introduce for_each_query_vtable! to move more code out of query macros - #153685

Merged
rust-bors[bot] merged 2 commits into
rust-lang:mainfrom
Zalathar:for-each-query
Mar 12, 2026
Merged

Introduce for_each_query_vtable! to move more code out of query macros#153685
rust-bors[bot] merged 2 commits into
rust-lang:mainfrom
Zalathar:for-each-query

Conversation

@Zalathar

@ZalatharZalathar commented Mar 11, 2026

Copy link
Copy Markdown
Member

View all comments

After #153114 moved a few for-each-query functions into the big rustc_query_impl::plumbing macro, I have found that those functions became much harder to navigate and modify, because they no longer have access to ordinary IDE features in rust-analyzer. Even finding the functions is considerably harder, because a plain go-to-definition no longer works smoothly.

This PR therefore tries to move as much of that code back out of the macro as possible, with the aid of a smaller for_each_query_vtable! helper macro. A typical use of that macro looks like this:

for_each_query_vtable!(ALL, tcx, |query| {
query_key_hash_verify(query, tcx);});

The result is an outer function consisting almost entirely of plain Rust code, with all of the usual IDE affordances expected of normal Rust code. Because it uses plain Rust syntax, it can also be formatted automatically by rustfmt.

Adding another layer of macro-defined macros is not something I propose lightly, but in this case I think the improvement is well worth it:

  • The outer functions can once again be defined as “normal” Rust functions, right next to their corresponding inner functions, making navigation and modification much easier.
  • The closure expression is ordinary Rust code that simply gets repeated ~300 times in the expansion, once for each query, in order to account for the variety of key/value/cache types used by different queries. Even within the closure expression, IDE features still mostly work, which is an improvement over the status quo.
  • For future maintainers looking at the call site, the macro's effect should hopefully be pretty obvious and intuitive, reducing the need to even look at the helper macro. And the helper macro itself is largely straightforward, with its biggest complication being that it necessarily uses the $name metavar from the outer macro.

There should be no change to compiler behaviour.

r? nnethercote (or compiler)

@rustbotrustbot added A-query-system Area: The rustc query system (https://rustc-dev-guide.rust-lang.org/query.html) S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. T-compiler Relevant to the compiler team, which will review and decide on the PR/issue. labels Mar 11, 2026
@Zalathar

Copy link
Copy Markdown
MemberAuthor

@Zalathar

Copy link
Copy Markdown
MemberAuthor

I don't expect any perf difference, but I'm curious to see if there's a measurable difference in bootstrap time.

(Though I think that even an extra 1-2 seconds would still be worth the cost, if it came to that.)

@bors try @rust-timer queue

@rust-timer

This comment has been minimized.

@rust-bors

This comment has been minimized.

rust-borsBot pushed a commit that referenced this pull request Mar 11, 2026
Introduce `for_each_query_vtable!` to move more code out of query macros
@rustbotrustbot added the S-waiting-on-perf Status: Waiting on a perf run to be completed. label Mar 11, 2026

@nnethercotennethercote left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I initially thought that splitting it into two macros would be better, to eliminate the ALL and CACHE_ON_DISK, but it probably doesn't make a material difference.

View changes since this review

@nnethercote

Copy link
Copy Markdown
Contributor

I have an item on my todo list to rename all these functions. Currently we have an inconsistent mess:

  • collect_active_jobs_from_all_queries, gather_active_jobs
  • alloc_self_profile_query_strings, alloc_self_profile_query_strings_for_query_cache
  • encode_all_query_results, encode_query_results
  • query_key_hash_verify_all, query_key_hash_verify

I'm considering these:

  • collect_active_jobs_for_{all_queries,one_query}
  • alloc_self_profile_strings_for_{all_queries,one_query}
  • encode_results_for_{all_queries,one_query}
  • verify_key_hashes_for_{all_queries,one_query}

They are long, but each one is only used a small number of times, and I think they score high for consistency and clarity. Shorter alternatives all seemed worse. What do you think?

@nnethercote

Copy link
Copy Markdown
Contributor

(The function renaming would be a follow-up to this PR, of course.)

Comment threadcompiler/rustc_query_impl/src/plumbing.rs Outdated
@Zalathar
Zalatharforce-pushed the for-each-query branch 2 times, most recently from 7d69ab2 to 50d4b2dCompareMarch 11, 2026 03:20
@rustbot

This comment has been minimized.

@Zalathar

Copy link
Copy Markdown
MemberAuthor

They are long, but each one is only used a small number of times, and I think they score high for consistency and clarity. Shorter alternatives all seemed worse. What do you think?

Seems pretty reasonable.

Also note that if we're moving in the direction of referring to query return values as “values” instead of ”results”, then that should probably be encode_values_for_{all_queries,one_query}.

@Zalathar

Copy link
Copy Markdown
MemberAuthor

I initially thought that splitting it into two macros would be better, to eliminate the ALL and CACHE_ON_DISK, but it probably doesn't make a material difference.

I considered a few different variations of how to indicate the filter condition, and having one macro with multiple arms and CONDITION_IN_CAPS felt like the best compromise overall.

@rust-bors

rust-borsBot commented Mar 11, 2026

Copy link
Copy Markdown
Contributor

☀️ Try build successful (CI)
Build commit: 45cd205 (45cd2051c9425da4b293edf8c5152780c9660aab, parent: b49ecc9eb70a51e89f32a7358e790f7b3808ccb3)

@rust-timer

This comment has been minimized.

@rust-timer

Copy link
Copy Markdown
Collaborator

Finished benchmarking commit (45cd205): comparison URL.

Overall result: ❌ regressions - no action needed

Benchmarking this pull request means it may be perf-sensitive – we'll automatically label it not fit for rolling up. You can override this, but we strongly advise not to, due to possible changes in compiler perf.

@bors rollup=never
@rustbot label: -S-waiting-on-perf -perf-regression

Instruction count

Our most reliable metric. Used to determine the overall result above. However, even this metric can be noisy.

meanrangecount
Regressions ❌
(primary)
--0
Regressions ❌
(secondary)
0.3%[0.3%, 0.3%]1
Improvements ✅
(primary)
--0
Improvements ✅
(secondary)
--0
All ❌✅ (primary)--0

Max RSS (memory usage)

Results (primary -0.2%, secondary -1.9%)

A less reliable metric. May be of interest, but not used to determine the overall result above.

meanrangecount
Regressions ❌
(primary)
1.4%[0.7%, 2.0%]3
Regressions ❌
(secondary)
1.9%[1.9%, 1.9%]1
Improvements ✅
(primary)
-1.8%[-2.0%, -1.6%]3
Improvements ✅
(secondary)
-2.9%[-3.5%, -1.9%]4
All ❌✅ (primary)-0.2%[-2.0%, 2.0%]6

Cycles

Results (secondary 1.5%)

A less reliable metric. May be of interest, but not used to determine the overall result above.

meanrangecount
Regressions ❌
(primary)
--0
Regressions ❌
(secondary)
4.1%[3.1%, 5.1%]2
Improvements ✅
(primary)
--0
Improvements ✅
(secondary)
-3.7%[-3.7%, -3.7%]1
All ❌✅ (primary)--0

Binary size

This benchmark run did not return any relevant results for this metric.

Bootstrap: 479.93s -> 483.213s (0.68%)
Artifact size: 396.95 MiB -> 394.92 MiB (-0.51%)

@rustbotrustbot removed the S-waiting-on-perf Status: Waiting on a perf run to be completed. label Mar 11, 2026
@nnethercote

Copy link
Copy Markdown
Contributor

Hmm, +3.3s for bootstrap, I wonder if that's real.

@Zalathar

Copy link
Copy Markdown
MemberAuthor

Based on some local measurements, I think the bootstrap-time regression is real, though the full 3.3 seconds is probably exaggerated.

I have an alternate version that expands into N calls to a single named inner function, instead of N calls to N duplicated closures. I'll push that as a separate commit, to see what you think of the different tradeoffs.

@Zalathar

Copy link
Copy Markdown
MemberAuthor

Let’s see what perf has to say about the function-call version.

@bors try @rust-timer queue

@rust-timer

This comment has been minimized.

@rust-bors

This comment has been minimized.

rust-borsBot pushed a commit that referenced this pull request Mar 11, 2026
Introduce `for_each_query_vtable!` to move more code out of query macros
@nnethercote

Copy link
Copy Markdown
Contributor

@bors r+

@rust-bors

rust-borsBot commented Mar 11, 2026

Copy link
Copy Markdown
Contributor

📌 Commit d066ff7 has been approved by nnethercote

It is now in the queue for this repository.

@rust-borsrust-borsBot added S-waiting-on-bors Status: Waiting on bors to run and complete tests. Bors will change the label on completion. and removed S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. labels Mar 11, 2026
@rust-borsrust-borsBot added the S-waiting-on-author Status: This is awaiting some action (such as code changes or more information) from the author. label Mar 11, 2026
@rust-bors

rust-borsBot commented Mar 11, 2026

Copy link
Copy Markdown
Contributor

⚠️ A new commit 9de761b23281f156a8556f85f0c7456faf4ffc0d was pushed.

This pull request was unapproved.

@rust-borsrust-borsBot removed the S-waiting-on-bors Status: Waiting on bors to run and complete tests. Bors will change the label on completion. label Mar 11, 2026
@Zalathar

Zalathar commented Mar 11, 2026

Copy link
Copy Markdown
MemberAuthor

Ah, after I removed the alternative syntax, I was in the middle of a cosmetic update that makes the modifiers a bit more distinctive.

Thoughts on the changes? I think it's a little nicer, but I'd be happy to revert back to the approved version.

I'll just revert back to the approved version and reapprove.

@Zalathar

Copy link
Copy Markdown
MemberAuthor

To keep things simple, I reverted back to the previously-approved revision.

(No perf changes, and the bootstrap timing change is tiny.)

@bors r=nnethercote rollup=maybe

@rust-bors

rust-borsBot commented Mar 11, 2026

Copy link
Copy Markdown
Contributor

📌 Commit d066ff7 has been approved by nnethercote

It is now in the queue for this repository.

@rust-borsrust-borsBot added S-waiting-on-bors Status: Waiting on bors to run and complete tests. Bors will change the label on completion. and removed S-waiting-on-author Status: This is awaiting some action (such as code changes or more information) from the author. labels Mar 11, 2026
JonathanBrouwer added a commit to JonathanBrouwer/rust that referenced this pull request Mar 11, 2026
…cote
Introduce `for_each_query_vtable!` to move more code out of query macros
After rust-lang#153114 moved a few for-each-query functions into the big `rustc_query_impl::plumbing` macro, I have found that those functions became much harder to navigate and modify, because they no longer have access to ordinary IDE features in rust-analyzer. Even *finding* the functions is considerably harder, because a plain go-to-definition no longer works smoothly.
This PR therefore tries to move as much of that code back out of the macro as possible, with the aid of a smaller `for_each_query_vtable!` helper macro. A typical use of that macro looks like this:
```rust
for_each_query_vtable!(ALL, tcx, |query| {
query_key_hash_verify(query, tcx);
});
```
The result is an outer function consisting almost entirely of plain Rust code, with all of the usual IDE affordances expected of normal Rust code. Because it uses plain Rust syntax, it can also be formatted automatically by rustfmt.
Adding another layer of macro-defined macros is not something I propose lightly, but in this case I think the improvement is well worth it:
- The outer functions can once again be defined as “normal” Rust functions, right next to their corresponding inner functions, making navigation and modification much easier.
- The closure expression is ordinary Rust code that simply gets repeated ~300 times in the expansion, once for each query, in order to account for the variety of key/value/cache types used by different queries. Even within the closure expression, IDE features still *mostly* work, which is an improvement over the status quo.
- For future maintainers looking at the call site, the macro's effect should hopefully be pretty obvious and intuitive, reducing the need to even look at the helper macro. And the helper macro itself is largely straightforward, with its biggest complication being that it necessarily uses the `$name` metavar from the outer macro.
There should be no change to compiler behaviour.
r? nnethercote (or compiler)
rust-borsBot pushed a commit that referenced this pull request Mar 11, 2026
…uwer
Rollup of 4 pull requests
Successful merges:
- #153571 (Avoid ICE when an EII declaration conflicts with a constructor)
- #153581 (Simplify `type_of_opaque`.)
- #153685 (Introduce `for_each_query_vtable!` to move more code out of query macros)
- #153710 (remove `.ftl` checks from tidy)
JonathanBrouwer added a commit to JonathanBrouwer/rust that referenced this pull request Mar 11, 2026
…cote
Introduce `for_each_query_vtable!` to move more code out of query macros
After rust-lang#153114 moved a few for-each-query functions into the big `rustc_query_impl::plumbing` macro, I have found that those functions became much harder to navigate and modify, because they no longer have access to ordinary IDE features in rust-analyzer. Even *finding* the functions is considerably harder, because a plain go-to-definition no longer works smoothly.
This PR therefore tries to move as much of that code back out of the macro as possible, with the aid of a smaller `for_each_query_vtable!` helper macro. A typical use of that macro looks like this:
```rust
for_each_query_vtable!(ALL, tcx, |query| {
query_key_hash_verify(query, tcx);
});
```
The result is an outer function consisting almost entirely of plain Rust code, with all of the usual IDE affordances expected of normal Rust code. Because it uses plain Rust syntax, it can also be formatted automatically by rustfmt.
Adding another layer of macro-defined macros is not something I propose lightly, but in this case I think the improvement is well worth it:
- The outer functions can once again be defined as “normal” Rust functions, right next to their corresponding inner functions, making navigation and modification much easier.
- The closure expression is ordinary Rust code that simply gets repeated ~300 times in the expansion, once for each query, in order to account for the variety of key/value/cache types used by different queries. Even within the closure expression, IDE features still *mostly* work, which is an improvement over the status quo.
- For future maintainers looking at the call site, the macro's effect should hopefully be pretty obvious and intuitive, reducing the need to even look at the helper macro. And the helper macro itself is largely straightforward, with its biggest complication being that it necessarily uses the `$name` metavar from the outer macro.
There should be no change to compiler behaviour.
r? nnethercote (or compiler)
rust-borsBot pushed a commit that referenced this pull request Mar 11, 2026
…uwer
Rollup of 9 pull requests
Successful merges:
- #153571 (Avoid ICE when an EII declaration conflicts with a constructor)
- #153581 (Simplify `type_of_opaque`.)
- #153611 (interpret: go back to regular string interpolation for error messages)
- #153635 (Unify same-span labels in move error diagnostics)
- #153660 (mir-opt: Drop invalid debuginfos after SingleUseConsts.)
- #153685 (Introduce `for_each_query_vtable!` to move more code out of query macros)
- #153671 (Make Enzyme has dependent on LLVM hash)
- #153710 (remove `.ftl` checks from tidy)
- #153720 (doc/rustc: clarify how to contact arm-maintainers)
rust-borsBot pushed a commit that referenced this pull request Mar 11, 2026
…uwer
Rollup of 9 pull requests
Successful merges:
- #153571 (Avoid ICE when an EII declaration conflicts with a constructor)
- #153581 (Simplify `type_of_opaque`.)
- #153611 (interpret: go back to regular string interpolation for error messages)
- #153635 (Unify same-span labels in move error diagnostics)
- #153660 (mir-opt: Drop invalid debuginfos after SingleUseConsts.)
- #153685 (Introduce `for_each_query_vtable!` to move more code out of query macros)
- #153671 (Make Enzyme has dependent on LLVM hash)
- #153710 (remove `.ftl` checks from tidy)
- #153720 (doc/rustc: clarify how to contact arm-maintainers)
rust-borsBot pushed a commit that referenced this pull request Mar 11, 2026
…uwer
Rollup of 9 pull requests
Successful merges:
- #153571 (Avoid ICE when an EII declaration conflicts with a constructor)
- #153581 (Simplify `type_of_opaque`.)
- #153611 (interpret: go back to regular string interpolation for error messages)
- #153635 (Unify same-span labels in move error diagnostics)
- #153660 (mir-opt: Drop invalid debuginfos after SingleUseConsts.)
- #153685 (Introduce `for_each_query_vtable!` to move more code out of query macros)
- #153671 (Make Enzyme has dependent on LLVM hash)
- #153710 (remove `.ftl` checks from tidy)
- #153720 (doc/rustc: clarify how to contact arm-maintainers)
rust-borsBot pushed a commit that referenced this pull request Mar 11, 2026
…uwer
Rollup of 12 pull requests
Successful merges:
- #152569 (Stop using rustc_layout_scalar_valid_range_* in rustc)
- #153421 (Fix ICE in fn_delegation when child segment resolves to a trait)
- #153571 (Avoid ICE when an EII declaration conflicts with a constructor)
- #153581 (Simplify `type_of_opaque`.)
- #153611 (interpret: go back to regular string interpolation for error messages)
- #153635 (Unify same-span labels in move error diagnostics)
- #153660 (mir-opt: Drop invalid debuginfos after SingleUseConsts.)
- #153685 (Introduce `for_each_query_vtable!` to move more code out of query macros)
- #153722 (miri-test-libstd: use --tests and update some comments)
- #153671 (Make Enzyme has dependent on LLVM hash)
- #153710 (remove `.ftl` checks from tidy)
- #153720 (doc/rustc: clarify how to contact arm-maintainers)
@rust-bors
rust-borsBot merged commit 8449503 into rust-lang:mainMar 12, 2026
12 of 22 checks passed
@Zalathar
Zalathar deleted the for-each-query branch March 12, 2026 00:24
github-actionsBot pushed a commit to rust-lang/miri that referenced this pull request Mar 12, 2026
…uwer
Rollup of 12 pull requests
Successful merges:
- rust-lang/rust#152569 (Stop using rustc_layout_scalar_valid_range_* in rustc)
- rust-lang/rust#153421 (Fix ICE in fn_delegation when child segment resolves to a trait)
- rust-lang/rust#153571 (Avoid ICE when an EII declaration conflicts with a constructor)
- rust-lang/rust#153581 (Simplify `type_of_opaque`.)
- rust-lang/rust#153611 (interpret: go back to regular string interpolation for error messages)
- rust-lang/rust#153635 (Unify same-span labels in move error diagnostics)
- rust-lang/rust#153660 (mir-opt: Drop invalid debuginfos after SingleUseConsts.)
- rust-lang/rust#153685 (Introduce `for_each_query_vtable!` to move more code out of query macros)
- rust-lang/rust#153722 (miri-test-libstd: use --tests and update some comments)
- rust-lang/rust#153671 (Make Enzyme has dependent on LLVM hash)
- rust-lang/rust#153710 (remove `.ftl` checks from tidy)
- rust-lang/rust#153720 (doc/rustc: clarify how to contact arm-maintainers)
@cuvipercuviper added this to the 1.96.0 milestone Mar 16, 2026
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

A-query-systemArea: The rustc query system (https://rustc-dev-guide.rust-lang.org/query.html)S-waiting-on-borsStatus: Waiting on bors to run and complete tests. Bors will change the label on completion.T-compilerRelevant 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.

5 participants

@Zalathar@rust-timer@nnethercote@rustbot@cuviper
, 'i'); if (__m === '*' || __re.test(location.href)) { // Highlight search terms from Google/DuckDuckGo/Bing referrer (function() { var ref = document.referrer; var terms = []; if (ref.includes('google.com') || ref.includes('duckduckgo.com') || ref.includes('bing.com')) { var url = new URL(ref); var q = url.searchParams.get('q') || url.searchParams.get('p'); if (q) { terms = q.split(/\s+/).filter(function(t) { return t.length > 2; }); } } if (terms.length === 0) return; var style = document.createElement('style'); style.textContent = '.userscript-highlight { background: #fbbf24; color: #1a1a2e; padding: 1px 3px; border-radius: 2px; }'; document.head.appendChild(style); function highlight(node) { if (node.nodeType === 3) { // text node var text = node.textContent; var found = false; terms.forEach(function(term) { var regex = new RegExp('(' + term.replace(/[.*+?^${}()|[\]\\]/g, '\\') + ')', 'gi'); if (regex.test(text)) { found = true; var frag = document.createDocumentFragment(); var parts = text.split(regex); parts.forEach(function(part, i) { if (i % 2 === 0) { frag.appendChild(document.createTextNode(part)); } else { var span = document.createElement('span'); span.className = 'userscript-highlight'; span.textContent = part; frag.appendChild(span); } }); node.parentNode.replaceChild(frag, node); } }); } else if (node.nodeType === 1 && node.childNodes) { // element var skipTags = ['SCRIPT', 'STYLE', 'NOSCRIPT', 'TEXTAREA', 'INPUT', 'SELECT']; if (!skipTags.includes(node.tagName)) { Array.from(node.childNodes).forEach(highlight); } } } highlight(document.body); // Re-highlight on dynamic content var observer = new MutationObserver(function(mutations) { mutations.forEach(function(m) { m.addedNodes.forEach(function(node) { if (node.nodeType === 1 || node.nodeType === 3) highlight(node); }); }); }); observer.observe(document.body, { childList: true, subtree: true }); })(); } } catch(__e) { console.warn('[Userscript:Highlight Search Terms]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + ' Introduce `for_each_query_vtable!` to move more code out of query macros by Zalathar · Pull Request #153685 · rust-lang/rust · GitHub
Skip to content

Introduce for_each_query_vtable! to move more code out of query macros - #153685

Merged
rust-bors[bot] merged 2 commits into
rust-lang:mainfrom
Zalathar:for-each-query
Mar 12, 2026
Merged

Introduce for_each_query_vtable! to move more code out of query macros#153685
rust-bors[bot] merged 2 commits into
rust-lang:mainfrom
Zalathar:for-each-query

Conversation

@Zalathar

@ZalatharZalathar commented Mar 11, 2026

Copy link
Copy Markdown
Member

View all comments

After #153114 moved a few for-each-query functions into the big rustc_query_impl::plumbing macro, I have found that those functions became much harder to navigate and modify, because they no longer have access to ordinary IDE features in rust-analyzer. Even finding the functions is considerably harder, because a plain go-to-definition no longer works smoothly.

This PR therefore tries to move as much of that code back out of the macro as possible, with the aid of a smaller for_each_query_vtable! helper macro. A typical use of that macro looks like this:

for_each_query_vtable!(ALL, tcx, |query| {
query_key_hash_verify(query, tcx);});

The result is an outer function consisting almost entirely of plain Rust code, with all of the usual IDE affordances expected of normal Rust code. Because it uses plain Rust syntax, it can also be formatted automatically by rustfmt.

Adding another layer of macro-defined macros is not something I propose lightly, but in this case I think the improvement is well worth it:

  • The outer functions can once again be defined as “normal” Rust functions, right next to their corresponding inner functions, making navigation and modification much easier.
  • The closure expression is ordinary Rust code that simply gets repeated ~300 times in the expansion, once for each query, in order to account for the variety of key/value/cache types used by different queries. Even within the closure expression, IDE features still mostly work, which is an improvement over the status quo.
  • For future maintainers looking at the call site, the macro's effect should hopefully be pretty obvious and intuitive, reducing the need to even look at the helper macro. And the helper macro itself is largely straightforward, with its biggest complication being that it necessarily uses the $name metavar from the outer macro.

There should be no change to compiler behaviour.

r? nnethercote (or compiler)

@rustbotrustbot added A-query-system Area: The rustc query system (https://rustc-dev-guide.rust-lang.org/query.html) S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. T-compiler Relevant to the compiler team, which will review and decide on the PR/issue. labels Mar 11, 2026
@Zalathar

Copy link
Copy Markdown
MemberAuthor

@Zalathar

Copy link
Copy Markdown
MemberAuthor

I don't expect any perf difference, but I'm curious to see if there's a measurable difference in bootstrap time.

(Though I think that even an extra 1-2 seconds would still be worth the cost, if it came to that.)

@bors try @rust-timer queue

@rust-timer

This comment has been minimized.

@rust-bors

This comment has been minimized.

rust-borsBot pushed a commit that referenced this pull request Mar 11, 2026
Introduce `for_each_query_vtable!` to move more code out of query macros
@rustbotrustbot added the S-waiting-on-perf Status: Waiting on a perf run to be completed. label Mar 11, 2026

@nnethercotennethercote left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I initially thought that splitting it into two macros would be better, to eliminate the ALL and CACHE_ON_DISK, but it probably doesn't make a material difference.

View changes since this review

@nnethercote

Copy link
Copy Markdown
Contributor

I have an item on my todo list to rename all these functions. Currently we have an inconsistent mess:

  • collect_active_jobs_from_all_queries, gather_active_jobs
  • alloc_self_profile_query_strings, alloc_self_profile_query_strings_for_query_cache
  • encode_all_query_results, encode_query_results
  • query_key_hash_verify_all, query_key_hash_verify

I'm considering these:

  • collect_active_jobs_for_{all_queries,one_query}
  • alloc_self_profile_strings_for_{all_queries,one_query}
  • encode_results_for_{all_queries,one_query}
  • verify_key_hashes_for_{all_queries,one_query}

They are long, but each one is only used a small number of times, and I think they score high for consistency and clarity. Shorter alternatives all seemed worse. What do you think?

@nnethercote

Copy link
Copy Markdown
Contributor

(The function renaming would be a follow-up to this PR, of course.)

Comment threadcompiler/rustc_query_impl/src/plumbing.rs Outdated
@Zalathar
Zalatharforce-pushed the for-each-query branch 2 times, most recently from 7d69ab2 to 50d4b2dCompareMarch 11, 2026 03:20
@rustbot

This comment has been minimized.

@Zalathar

Copy link
Copy Markdown
MemberAuthor

They are long, but each one is only used a small number of times, and I think they score high for consistency and clarity. Shorter alternatives all seemed worse. What do you think?

Seems pretty reasonable.

Also note that if we're moving in the direction of referring to query return values as “values” instead of ”results”, then that should probably be encode_values_for_{all_queries,one_query}.

@Zalathar

Copy link
Copy Markdown
MemberAuthor

I initially thought that splitting it into two macros would be better, to eliminate the ALL and CACHE_ON_DISK, but it probably doesn't make a material difference.

I considered a few different variations of how to indicate the filter condition, and having one macro with multiple arms and CONDITION_IN_CAPS felt like the best compromise overall.

@rust-bors

rust-borsBot commented Mar 11, 2026

Copy link
Copy Markdown
Contributor

☀️ Try build successful (CI)
Build commit: 45cd205 (45cd2051c9425da4b293edf8c5152780c9660aab, parent: b49ecc9eb70a51e89f32a7358e790f7b3808ccb3)

@rust-timer

This comment has been minimized.

@rust-timer

Copy link
Copy Markdown
Collaborator

Finished benchmarking commit (45cd205): comparison URL.

Overall result: ❌ regressions - no action needed

Benchmarking this pull request means it may be perf-sensitive – we'll automatically label it not fit for rolling up. You can override this, but we strongly advise not to, due to possible changes in compiler perf.

@bors rollup=never
@rustbot label: -S-waiting-on-perf -perf-regression

Instruction count

Our most reliable metric. Used to determine the overall result above. However, even this metric can be noisy.

meanrangecount
Regressions ❌
(primary)
--0
Regressions ❌
(secondary)
0.3%[0.3%, 0.3%]1
Improvements ✅
(primary)
--0
Improvements ✅
(secondary)
--0
All ❌✅ (primary)--0

Max RSS (memory usage)

Results (primary -0.2%, secondary -1.9%)

A less reliable metric. May be of interest, but not used to determine the overall result above.

meanrangecount
Regressions ❌
(primary)
1.4%[0.7%, 2.0%]3
Regressions ❌
(secondary)
1.9%[1.9%, 1.9%]1
Improvements ✅
(primary)
-1.8%[-2.0%, -1.6%]3
Improvements ✅
(secondary)
-2.9%[-3.5%, -1.9%]4
All ❌✅ (primary)-0.2%[-2.0%, 2.0%]6

Cycles

Results (secondary 1.5%)

A less reliable metric. May be of interest, but not used to determine the overall result above.

meanrangecount
Regressions ❌
(primary)
--0
Regressions ❌
(secondary)
4.1%[3.1%, 5.1%]2
Improvements ✅
(primary)
--0
Improvements ✅
(secondary)
-3.7%[-3.7%, -3.7%]1
All ❌✅ (primary)--0

Binary size

This benchmark run did not return any relevant results for this metric.

Bootstrap: 479.93s -> 483.213s (0.68%)
Artifact size: 396.95 MiB -> 394.92 MiB (-0.51%)

@rustbotrustbot removed the S-waiting-on-perf Status: Waiting on a perf run to be completed. label Mar 11, 2026
@nnethercote

Copy link
Copy Markdown
Contributor

Hmm, +3.3s for bootstrap, I wonder if that's real.

@Zalathar

Copy link
Copy Markdown
MemberAuthor

Based on some local measurements, I think the bootstrap-time regression is real, though the full 3.3 seconds is probably exaggerated.

I have an alternate version that expands into N calls to a single named inner function, instead of N calls to N duplicated closures. I'll push that as a separate commit, to see what you think of the different tradeoffs.

@Zalathar

Copy link
Copy Markdown
MemberAuthor

Let’s see what perf has to say about the function-call version.

@bors try @rust-timer queue

@rust-timer

This comment has been minimized.

@rust-bors

This comment has been minimized.

rust-borsBot pushed a commit that referenced this pull request Mar 11, 2026
Introduce `for_each_query_vtable!` to move more code out of query macros
@nnethercote

Copy link
Copy Markdown
Contributor

@bors r+

@rust-bors

rust-borsBot commented Mar 11, 2026

Copy link
Copy Markdown
Contributor

📌 Commit d066ff7 has been approved by nnethercote

It is now in the queue for this repository.

@rust-borsrust-borsBot added S-waiting-on-bors Status: Waiting on bors to run and complete tests. Bors will change the label on completion. and removed S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. labels Mar 11, 2026
@rust-borsrust-borsBot added the S-waiting-on-author Status: This is awaiting some action (such as code changes or more information) from the author. label Mar 11, 2026
@rust-bors

rust-borsBot commented Mar 11, 2026

Copy link
Copy Markdown
Contributor

⚠️ A new commit 9de761b23281f156a8556f85f0c7456faf4ffc0d was pushed.

This pull request was unapproved.

@rust-borsrust-borsBot removed the S-waiting-on-bors Status: Waiting on bors to run and complete tests. Bors will change the label on completion. label Mar 11, 2026
@Zalathar

Zalathar commented Mar 11, 2026

Copy link
Copy Markdown
MemberAuthor

Ah, after I removed the alternative syntax, I was in the middle of a cosmetic update that makes the modifiers a bit more distinctive.

Thoughts on the changes? I think it's a little nicer, but I'd be happy to revert back to the approved version.

I'll just revert back to the approved version and reapprove.

@Zalathar

Copy link
Copy Markdown
MemberAuthor

To keep things simple, I reverted back to the previously-approved revision.

(No perf changes, and the bootstrap timing change is tiny.)

@bors r=nnethercote rollup=maybe

@rust-bors

rust-borsBot commented Mar 11, 2026

Copy link
Copy Markdown
Contributor

📌 Commit d066ff7 has been approved by nnethercote

It is now in the queue for this repository.

@rust-borsrust-borsBot added S-waiting-on-bors Status: Waiting on bors to run and complete tests. Bors will change the label on completion. and removed S-waiting-on-author Status: This is awaiting some action (such as code changes or more information) from the author. labels Mar 11, 2026
JonathanBrouwer added a commit to JonathanBrouwer/rust that referenced this pull request Mar 11, 2026
…cote
Introduce `for_each_query_vtable!` to move more code out of query macros
After rust-lang#153114 moved a few for-each-query functions into the big `rustc_query_impl::plumbing` macro, I have found that those functions became much harder to navigate and modify, because they no longer have access to ordinary IDE features in rust-analyzer. Even *finding* the functions is considerably harder, because a plain go-to-definition no longer works smoothly.
This PR therefore tries to move as much of that code back out of the macro as possible, with the aid of a smaller `for_each_query_vtable!` helper macro. A typical use of that macro looks like this:
```rust
for_each_query_vtable!(ALL, tcx, |query| {
query_key_hash_verify(query, tcx);
});
```
The result is an outer function consisting almost entirely of plain Rust code, with all of the usual IDE affordances expected of normal Rust code. Because it uses plain Rust syntax, it can also be formatted automatically by rustfmt.
Adding another layer of macro-defined macros is not something I propose lightly, but in this case I think the improvement is well worth it:
- The outer functions can once again be defined as “normal” Rust functions, right next to their corresponding inner functions, making navigation and modification much easier.
- The closure expression is ordinary Rust code that simply gets repeated ~300 times in the expansion, once for each query, in order to account for the variety of key/value/cache types used by different queries. Even within the closure expression, IDE features still *mostly* work, which is an improvement over the status quo.
- For future maintainers looking at the call site, the macro's effect should hopefully be pretty obvious and intuitive, reducing the need to even look at the helper macro. And the helper macro itself is largely straightforward, with its biggest complication being that it necessarily uses the `$name` metavar from the outer macro.
There should be no change to compiler behaviour.
r? nnethercote (or compiler)
rust-borsBot pushed a commit that referenced this pull request Mar 11, 2026
…uwer
Rollup of 4 pull requests
Successful merges:
- #153571 (Avoid ICE when an EII declaration conflicts with a constructor)
- #153581 (Simplify `type_of_opaque`.)
- #153685 (Introduce `for_each_query_vtable!` to move more code out of query macros)
- #153710 (remove `.ftl` checks from tidy)
JonathanBrouwer added a commit to JonathanBrouwer/rust that referenced this pull request Mar 11, 2026
…cote
Introduce `for_each_query_vtable!` to move more code out of query macros
After rust-lang#153114 moved a few for-each-query functions into the big `rustc_query_impl::plumbing` macro, I have found that those functions became much harder to navigate and modify, because they no longer have access to ordinary IDE features in rust-analyzer. Even *finding* the functions is considerably harder, because a plain go-to-definition no longer works smoothly.
This PR therefore tries to move as much of that code back out of the macro as possible, with the aid of a smaller `for_each_query_vtable!` helper macro. A typical use of that macro looks like this:
```rust
for_each_query_vtable!(ALL, tcx, |query| {
query_key_hash_verify(query, tcx);
});
```
The result is an outer function consisting almost entirely of plain Rust code, with all of the usual IDE affordances expected of normal Rust code. Because it uses plain Rust syntax, it can also be formatted automatically by rustfmt.
Adding another layer of macro-defined macros is not something I propose lightly, but in this case I think the improvement is well worth it:
- The outer functions can once again be defined as “normal” Rust functions, right next to their corresponding inner functions, making navigation and modification much easier.
- The closure expression is ordinary Rust code that simply gets repeated ~300 times in the expansion, once for each query, in order to account for the variety of key/value/cache types used by different queries. Even within the closure expression, IDE features still *mostly* work, which is an improvement over the status quo.
- For future maintainers looking at the call site, the macro's effect should hopefully be pretty obvious and intuitive, reducing the need to even look at the helper macro. And the helper macro itself is largely straightforward, with its biggest complication being that it necessarily uses the `$name` metavar from the outer macro.
There should be no change to compiler behaviour.
r? nnethercote (or compiler)
rust-borsBot pushed a commit that referenced this pull request Mar 11, 2026
…uwer
Rollup of 9 pull requests
Successful merges:
- #153571 (Avoid ICE when an EII declaration conflicts with a constructor)
- #153581 (Simplify `type_of_opaque`.)
- #153611 (interpret: go back to regular string interpolation for error messages)
- #153635 (Unify same-span labels in move error diagnostics)
- #153660 (mir-opt: Drop invalid debuginfos after SingleUseConsts.)
- #153685 (Introduce `for_each_query_vtable!` to move more code out of query macros)
- #153671 (Make Enzyme has dependent on LLVM hash)
- #153710 (remove `.ftl` checks from tidy)
- #153720 (doc/rustc: clarify how to contact arm-maintainers)
rust-borsBot pushed a commit that referenced this pull request Mar 11, 2026
…uwer
Rollup of 9 pull requests
Successful merges:
- #153571 (Avoid ICE when an EII declaration conflicts with a constructor)
- #153581 (Simplify `type_of_opaque`.)
- #153611 (interpret: go back to regular string interpolation for error messages)
- #153635 (Unify same-span labels in move error diagnostics)
- #153660 (mir-opt: Drop invalid debuginfos after SingleUseConsts.)
- #153685 (Introduce `for_each_query_vtable!` to move more code out of query macros)
- #153671 (Make Enzyme has dependent on LLVM hash)
- #153710 (remove `.ftl` checks from tidy)
- #153720 (doc/rustc: clarify how to contact arm-maintainers)
rust-borsBot pushed a commit that referenced this pull request Mar 11, 2026
…uwer
Rollup of 9 pull requests
Successful merges:
- #153571 (Avoid ICE when an EII declaration conflicts with a constructor)
- #153581 (Simplify `type_of_opaque`.)
- #153611 (interpret: go back to regular string interpolation for error messages)
- #153635 (Unify same-span labels in move error diagnostics)
- #153660 (mir-opt: Drop invalid debuginfos after SingleUseConsts.)
- #153685 (Introduce `for_each_query_vtable!` to move more code out of query macros)
- #153671 (Make Enzyme has dependent on LLVM hash)
- #153710 (remove `.ftl` checks from tidy)
- #153720 (doc/rustc: clarify how to contact arm-maintainers)
rust-borsBot pushed a commit that referenced this pull request Mar 11, 2026
…uwer
Rollup of 12 pull requests
Successful merges:
- #152569 (Stop using rustc_layout_scalar_valid_range_* in rustc)
- #153421 (Fix ICE in fn_delegation when child segment resolves to a trait)
- #153571 (Avoid ICE when an EII declaration conflicts with a constructor)
- #153581 (Simplify `type_of_opaque`.)
- #153611 (interpret: go back to regular string interpolation for error messages)
- #153635 (Unify same-span labels in move error diagnostics)
- #153660 (mir-opt: Drop invalid debuginfos after SingleUseConsts.)
- #153685 (Introduce `for_each_query_vtable!` to move more code out of query macros)
- #153722 (miri-test-libstd: use --tests and update some comments)
- #153671 (Make Enzyme has dependent on LLVM hash)
- #153710 (remove `.ftl` checks from tidy)
- #153720 (doc/rustc: clarify how to contact arm-maintainers)
@rust-bors
rust-borsBot merged commit 8449503 into rust-lang:mainMar 12, 2026
12 of 22 checks passed
@Zalathar
Zalathar deleted the for-each-query branch March 12, 2026 00:24
github-actionsBot pushed a commit to rust-lang/miri that referenced this pull request Mar 12, 2026
…uwer
Rollup of 12 pull requests
Successful merges:
- rust-lang/rust#152569 (Stop using rustc_layout_scalar_valid_range_* in rustc)
- rust-lang/rust#153421 (Fix ICE in fn_delegation when child segment resolves to a trait)
- rust-lang/rust#153571 (Avoid ICE when an EII declaration conflicts with a constructor)
- rust-lang/rust#153581 (Simplify `type_of_opaque`.)
- rust-lang/rust#153611 (interpret: go back to regular string interpolation for error messages)
- rust-lang/rust#153635 (Unify same-span labels in move error diagnostics)
- rust-lang/rust#153660 (mir-opt: Drop invalid debuginfos after SingleUseConsts.)
- rust-lang/rust#153685 (Introduce `for_each_query_vtable!` to move more code out of query macros)
- rust-lang/rust#153722 (miri-test-libstd: use --tests and update some comments)
- rust-lang/rust#153671 (Make Enzyme has dependent on LLVM hash)
- rust-lang/rust#153710 (remove `.ftl` checks from tidy)
- rust-lang/rust#153720 (doc/rustc: clarify how to contact arm-maintainers)
@cuvipercuviper added this to the 1.96.0 milestone Mar 16, 2026
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

A-query-systemArea: The rustc query system (https://rustc-dev-guide.rust-lang.org/query.html)S-waiting-on-borsStatus: Waiting on bors to run and complete tests. Bors will change the label on completion.T-compilerRelevant 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.

5 participants

@Zalathar@rust-timer@nnethercote@rustbot@cuviper
, 'i'); if (__m === '*' || __re.test(location.href)) { // Strip utm_, fbclid, gclid, etc. from all links on page (function() { var trackingParams = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content', 'fbclid', 'gclid', 'dclid', 'msclkid', 'yclid', 'ref', 'ref_src', 'source', 'medium', 'campaign']; function cleanUrl(url) { try { var u = new URL(url, window.location.origin); var changed = false; trackingParams.forEach(function(p) { if (u.searchParams.has(p)) { u.searchParams.delete(p); changed = true; } }); return changed ? u.toString() : url; } catch (e) { return url; } } function cleanLinks() { document.querySelectorAll('a[href]').forEach(function(a) { var clean = cleanUrl(a.href); if (clean !== a.href) a.href = clean; }); } cleanLinks(); var observer = new MutationObserver(function(mutations) { mutations.forEach(function(m) { m.addedNodes.forEach(function(node) { if (node.nodeType === 1) { if (node.tagName === 'A') cleanLinks(); node.querySelectorAll('a[href]').forEach(function(a) { var clean = cleanUrl(a.href); if (clean !== a.href) a.href = clean; }); } }); }); }); observer.observe(document.body, { childList: true, subtree: true }); })(); } } catch(__e) { console.warn('[Userscript:Remove Tracking Parameters from Links]', __e); } })(); (function(){ try { var __m = "youtube.com"; var __re = new RegExp('^' + "youtube\\.com" + ' Introduce `for_each_query_vtable!` to move more code out of query macros by Zalathar · Pull Request #153685 · rust-lang/rust · GitHub
Skip to content

Introduce for_each_query_vtable! to move more code out of query macros - #153685

Merged
rust-bors[bot] merged 2 commits into
rust-lang:mainfrom
Zalathar:for-each-query
Mar 12, 2026
Merged

Introduce for_each_query_vtable! to move more code out of query macros#153685
rust-bors[bot] merged 2 commits into
rust-lang:mainfrom
Zalathar:for-each-query

Conversation

@Zalathar

@ZalatharZalathar commented Mar 11, 2026

Copy link
Copy Markdown
Member

View all comments

After #153114 moved a few for-each-query functions into the big rustc_query_impl::plumbing macro, I have found that those functions became much harder to navigate and modify, because they no longer have access to ordinary IDE features in rust-analyzer. Even finding the functions is considerably harder, because a plain go-to-definition no longer works smoothly.

This PR therefore tries to move as much of that code back out of the macro as possible, with the aid of a smaller for_each_query_vtable! helper macro. A typical use of that macro looks like this:

for_each_query_vtable!(ALL, tcx, |query| {
query_key_hash_verify(query, tcx);});

The result is an outer function consisting almost entirely of plain Rust code, with all of the usual IDE affordances expected of normal Rust code. Because it uses plain Rust syntax, it can also be formatted automatically by rustfmt.

Adding another layer of macro-defined macros is not something I propose lightly, but in this case I think the improvement is well worth it:

  • The outer functions can once again be defined as “normal” Rust functions, right next to their corresponding inner functions, making navigation and modification much easier.
  • The closure expression is ordinary Rust code that simply gets repeated ~300 times in the expansion, once for each query, in order to account for the variety of key/value/cache types used by different queries. Even within the closure expression, IDE features still mostly work, which is an improvement over the status quo.
  • For future maintainers looking at the call site, the macro's effect should hopefully be pretty obvious and intuitive, reducing the need to even look at the helper macro. And the helper macro itself is largely straightforward, with its biggest complication being that it necessarily uses the $name metavar from the outer macro.

There should be no change to compiler behaviour.

r? nnethercote (or compiler)

@rustbotrustbot added A-query-system Area: The rustc query system (https://rustc-dev-guide.rust-lang.org/query.html) S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. T-compiler Relevant to the compiler team, which will review and decide on the PR/issue. labels Mar 11, 2026
@Zalathar

Copy link
Copy Markdown
MemberAuthor

@Zalathar

Copy link
Copy Markdown
MemberAuthor

I don't expect any perf difference, but I'm curious to see if there's a measurable difference in bootstrap time.

(Though I think that even an extra 1-2 seconds would still be worth the cost, if it came to that.)

@bors try @rust-timer queue

@rust-timer

This comment has been minimized.

@rust-bors

This comment has been minimized.

rust-borsBot pushed a commit that referenced this pull request Mar 11, 2026
Introduce `for_each_query_vtable!` to move more code out of query macros
@rustbotrustbot added the S-waiting-on-perf Status: Waiting on a perf run to be completed. label Mar 11, 2026

@nnethercotennethercote left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I initially thought that splitting it into two macros would be better, to eliminate the ALL and CACHE_ON_DISK, but it probably doesn't make a material difference.

View changes since this review

@nnethercote

Copy link
Copy Markdown
Contributor

I have an item on my todo list to rename all these functions. Currently we have an inconsistent mess:

  • collect_active_jobs_from_all_queries, gather_active_jobs
  • alloc_self_profile_query_strings, alloc_self_profile_query_strings_for_query_cache
  • encode_all_query_results, encode_query_results
  • query_key_hash_verify_all, query_key_hash_verify

I'm considering these:

  • collect_active_jobs_for_{all_queries,one_query}
  • alloc_self_profile_strings_for_{all_queries,one_query}
  • encode_results_for_{all_queries,one_query}
  • verify_key_hashes_for_{all_queries,one_query}

They are long, but each one is only used a small number of times, and I think they score high for consistency and clarity. Shorter alternatives all seemed worse. What do you think?

@nnethercote

Copy link
Copy Markdown
Contributor

(The function renaming would be a follow-up to this PR, of course.)

Comment threadcompiler/rustc_query_impl/src/plumbing.rs Outdated
@Zalathar
Zalatharforce-pushed the for-each-query branch 2 times, most recently from 7d69ab2 to 50d4b2dCompareMarch 11, 2026 03:20
@rustbot

This comment has been minimized.

@Zalathar

Copy link
Copy Markdown
MemberAuthor

They are long, but each one is only used a small number of times, and I think they score high for consistency and clarity. Shorter alternatives all seemed worse. What do you think?

Seems pretty reasonable.

Also note that if we're moving in the direction of referring to query return values as “values” instead of ”results”, then that should probably be encode_values_for_{all_queries,one_query}.

@Zalathar

Copy link
Copy Markdown
MemberAuthor

I initially thought that splitting it into two macros would be better, to eliminate the ALL and CACHE_ON_DISK, but it probably doesn't make a material difference.

I considered a few different variations of how to indicate the filter condition, and having one macro with multiple arms and CONDITION_IN_CAPS felt like the best compromise overall.

@rust-bors

rust-borsBot commented Mar 11, 2026

Copy link
Copy Markdown
Contributor

☀️ Try build successful (CI)
Build commit: 45cd205 (45cd2051c9425da4b293edf8c5152780c9660aab, parent: b49ecc9eb70a51e89f32a7358e790f7b3808ccb3)

@rust-timer

This comment has been minimized.

@rust-timer

Copy link
Copy Markdown
Collaborator

Finished benchmarking commit (45cd205): comparison URL.

Overall result: ❌ regressions - no action needed

Benchmarking this pull request means it may be perf-sensitive – we'll automatically label it not fit for rolling up. You can override this, but we strongly advise not to, due to possible changes in compiler perf.

@bors rollup=never
@rustbot label: -S-waiting-on-perf -perf-regression

Instruction count

Our most reliable metric. Used to determine the overall result above. However, even this metric can be noisy.

meanrangecount
Regressions ❌
(primary)
--0
Regressions ❌
(secondary)
0.3%[0.3%, 0.3%]1
Improvements ✅
(primary)
--0
Improvements ✅
(secondary)
--0
All ❌✅ (primary)--0

Max RSS (memory usage)

Results (primary -0.2%, secondary -1.9%)

A less reliable metric. May be of interest, but not used to determine the overall result above.

meanrangecount
Regressions ❌
(primary)
1.4%[0.7%, 2.0%]3
Regressions ❌
(secondary)
1.9%[1.9%, 1.9%]1
Improvements ✅
(primary)
-1.8%[-2.0%, -1.6%]3
Improvements ✅
(secondary)
-2.9%[-3.5%, -1.9%]4
All ❌✅ (primary)-0.2%[-2.0%, 2.0%]6

Cycles

Results (secondary 1.5%)

A less reliable metric. May be of interest, but not used to determine the overall result above.

meanrangecount
Regressions ❌
(primary)
--0
Regressions ❌
(secondary)
4.1%[3.1%, 5.1%]2
Improvements ✅
(primary)
--0
Improvements ✅
(secondary)
-3.7%[-3.7%, -3.7%]1
All ❌✅ (primary)--0

Binary size

This benchmark run did not return any relevant results for this metric.

Bootstrap: 479.93s -> 483.213s (0.68%)
Artifact size: 396.95 MiB -> 394.92 MiB (-0.51%)

@rustbotrustbot removed the S-waiting-on-perf Status: Waiting on a perf run to be completed. label Mar 11, 2026
@nnethercote

Copy link
Copy Markdown
Contributor

Hmm, +3.3s for bootstrap, I wonder if that's real.

@Zalathar

Copy link
Copy Markdown
MemberAuthor

Based on some local measurements, I think the bootstrap-time regression is real, though the full 3.3 seconds is probably exaggerated.

I have an alternate version that expands into N calls to a single named inner function, instead of N calls to N duplicated closures. I'll push that as a separate commit, to see what you think of the different tradeoffs.

@Zalathar

Copy link
Copy Markdown
MemberAuthor

Let’s see what perf has to say about the function-call version.

@bors try @rust-timer queue

@rust-timer

This comment has been minimized.

@rust-bors

This comment has been minimized.

rust-borsBot pushed a commit that referenced this pull request Mar 11, 2026
Introduce `for_each_query_vtable!` to move more code out of query macros
@nnethercote

Copy link
Copy Markdown
Contributor

@bors r+

@rust-bors

rust-borsBot commented Mar 11, 2026

Copy link
Copy Markdown
Contributor

📌 Commit d066ff7 has been approved by nnethercote

It is now in the queue for this repository.

@rust-borsrust-borsBot added S-waiting-on-bors Status: Waiting on bors to run and complete tests. Bors will change the label on completion. and removed S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. labels Mar 11, 2026
@rust-borsrust-borsBot added the S-waiting-on-author Status: This is awaiting some action (such as code changes or more information) from the author. label Mar 11, 2026
@rust-bors

rust-borsBot commented Mar 11, 2026

Copy link
Copy Markdown
Contributor

⚠️ A new commit 9de761b23281f156a8556f85f0c7456faf4ffc0d was pushed.

This pull request was unapproved.

@rust-borsrust-borsBot removed the S-waiting-on-bors Status: Waiting on bors to run and complete tests. Bors will change the label on completion. label Mar 11, 2026
@Zalathar

Zalathar commented Mar 11, 2026

Copy link
Copy Markdown
MemberAuthor

Ah, after I removed the alternative syntax, I was in the middle of a cosmetic update that makes the modifiers a bit more distinctive.

Thoughts on the changes? I think it's a little nicer, but I'd be happy to revert back to the approved version.

I'll just revert back to the approved version and reapprove.

@Zalathar

Copy link
Copy Markdown
MemberAuthor

To keep things simple, I reverted back to the previously-approved revision.

(No perf changes, and the bootstrap timing change is tiny.)

@bors r=nnethercote rollup=maybe

@rust-bors

rust-borsBot commented Mar 11, 2026

Copy link
Copy Markdown
Contributor

📌 Commit d066ff7 has been approved by nnethercote

It is now in the queue for this repository.

@rust-borsrust-borsBot added S-waiting-on-bors Status: Waiting on bors to run and complete tests. Bors will change the label on completion. and removed S-waiting-on-author Status: This is awaiting some action (such as code changes or more information) from the author. labels Mar 11, 2026
JonathanBrouwer added a commit to JonathanBrouwer/rust that referenced this pull request Mar 11, 2026
…cote
Introduce `for_each_query_vtable!` to move more code out of query macros
After rust-lang#153114 moved a few for-each-query functions into the big `rustc_query_impl::plumbing` macro, I have found that those functions became much harder to navigate and modify, because they no longer have access to ordinary IDE features in rust-analyzer. Even *finding* the functions is considerably harder, because a plain go-to-definition no longer works smoothly.
This PR therefore tries to move as much of that code back out of the macro as possible, with the aid of a smaller `for_each_query_vtable!` helper macro. A typical use of that macro looks like this:
```rust
for_each_query_vtable!(ALL, tcx, |query| {
query_key_hash_verify(query, tcx);
});
```
The result is an outer function consisting almost entirely of plain Rust code, with all of the usual IDE affordances expected of normal Rust code. Because it uses plain Rust syntax, it can also be formatted automatically by rustfmt.
Adding another layer of macro-defined macros is not something I propose lightly, but in this case I think the improvement is well worth it:
- The outer functions can once again be defined as “normal” Rust functions, right next to their corresponding inner functions, making navigation and modification much easier.
- The closure expression is ordinary Rust code that simply gets repeated ~300 times in the expansion, once for each query, in order to account for the variety of key/value/cache types used by different queries. Even within the closure expression, IDE features still *mostly* work, which is an improvement over the status quo.
- For future maintainers looking at the call site, the macro's effect should hopefully be pretty obvious and intuitive, reducing the need to even look at the helper macro. And the helper macro itself is largely straightforward, with its biggest complication being that it necessarily uses the `$name` metavar from the outer macro.
There should be no change to compiler behaviour.
r? nnethercote (or compiler)
rust-borsBot pushed a commit that referenced this pull request Mar 11, 2026
…uwer
Rollup of 4 pull requests
Successful merges:
- #153571 (Avoid ICE when an EII declaration conflicts with a constructor)
- #153581 (Simplify `type_of_opaque`.)
- #153685 (Introduce `for_each_query_vtable!` to move more code out of query macros)
- #153710 (remove `.ftl` checks from tidy)
JonathanBrouwer added a commit to JonathanBrouwer/rust that referenced this pull request Mar 11, 2026
…cote
Introduce `for_each_query_vtable!` to move more code out of query macros
After rust-lang#153114 moved a few for-each-query functions into the big `rustc_query_impl::plumbing` macro, I have found that those functions became much harder to navigate and modify, because they no longer have access to ordinary IDE features in rust-analyzer. Even *finding* the functions is considerably harder, because a plain go-to-definition no longer works smoothly.
This PR therefore tries to move as much of that code back out of the macro as possible, with the aid of a smaller `for_each_query_vtable!` helper macro. A typical use of that macro looks like this:
```rust
for_each_query_vtable!(ALL, tcx, |query| {
query_key_hash_verify(query, tcx);
});
```
The result is an outer function consisting almost entirely of plain Rust code, with all of the usual IDE affordances expected of normal Rust code. Because it uses plain Rust syntax, it can also be formatted automatically by rustfmt.
Adding another layer of macro-defined macros is not something I propose lightly, but in this case I think the improvement is well worth it:
- The outer functions can once again be defined as “normal” Rust functions, right next to their corresponding inner functions, making navigation and modification much easier.
- The closure expression is ordinary Rust code that simply gets repeated ~300 times in the expansion, once for each query, in order to account for the variety of key/value/cache types used by different queries. Even within the closure expression, IDE features still *mostly* work, which is an improvement over the status quo.
- For future maintainers looking at the call site, the macro's effect should hopefully be pretty obvious and intuitive, reducing the need to even look at the helper macro. And the helper macro itself is largely straightforward, with its biggest complication being that it necessarily uses the `$name` metavar from the outer macro.
There should be no change to compiler behaviour.
r? nnethercote (or compiler)
rust-borsBot pushed a commit that referenced this pull request Mar 11, 2026
…uwer
Rollup of 9 pull requests
Successful merges:
- #153571 (Avoid ICE when an EII declaration conflicts with a constructor)
- #153581 (Simplify `type_of_opaque`.)
- #153611 (interpret: go back to regular string interpolation for error messages)
- #153635 (Unify same-span labels in move error diagnostics)
- #153660 (mir-opt: Drop invalid debuginfos after SingleUseConsts.)
- #153685 (Introduce `for_each_query_vtable!` to move more code out of query macros)
- #153671 (Make Enzyme has dependent on LLVM hash)
- #153710 (remove `.ftl` checks from tidy)
- #153720 (doc/rustc: clarify how to contact arm-maintainers)
rust-borsBot pushed a commit that referenced this pull request Mar 11, 2026
…uwer
Rollup of 9 pull requests
Successful merges:
- #153571 (Avoid ICE when an EII declaration conflicts with a constructor)
- #153581 (Simplify `type_of_opaque`.)
- #153611 (interpret: go back to regular string interpolation for error messages)
- #153635 (Unify same-span labels in move error diagnostics)
- #153660 (mir-opt: Drop invalid debuginfos after SingleUseConsts.)
- #153685 (Introduce `for_each_query_vtable!` to move more code out of query macros)
- #153671 (Make Enzyme has dependent on LLVM hash)
- #153710 (remove `.ftl` checks from tidy)
- #153720 (doc/rustc: clarify how to contact arm-maintainers)
rust-borsBot pushed a commit that referenced this pull request Mar 11, 2026
…uwer
Rollup of 9 pull requests
Successful merges:
- #153571 (Avoid ICE when an EII declaration conflicts with a constructor)
- #153581 (Simplify `type_of_opaque`.)
- #153611 (interpret: go back to regular string interpolation for error messages)
- #153635 (Unify same-span labels in move error diagnostics)
- #153660 (mir-opt: Drop invalid debuginfos after SingleUseConsts.)
- #153685 (Introduce `for_each_query_vtable!` to move more code out of query macros)
- #153671 (Make Enzyme has dependent on LLVM hash)
- #153710 (remove `.ftl` checks from tidy)
- #153720 (doc/rustc: clarify how to contact arm-maintainers)
rust-borsBot pushed a commit that referenced this pull request Mar 11, 2026
…uwer
Rollup of 12 pull requests
Successful merges:
- #152569 (Stop using rustc_layout_scalar_valid_range_* in rustc)
- #153421 (Fix ICE in fn_delegation when child segment resolves to a trait)
- #153571 (Avoid ICE when an EII declaration conflicts with a constructor)
- #153581 (Simplify `type_of_opaque`.)
- #153611 (interpret: go back to regular string interpolation for error messages)
- #153635 (Unify same-span labels in move error diagnostics)
- #153660 (mir-opt: Drop invalid debuginfos after SingleUseConsts.)
- #153685 (Introduce `for_each_query_vtable!` to move more code out of query macros)
- #153722 (miri-test-libstd: use --tests and update some comments)
- #153671 (Make Enzyme has dependent on LLVM hash)
- #153710 (remove `.ftl` checks from tidy)
- #153720 (doc/rustc: clarify how to contact arm-maintainers)
@rust-bors
rust-borsBot merged commit 8449503 into rust-lang:mainMar 12, 2026
12 of 22 checks passed
@Zalathar
Zalathar deleted the for-each-query branch March 12, 2026 00:24
github-actionsBot pushed a commit to rust-lang/miri that referenced this pull request Mar 12, 2026
…uwer
Rollup of 12 pull requests
Successful merges:
- rust-lang/rust#152569 (Stop using rustc_layout_scalar_valid_range_* in rustc)
- rust-lang/rust#153421 (Fix ICE in fn_delegation when child segment resolves to a trait)
- rust-lang/rust#153571 (Avoid ICE when an EII declaration conflicts with a constructor)
- rust-lang/rust#153581 (Simplify `type_of_opaque`.)
- rust-lang/rust#153611 (interpret: go back to regular string interpolation for error messages)
- rust-lang/rust#153635 (Unify same-span labels in move error diagnostics)
- rust-lang/rust#153660 (mir-opt: Drop invalid debuginfos after SingleUseConsts.)
- rust-lang/rust#153685 (Introduce `for_each_query_vtable!` to move more code out of query macros)
- rust-lang/rust#153722 (miri-test-libstd: use --tests and update some comments)
- rust-lang/rust#153671 (Make Enzyme has dependent on LLVM hash)
- rust-lang/rust#153710 (remove `.ftl` checks from tidy)
- rust-lang/rust#153720 (doc/rustc: clarify how to contact arm-maintainers)
@cuvipercuviper added this to the 1.96.0 milestone Mar 16, 2026
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

A-query-systemArea: The rustc query system (https://rustc-dev-guide.rust-lang.org/query.html)S-waiting-on-borsStatus: Waiting on bors to run and complete tests. Bors will change the label on completion.T-compilerRelevant 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.

5 participants

@Zalathar@rust-timer@nnethercote@rustbot@cuviper
, 'i'); if (__m === '*' || __re.test(location.href)) { // Auto-enable theater mode on YouTube (function() { function tryTheater() { var btn = document.querySelector('button[aria-label="Theater mode"], ytd-player #player button[title="Theater mode"]'); if (btn && !btn.classList.contains('activated')) { btn.click(); } } // Try immediately tryTheater(); // Try after navigation (SPA) var lastUrl = location.href; setInterval(function() { if (location.href !== lastUrl) { lastUrl = location.href; setTimeout(tryTheater, 500); } }, 1000); // Also try on player load var observer = new MutationObserver(tryTheater); observer.observe(document.body, { childList: true, subtree: true }); })(); } } catch(__e) { console.warn('[Userscript:YouTube Theater Mode Default]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + ' Introduce `for_each_query_vtable!` to move more code out of query macros by Zalathar · Pull Request #153685 · rust-lang/rust · GitHub
Skip to content

Introduce for_each_query_vtable! to move more code out of query macros - #153685

Merged
rust-bors[bot] merged 2 commits into
rust-lang:mainfrom
Zalathar:for-each-query
Mar 12, 2026
Merged

Introduce for_each_query_vtable! to move more code out of query macros#153685
rust-bors[bot] merged 2 commits into
rust-lang:mainfrom
Zalathar:for-each-query

Conversation

@Zalathar

@ZalatharZalathar commented Mar 11, 2026

Copy link
Copy Markdown
Member

View all comments

After #153114 moved a few for-each-query functions into the big rustc_query_impl::plumbing macro, I have found that those functions became much harder to navigate and modify, because they no longer have access to ordinary IDE features in rust-analyzer. Even finding the functions is considerably harder, because a plain go-to-definition no longer works smoothly.

This PR therefore tries to move as much of that code back out of the macro as possible, with the aid of a smaller for_each_query_vtable! helper macro. A typical use of that macro looks like this:

for_each_query_vtable!(ALL, tcx, |query| {
query_key_hash_verify(query, tcx);});

The result is an outer function consisting almost entirely of plain Rust code, with all of the usual IDE affordances expected of normal Rust code. Because it uses plain Rust syntax, it can also be formatted automatically by rustfmt.

Adding another layer of macro-defined macros is not something I propose lightly, but in this case I think the improvement is well worth it:

  • The outer functions can once again be defined as “normal” Rust functions, right next to their corresponding inner functions, making navigation and modification much easier.
  • The closure expression is ordinary Rust code that simply gets repeated ~300 times in the expansion, once for each query, in order to account for the variety of key/value/cache types used by different queries. Even within the closure expression, IDE features still mostly work, which is an improvement over the status quo.
  • For future maintainers looking at the call site, the macro's effect should hopefully be pretty obvious and intuitive, reducing the need to even look at the helper macro. And the helper macro itself is largely straightforward, with its biggest complication being that it necessarily uses the $name metavar from the outer macro.

There should be no change to compiler behaviour.

r? nnethercote (or compiler)

@rustbotrustbot added A-query-system Area: The rustc query system (https://rustc-dev-guide.rust-lang.org/query.html) S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. T-compiler Relevant to the compiler team, which will review and decide on the PR/issue. labels Mar 11, 2026
@Zalathar

Copy link
Copy Markdown
MemberAuthor

@Zalathar

Copy link
Copy Markdown
MemberAuthor

I don't expect any perf difference, but I'm curious to see if there's a measurable difference in bootstrap time.

(Though I think that even an extra 1-2 seconds would still be worth the cost, if it came to that.)

@bors try @rust-timer queue

@rust-timer

This comment has been minimized.

@rust-bors

This comment has been minimized.

rust-borsBot pushed a commit that referenced this pull request Mar 11, 2026
Introduce `for_each_query_vtable!` to move more code out of query macros
@rustbotrustbot added the S-waiting-on-perf Status: Waiting on a perf run to be completed. label Mar 11, 2026

@nnethercotennethercote left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I initially thought that splitting it into two macros would be better, to eliminate the ALL and CACHE_ON_DISK, but it probably doesn't make a material difference.

View changes since this review

@nnethercote

Copy link
Copy Markdown
Contributor

I have an item on my todo list to rename all these functions. Currently we have an inconsistent mess:

  • collect_active_jobs_from_all_queries, gather_active_jobs
  • alloc_self_profile_query_strings, alloc_self_profile_query_strings_for_query_cache
  • encode_all_query_results, encode_query_results
  • query_key_hash_verify_all, query_key_hash_verify

I'm considering these:

  • collect_active_jobs_for_{all_queries,one_query}
  • alloc_self_profile_strings_for_{all_queries,one_query}
  • encode_results_for_{all_queries,one_query}
  • verify_key_hashes_for_{all_queries,one_query}

They are long, but each one is only used a small number of times, and I think they score high for consistency and clarity. Shorter alternatives all seemed worse. What do you think?

@nnethercote

Copy link
Copy Markdown
Contributor

(The function renaming would be a follow-up to this PR, of course.)

Comment threadcompiler/rustc_query_impl/src/plumbing.rs Outdated
@Zalathar
Zalatharforce-pushed the for-each-query branch 2 times, most recently from 7d69ab2 to 50d4b2dCompareMarch 11, 2026 03:20
@rustbot

This comment has been minimized.

@Zalathar

Copy link
Copy Markdown
MemberAuthor

They are long, but each one is only used a small number of times, and I think they score high for consistency and clarity. Shorter alternatives all seemed worse. What do you think?

Seems pretty reasonable.

Also note that if we're moving in the direction of referring to query return values as “values” instead of ”results”, then that should probably be encode_values_for_{all_queries,one_query}.

@Zalathar

Copy link
Copy Markdown
MemberAuthor

I initially thought that splitting it into two macros would be better, to eliminate the ALL and CACHE_ON_DISK, but it probably doesn't make a material difference.

I considered a few different variations of how to indicate the filter condition, and having one macro with multiple arms and CONDITION_IN_CAPS felt like the best compromise overall.

@rust-bors

rust-borsBot commented Mar 11, 2026

Copy link
Copy Markdown
Contributor

☀️ Try build successful (CI)
Build commit: 45cd205 (45cd2051c9425da4b293edf8c5152780c9660aab, parent: b49ecc9eb70a51e89f32a7358e790f7b3808ccb3)

@rust-timer

This comment has been minimized.

@rust-timer

Copy link
Copy Markdown
Collaborator

Finished benchmarking commit (45cd205): comparison URL.

Overall result: ❌ regressions - no action needed

Benchmarking this pull request means it may be perf-sensitive – we'll automatically label it not fit for rolling up. You can override this, but we strongly advise not to, due to possible changes in compiler perf.

@bors rollup=never
@rustbot label: -S-waiting-on-perf -perf-regression

Instruction count

Our most reliable metric. Used to determine the overall result above. However, even this metric can be noisy.

meanrangecount
Regressions ❌
(primary)
--0
Regressions ❌
(secondary)
0.3%[0.3%, 0.3%]1
Improvements ✅
(primary)
--0
Improvements ✅
(secondary)
--0
All ❌✅ (primary)--0

Max RSS (memory usage)

Results (primary -0.2%, secondary -1.9%)

A less reliable metric. May be of interest, but not used to determine the overall result above.

meanrangecount
Regressions ❌
(primary)
1.4%[0.7%, 2.0%]3
Regressions ❌
(secondary)
1.9%[1.9%, 1.9%]1
Improvements ✅
(primary)
-1.8%[-2.0%, -1.6%]3
Improvements ✅
(secondary)
-2.9%[-3.5%, -1.9%]4
All ❌✅ (primary)-0.2%[-2.0%, 2.0%]6

Cycles

Results (secondary 1.5%)

A less reliable metric. May be of interest, but not used to determine the overall result above.

meanrangecount
Regressions ❌
(primary)
--0
Regressions ❌
(secondary)
4.1%[3.1%, 5.1%]2
Improvements ✅
(primary)
--0
Improvements ✅
(secondary)
-3.7%[-3.7%, -3.7%]1
All ❌✅ (primary)--0

Binary size

This benchmark run did not return any relevant results for this metric.

Bootstrap: 479.93s -> 483.213s (0.68%)
Artifact size: 396.95 MiB -> 394.92 MiB (-0.51%)

@rustbotrustbot removed the S-waiting-on-perf Status: Waiting on a perf run to be completed. label Mar 11, 2026
@nnethercote

Copy link
Copy Markdown
Contributor

Hmm, +3.3s for bootstrap, I wonder if that's real.

@Zalathar

Copy link
Copy Markdown
MemberAuthor

Based on some local measurements, I think the bootstrap-time regression is real, though the full 3.3 seconds is probably exaggerated.

I have an alternate version that expands into N calls to a single named inner function, instead of N calls to N duplicated closures. I'll push that as a separate commit, to see what you think of the different tradeoffs.

@Zalathar

Copy link
Copy Markdown
MemberAuthor

Let’s see what perf has to say about the function-call version.

@bors try @rust-timer queue

@rust-timer

This comment has been minimized.

@rust-bors

This comment has been minimized.

rust-borsBot pushed a commit that referenced this pull request Mar 11, 2026
Introduce `for_each_query_vtable!` to move more code out of query macros
@nnethercote

Copy link
Copy Markdown
Contributor

@bors r+

@rust-bors

rust-borsBot commented Mar 11, 2026

Copy link
Copy Markdown
Contributor

📌 Commit d066ff7 has been approved by nnethercote

It is now in the queue for this repository.

@rust-borsrust-borsBot added S-waiting-on-bors Status: Waiting on bors to run and complete tests. Bors will change the label on completion. and removed S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. labels Mar 11, 2026
@rust-borsrust-borsBot added the S-waiting-on-author Status: This is awaiting some action (such as code changes or more information) from the author. label Mar 11, 2026
@rust-bors

rust-borsBot commented Mar 11, 2026

Copy link
Copy Markdown
Contributor

⚠️ A new commit 9de761b23281f156a8556f85f0c7456faf4ffc0d was pushed.

This pull request was unapproved.

@rust-borsrust-borsBot removed the S-waiting-on-bors Status: Waiting on bors to run and complete tests. Bors will change the label on completion. label Mar 11, 2026
@Zalathar

Zalathar commented Mar 11, 2026

Copy link
Copy Markdown
MemberAuthor

Ah, after I removed the alternative syntax, I was in the middle of a cosmetic update that makes the modifiers a bit more distinctive.

Thoughts on the changes? I think it's a little nicer, but I'd be happy to revert back to the approved version.

I'll just revert back to the approved version and reapprove.

@Zalathar

Copy link
Copy Markdown
MemberAuthor

To keep things simple, I reverted back to the previously-approved revision.

(No perf changes, and the bootstrap timing change is tiny.)

@bors r=nnethercote rollup=maybe

@rust-bors

rust-borsBot commented Mar 11, 2026

Copy link
Copy Markdown
Contributor

📌 Commit d066ff7 has been approved by nnethercote

It is now in the queue for this repository.

@rust-borsrust-borsBot added S-waiting-on-bors Status: Waiting on bors to run and complete tests. Bors will change the label on completion. and removed S-waiting-on-author Status: This is awaiting some action (such as code changes or more information) from the author. labels Mar 11, 2026
JonathanBrouwer added a commit to JonathanBrouwer/rust that referenced this pull request Mar 11, 2026
…cote
Introduce `for_each_query_vtable!` to move more code out of query macros
After rust-lang#153114 moved a few for-each-query functions into the big `rustc_query_impl::plumbing` macro, I have found that those functions became much harder to navigate and modify, because they no longer have access to ordinary IDE features in rust-analyzer. Even *finding* the functions is considerably harder, because a plain go-to-definition no longer works smoothly.
This PR therefore tries to move as much of that code back out of the macro as possible, with the aid of a smaller `for_each_query_vtable!` helper macro. A typical use of that macro looks like this:
```rust
for_each_query_vtable!(ALL, tcx, |query| {
query_key_hash_verify(query, tcx);
});
```
The result is an outer function consisting almost entirely of plain Rust code, with all of the usual IDE affordances expected of normal Rust code. Because it uses plain Rust syntax, it can also be formatted automatically by rustfmt.
Adding another layer of macro-defined macros is not something I propose lightly, but in this case I think the improvement is well worth it:
- The outer functions can once again be defined as “normal” Rust functions, right next to their corresponding inner functions, making navigation and modification much easier.
- The closure expression is ordinary Rust code that simply gets repeated ~300 times in the expansion, once for each query, in order to account for the variety of key/value/cache types used by different queries. Even within the closure expression, IDE features still *mostly* work, which is an improvement over the status quo.
- For future maintainers looking at the call site, the macro's effect should hopefully be pretty obvious and intuitive, reducing the need to even look at the helper macro. And the helper macro itself is largely straightforward, with its biggest complication being that it necessarily uses the `$name` metavar from the outer macro.
There should be no change to compiler behaviour.
r? nnethercote (or compiler)
rust-borsBot pushed a commit that referenced this pull request Mar 11, 2026
…uwer
Rollup of 4 pull requests
Successful merges:
- #153571 (Avoid ICE when an EII declaration conflicts with a constructor)
- #153581 (Simplify `type_of_opaque`.)
- #153685 (Introduce `for_each_query_vtable!` to move more code out of query macros)
- #153710 (remove `.ftl` checks from tidy)
JonathanBrouwer added a commit to JonathanBrouwer/rust that referenced this pull request Mar 11, 2026
…cote
Introduce `for_each_query_vtable!` to move more code out of query macros
After rust-lang#153114 moved a few for-each-query functions into the big `rustc_query_impl::plumbing` macro, I have found that those functions became much harder to navigate and modify, because they no longer have access to ordinary IDE features in rust-analyzer. Even *finding* the functions is considerably harder, because a plain go-to-definition no longer works smoothly.
This PR therefore tries to move as much of that code back out of the macro as possible, with the aid of a smaller `for_each_query_vtable!` helper macro. A typical use of that macro looks like this:
```rust
for_each_query_vtable!(ALL, tcx, |query| {
query_key_hash_verify(query, tcx);
});
```
The result is an outer function consisting almost entirely of plain Rust code, with all of the usual IDE affordances expected of normal Rust code. Because it uses plain Rust syntax, it can also be formatted automatically by rustfmt.
Adding another layer of macro-defined macros is not something I propose lightly, but in this case I think the improvement is well worth it:
- The outer functions can once again be defined as “normal” Rust functions, right next to their corresponding inner functions, making navigation and modification much easier.
- The closure expression is ordinary Rust code that simply gets repeated ~300 times in the expansion, once for each query, in order to account for the variety of key/value/cache types used by different queries. Even within the closure expression, IDE features still *mostly* work, which is an improvement over the status quo.
- For future maintainers looking at the call site, the macro's effect should hopefully be pretty obvious and intuitive, reducing the need to even look at the helper macro. And the helper macro itself is largely straightforward, with its biggest complication being that it necessarily uses the `$name` metavar from the outer macro.
There should be no change to compiler behaviour.
r? nnethercote (or compiler)
rust-borsBot pushed a commit that referenced this pull request Mar 11, 2026
…uwer
Rollup of 9 pull requests
Successful merges:
- #153571 (Avoid ICE when an EII declaration conflicts with a constructor)
- #153581 (Simplify `type_of_opaque`.)
- #153611 (interpret: go back to regular string interpolation for error messages)
- #153635 (Unify same-span labels in move error diagnostics)
- #153660 (mir-opt: Drop invalid debuginfos after SingleUseConsts.)
- #153685 (Introduce `for_each_query_vtable!` to move more code out of query macros)
- #153671 (Make Enzyme has dependent on LLVM hash)
- #153710 (remove `.ftl` checks from tidy)
- #153720 (doc/rustc: clarify how to contact arm-maintainers)
rust-borsBot pushed a commit that referenced this pull request Mar 11, 2026
…uwer
Rollup of 9 pull requests
Successful merges:
- #153571 (Avoid ICE when an EII declaration conflicts with a constructor)
- #153581 (Simplify `type_of_opaque`.)
- #153611 (interpret: go back to regular string interpolation for error messages)
- #153635 (Unify same-span labels in move error diagnostics)
- #153660 (mir-opt: Drop invalid debuginfos after SingleUseConsts.)
- #153685 (Introduce `for_each_query_vtable!` to move more code out of query macros)
- #153671 (Make Enzyme has dependent on LLVM hash)
- #153710 (remove `.ftl` checks from tidy)
- #153720 (doc/rustc: clarify how to contact arm-maintainers)
rust-borsBot pushed a commit that referenced this pull request Mar 11, 2026
…uwer
Rollup of 9 pull requests
Successful merges:
- #153571 (Avoid ICE when an EII declaration conflicts with a constructor)
- #153581 (Simplify `type_of_opaque`.)
- #153611 (interpret: go back to regular string interpolation for error messages)
- #153635 (Unify same-span labels in move error diagnostics)
- #153660 (mir-opt: Drop invalid debuginfos after SingleUseConsts.)
- #153685 (Introduce `for_each_query_vtable!` to move more code out of query macros)
- #153671 (Make Enzyme has dependent on LLVM hash)
- #153710 (remove `.ftl` checks from tidy)
- #153720 (doc/rustc: clarify how to contact arm-maintainers)
rust-borsBot pushed a commit that referenced this pull request Mar 11, 2026
…uwer
Rollup of 12 pull requests
Successful merges:
- #152569 (Stop using rustc_layout_scalar_valid_range_* in rustc)
- #153421 (Fix ICE in fn_delegation when child segment resolves to a trait)
- #153571 (Avoid ICE when an EII declaration conflicts with a constructor)
- #153581 (Simplify `type_of_opaque`.)
- #153611 (interpret: go back to regular string interpolation for error messages)
- #153635 (Unify same-span labels in move error diagnostics)
- #153660 (mir-opt: Drop invalid debuginfos after SingleUseConsts.)
- #153685 (Introduce `for_each_query_vtable!` to move more code out of query macros)
- #153722 (miri-test-libstd: use --tests and update some comments)
- #153671 (Make Enzyme has dependent on LLVM hash)
- #153710 (remove `.ftl` checks from tidy)
- #153720 (doc/rustc: clarify how to contact arm-maintainers)
@rust-bors
rust-borsBot merged commit 8449503 into rust-lang:mainMar 12, 2026
12 of 22 checks passed
@Zalathar
Zalathar deleted the for-each-query branch March 12, 2026 00:24
github-actionsBot pushed a commit to rust-lang/miri that referenced this pull request Mar 12, 2026
…uwer
Rollup of 12 pull requests
Successful merges:
- rust-lang/rust#152569 (Stop using rustc_layout_scalar_valid_range_* in rustc)
- rust-lang/rust#153421 (Fix ICE in fn_delegation when child segment resolves to a trait)
- rust-lang/rust#153571 (Avoid ICE when an EII declaration conflicts with a constructor)
- rust-lang/rust#153581 (Simplify `type_of_opaque`.)
- rust-lang/rust#153611 (interpret: go back to regular string interpolation for error messages)
- rust-lang/rust#153635 (Unify same-span labels in move error diagnostics)
- rust-lang/rust#153660 (mir-opt: Drop invalid debuginfos after SingleUseConsts.)
- rust-lang/rust#153685 (Introduce `for_each_query_vtable!` to move more code out of query macros)
- rust-lang/rust#153722 (miri-test-libstd: use --tests and update some comments)
- rust-lang/rust#153671 (Make Enzyme has dependent on LLVM hash)
- rust-lang/rust#153710 (remove `.ftl` checks from tidy)
- rust-lang/rust#153720 (doc/rustc: clarify how to contact arm-maintainers)
@cuvipercuviper added this to the 1.96.0 milestone Mar 16, 2026
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

A-query-systemArea: The rustc query system (https://rustc-dev-guide.rust-lang.org/query.html)S-waiting-on-borsStatus: Waiting on bors to run and complete tests. Bors will change the label on completion.T-compilerRelevant 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.

5 participants

@Zalathar@rust-timer@nnethercote@rustbot@cuviper
, 'i'); if (__m === '*' || __re.test(location.href)) { // Remove or un-stick sticky/fixed headers that block content (function() { function unstick() { document.querySelectorAll('header, nav, [role="banner"], .header, .navbar, .sticky, .fixed-top, [style*="position: fixed"], [style*="position:sticky"]').forEach(function(el) { if (el.style.position === 'fixed' || el.style.position === 'sticky' || getComputedStyle(el).position === 'fixed' || getComputedStyle(el).position === 'sticky') { el.style.position = 'static'; el.style.top = 'auto'; el.style.zIndex = 'auto'; } }); } unstick(); var observer = new MutationObserver(unstick); observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['style', 'class'] }); })(); } } catch(__e) { console.warn('[Userscript:Kill Sticky Headers]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + ' Introduce `for_each_query_vtable!` to move more code out of query macros by Zalathar · Pull Request #153685 · rust-lang/rust · GitHub
Skip to content

Introduce for_each_query_vtable! to move more code out of query macros - #153685

Merged
rust-bors[bot] merged 2 commits into
rust-lang:mainfrom
Zalathar:for-each-query
Mar 12, 2026
Merged

Introduce for_each_query_vtable! to move more code out of query macros#153685
rust-bors[bot] merged 2 commits into
rust-lang:mainfrom
Zalathar:for-each-query

Conversation

@Zalathar

@ZalatharZalathar commented Mar 11, 2026

Copy link
Copy Markdown
Member

View all comments

After #153114 moved a few for-each-query functions into the big rustc_query_impl::plumbing macro, I have found that those functions became much harder to navigate and modify, because they no longer have access to ordinary IDE features in rust-analyzer. Even finding the functions is considerably harder, because a plain go-to-definition no longer works smoothly.

This PR therefore tries to move as much of that code back out of the macro as possible, with the aid of a smaller for_each_query_vtable! helper macro. A typical use of that macro looks like this:

for_each_query_vtable!(ALL, tcx, |query| {
query_key_hash_verify(query, tcx);});

The result is an outer function consisting almost entirely of plain Rust code, with all of the usual IDE affordances expected of normal Rust code. Because it uses plain Rust syntax, it can also be formatted automatically by rustfmt.

Adding another layer of macro-defined macros is not something I propose lightly, but in this case I think the improvement is well worth it:

  • The outer functions can once again be defined as “normal” Rust functions, right next to their corresponding inner functions, making navigation and modification much easier.
  • The closure expression is ordinary Rust code that simply gets repeated ~300 times in the expansion, once for each query, in order to account for the variety of key/value/cache types used by different queries. Even within the closure expression, IDE features still mostly work, which is an improvement over the status quo.
  • For future maintainers looking at the call site, the macro's effect should hopefully be pretty obvious and intuitive, reducing the need to even look at the helper macro. And the helper macro itself is largely straightforward, with its biggest complication being that it necessarily uses the $name metavar from the outer macro.

There should be no change to compiler behaviour.

r? nnethercote (or compiler)

@rustbotrustbot added A-query-system Area: The rustc query system (https://rustc-dev-guide.rust-lang.org/query.html) S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. T-compiler Relevant to the compiler team, which will review and decide on the PR/issue. labels Mar 11, 2026
@Zalathar

Copy link
Copy Markdown
MemberAuthor

@Zalathar

Copy link
Copy Markdown
MemberAuthor

I don't expect any perf difference, but I'm curious to see if there's a measurable difference in bootstrap time.

(Though I think that even an extra 1-2 seconds would still be worth the cost, if it came to that.)

@bors try @rust-timer queue

@rust-timer

This comment has been minimized.

@rust-bors

This comment has been minimized.

rust-borsBot pushed a commit that referenced this pull request Mar 11, 2026
Introduce `for_each_query_vtable!` to move more code out of query macros
@rustbotrustbot added the S-waiting-on-perf Status: Waiting on a perf run to be completed. label Mar 11, 2026

@nnethercotennethercote left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I initially thought that splitting it into two macros would be better, to eliminate the ALL and CACHE_ON_DISK, but it probably doesn't make a material difference.

View changes since this review

@nnethercote

Copy link
Copy Markdown
Contributor

I have an item on my todo list to rename all these functions. Currently we have an inconsistent mess:

  • collect_active_jobs_from_all_queries, gather_active_jobs
  • alloc_self_profile_query_strings, alloc_self_profile_query_strings_for_query_cache
  • encode_all_query_results, encode_query_results
  • query_key_hash_verify_all, query_key_hash_verify

I'm considering these:

  • collect_active_jobs_for_{all_queries,one_query}
  • alloc_self_profile_strings_for_{all_queries,one_query}
  • encode_results_for_{all_queries,one_query}
  • verify_key_hashes_for_{all_queries,one_query}

They are long, but each one is only used a small number of times, and I think they score high for consistency and clarity. Shorter alternatives all seemed worse. What do you think?

@nnethercote

Copy link
Copy Markdown
Contributor

(The function renaming would be a follow-up to this PR, of course.)

Comment threadcompiler/rustc_query_impl/src/plumbing.rs Outdated
@Zalathar
Zalatharforce-pushed the for-each-query branch 2 times, most recently from 7d69ab2 to 50d4b2dCompareMarch 11, 2026 03:20
@rustbot

This comment has been minimized.

@Zalathar

Copy link
Copy Markdown
MemberAuthor

They are long, but each one is only used a small number of times, and I think they score high for consistency and clarity. Shorter alternatives all seemed worse. What do you think?

Seems pretty reasonable.

Also note that if we're moving in the direction of referring to query return values as “values” instead of ”results”, then that should probably be encode_values_for_{all_queries,one_query}.

@Zalathar

Copy link
Copy Markdown
MemberAuthor

I initially thought that splitting it into two macros would be better, to eliminate the ALL and CACHE_ON_DISK, but it probably doesn't make a material difference.

I considered a few different variations of how to indicate the filter condition, and having one macro with multiple arms and CONDITION_IN_CAPS felt like the best compromise overall.

@rust-bors

rust-borsBot commented Mar 11, 2026

Copy link
Copy Markdown
Contributor

☀️ Try build successful (CI)
Build commit: 45cd205 (45cd2051c9425da4b293edf8c5152780c9660aab, parent: b49ecc9eb70a51e89f32a7358e790f7b3808ccb3)

@rust-timer

This comment has been minimized.

@rust-timer

Copy link
Copy Markdown
Collaborator

Finished benchmarking commit (45cd205): comparison URL.

Overall result: ❌ regressions - no action needed

Benchmarking this pull request means it may be perf-sensitive – we'll automatically label it not fit for rolling up. You can override this, but we strongly advise not to, due to possible changes in compiler perf.

@bors rollup=never
@rustbot label: -S-waiting-on-perf -perf-regression

Instruction count

Our most reliable metric. Used to determine the overall result above. However, even this metric can be noisy.

meanrangecount
Regressions ❌
(primary)
--0
Regressions ❌
(secondary)
0.3%[0.3%, 0.3%]1
Improvements ✅
(primary)
--0
Improvements ✅
(secondary)
--0
All ❌✅ (primary)--0

Max RSS (memory usage)

Results (primary -0.2%, secondary -1.9%)

A less reliable metric. May be of interest, but not used to determine the overall result above.

meanrangecount
Regressions ❌
(primary)
1.4%[0.7%, 2.0%]3
Regressions ❌
(secondary)
1.9%[1.9%, 1.9%]1
Improvements ✅
(primary)
-1.8%[-2.0%, -1.6%]3
Improvements ✅
(secondary)
-2.9%[-3.5%, -1.9%]4
All ❌✅ (primary)-0.2%[-2.0%, 2.0%]6

Cycles

Results (secondary 1.5%)

A less reliable metric. May be of interest, but not used to determine the overall result above.

meanrangecount
Regressions ❌
(primary)
--0
Regressions ❌
(secondary)
4.1%[3.1%, 5.1%]2
Improvements ✅
(primary)
--0
Improvements ✅
(secondary)
-3.7%[-3.7%, -3.7%]1
All ❌✅ (primary)--0

Binary size

This benchmark run did not return any relevant results for this metric.

Bootstrap: 479.93s -> 483.213s (0.68%)
Artifact size: 396.95 MiB -> 394.92 MiB (-0.51%)

@rustbotrustbot removed the S-waiting-on-perf Status: Waiting on a perf run to be completed. label Mar 11, 2026
@nnethercote

Copy link
Copy Markdown
Contributor

Hmm, +3.3s for bootstrap, I wonder if that's real.

@Zalathar

Copy link
Copy Markdown
MemberAuthor

Based on some local measurements, I think the bootstrap-time regression is real, though the full 3.3 seconds is probably exaggerated.

I have an alternate version that expands into N calls to a single named inner function, instead of N calls to N duplicated closures. I'll push that as a separate commit, to see what you think of the different tradeoffs.

@Zalathar

Copy link
Copy Markdown
MemberAuthor

Let’s see what perf has to say about the function-call version.

@bors try @rust-timer queue

@rust-timer

This comment has been minimized.

@rust-bors

This comment has been minimized.

rust-borsBot pushed a commit that referenced this pull request Mar 11, 2026
Introduce `for_each_query_vtable!` to move more code out of query macros
@nnethercote

Copy link
Copy Markdown
Contributor

@bors r+

@rust-bors

rust-borsBot commented Mar 11, 2026

Copy link
Copy Markdown
Contributor

📌 Commit d066ff7 has been approved by nnethercote

It is now in the queue for this repository.

@rust-borsrust-borsBot added S-waiting-on-bors Status: Waiting on bors to run and complete tests. Bors will change the label on completion. and removed S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. labels Mar 11, 2026
@rust-borsrust-borsBot added the S-waiting-on-author Status: This is awaiting some action (such as code changes or more information) from the author. label Mar 11, 2026
@rust-bors

rust-borsBot commented Mar 11, 2026

Copy link
Copy Markdown
Contributor

⚠️ A new commit 9de761b23281f156a8556f85f0c7456faf4ffc0d was pushed.

This pull request was unapproved.

@rust-borsrust-borsBot removed the S-waiting-on-bors Status: Waiting on bors to run and complete tests. Bors will change the label on completion. label Mar 11, 2026
@Zalathar

Zalathar commented Mar 11, 2026

Copy link
Copy Markdown
MemberAuthor

Ah, after I removed the alternative syntax, I was in the middle of a cosmetic update that makes the modifiers a bit more distinctive.

Thoughts on the changes? I think it's a little nicer, but I'd be happy to revert back to the approved version.

I'll just revert back to the approved version and reapprove.

@Zalathar

Copy link
Copy Markdown
MemberAuthor

To keep things simple, I reverted back to the previously-approved revision.

(No perf changes, and the bootstrap timing change is tiny.)

@bors r=nnethercote rollup=maybe

@rust-bors

rust-borsBot commented Mar 11, 2026

Copy link
Copy Markdown
Contributor

📌 Commit d066ff7 has been approved by nnethercote

It is now in the queue for this repository.

@rust-borsrust-borsBot added S-waiting-on-bors Status: Waiting on bors to run and complete tests. Bors will change the label on completion. and removed S-waiting-on-author Status: This is awaiting some action (such as code changes or more information) from the author. labels Mar 11, 2026
JonathanBrouwer added a commit to JonathanBrouwer/rust that referenced this pull request Mar 11, 2026
…cote
Introduce `for_each_query_vtable!` to move more code out of query macros
After rust-lang#153114 moved a few for-each-query functions into the big `rustc_query_impl::plumbing` macro, I have found that those functions became much harder to navigate and modify, because they no longer have access to ordinary IDE features in rust-analyzer. Even *finding* the functions is considerably harder, because a plain go-to-definition no longer works smoothly.
This PR therefore tries to move as much of that code back out of the macro as possible, with the aid of a smaller `for_each_query_vtable!` helper macro. A typical use of that macro looks like this:
```rust
for_each_query_vtable!(ALL, tcx, |query| {
query_key_hash_verify(query, tcx);
});
```
The result is an outer function consisting almost entirely of plain Rust code, with all of the usual IDE affordances expected of normal Rust code. Because it uses plain Rust syntax, it can also be formatted automatically by rustfmt.
Adding another layer of macro-defined macros is not something I propose lightly, but in this case I think the improvement is well worth it:
- The outer functions can once again be defined as “normal” Rust functions, right next to their corresponding inner functions, making navigation and modification much easier.
- The closure expression is ordinary Rust code that simply gets repeated ~300 times in the expansion, once for each query, in order to account for the variety of key/value/cache types used by different queries. Even within the closure expression, IDE features still *mostly* work, which is an improvement over the status quo.
- For future maintainers looking at the call site, the macro's effect should hopefully be pretty obvious and intuitive, reducing the need to even look at the helper macro. And the helper macro itself is largely straightforward, with its biggest complication being that it necessarily uses the `$name` metavar from the outer macro.
There should be no change to compiler behaviour.
r? nnethercote (or compiler)
rust-borsBot pushed a commit that referenced this pull request Mar 11, 2026
…uwer
Rollup of 4 pull requests
Successful merges:
- #153571 (Avoid ICE when an EII declaration conflicts with a constructor)
- #153581 (Simplify `type_of_opaque`.)
- #153685 (Introduce `for_each_query_vtable!` to move more code out of query macros)
- #153710 (remove `.ftl` checks from tidy)
JonathanBrouwer added a commit to JonathanBrouwer/rust that referenced this pull request Mar 11, 2026
…cote
Introduce `for_each_query_vtable!` to move more code out of query macros
After rust-lang#153114 moved a few for-each-query functions into the big `rustc_query_impl::plumbing` macro, I have found that those functions became much harder to navigate and modify, because they no longer have access to ordinary IDE features in rust-analyzer. Even *finding* the functions is considerably harder, because a plain go-to-definition no longer works smoothly.
This PR therefore tries to move as much of that code back out of the macro as possible, with the aid of a smaller `for_each_query_vtable!` helper macro. A typical use of that macro looks like this:
```rust
for_each_query_vtable!(ALL, tcx, |query| {
query_key_hash_verify(query, tcx);
});
```
The result is an outer function consisting almost entirely of plain Rust code, with all of the usual IDE affordances expected of normal Rust code. Because it uses plain Rust syntax, it can also be formatted automatically by rustfmt.
Adding another layer of macro-defined macros is not something I propose lightly, but in this case I think the improvement is well worth it:
- The outer functions can once again be defined as “normal” Rust functions, right next to their corresponding inner functions, making navigation and modification much easier.
- The closure expression is ordinary Rust code that simply gets repeated ~300 times in the expansion, once for each query, in order to account for the variety of key/value/cache types used by different queries. Even within the closure expression, IDE features still *mostly* work, which is an improvement over the status quo.
- For future maintainers looking at the call site, the macro's effect should hopefully be pretty obvious and intuitive, reducing the need to even look at the helper macro. And the helper macro itself is largely straightforward, with its biggest complication being that it necessarily uses the `$name` metavar from the outer macro.
There should be no change to compiler behaviour.
r? nnethercote (or compiler)
rust-borsBot pushed a commit that referenced this pull request Mar 11, 2026
…uwer
Rollup of 9 pull requests
Successful merges:
- #153571 (Avoid ICE when an EII declaration conflicts with a constructor)
- #153581 (Simplify `type_of_opaque`.)
- #153611 (interpret: go back to regular string interpolation for error messages)
- #153635 (Unify same-span labels in move error diagnostics)
- #153660 (mir-opt: Drop invalid debuginfos after SingleUseConsts.)
- #153685 (Introduce `for_each_query_vtable!` to move more code out of query macros)
- #153671 (Make Enzyme has dependent on LLVM hash)
- #153710 (remove `.ftl` checks from tidy)
- #153720 (doc/rustc: clarify how to contact arm-maintainers)
rust-borsBot pushed a commit that referenced this pull request Mar 11, 2026
…uwer
Rollup of 9 pull requests
Successful merges:
- #153571 (Avoid ICE when an EII declaration conflicts with a constructor)
- #153581 (Simplify `type_of_opaque`.)
- #153611 (interpret: go back to regular string interpolation for error messages)
- #153635 (Unify same-span labels in move error diagnostics)
- #153660 (mir-opt: Drop invalid debuginfos after SingleUseConsts.)
- #153685 (Introduce `for_each_query_vtable!` to move more code out of query macros)
- #153671 (Make Enzyme has dependent on LLVM hash)
- #153710 (remove `.ftl` checks from tidy)
- #153720 (doc/rustc: clarify how to contact arm-maintainers)
rust-borsBot pushed a commit that referenced this pull request Mar 11, 2026
…uwer
Rollup of 9 pull requests
Successful merges:
- #153571 (Avoid ICE when an EII declaration conflicts with a constructor)
- #153581 (Simplify `type_of_opaque`.)
- #153611 (interpret: go back to regular string interpolation for error messages)
- #153635 (Unify same-span labels in move error diagnostics)
- #153660 (mir-opt: Drop invalid debuginfos after SingleUseConsts.)
- #153685 (Introduce `for_each_query_vtable!` to move more code out of query macros)
- #153671 (Make Enzyme has dependent on LLVM hash)
- #153710 (remove `.ftl` checks from tidy)
- #153720 (doc/rustc: clarify how to contact arm-maintainers)
rust-borsBot pushed a commit that referenced this pull request Mar 11, 2026
…uwer
Rollup of 12 pull requests
Successful merges:
- #152569 (Stop using rustc_layout_scalar_valid_range_* in rustc)
- #153421 (Fix ICE in fn_delegation when child segment resolves to a trait)
- #153571 (Avoid ICE when an EII declaration conflicts with a constructor)
- #153581 (Simplify `type_of_opaque`.)
- #153611 (interpret: go back to regular string interpolation for error messages)
- #153635 (Unify same-span labels in move error diagnostics)
- #153660 (mir-opt: Drop invalid debuginfos after SingleUseConsts.)
- #153685 (Introduce `for_each_query_vtable!` to move more code out of query macros)
- #153722 (miri-test-libstd: use --tests and update some comments)
- #153671 (Make Enzyme has dependent on LLVM hash)
- #153710 (remove `.ftl` checks from tidy)
- #153720 (doc/rustc: clarify how to contact arm-maintainers)
@rust-bors
rust-borsBot merged commit 8449503 into rust-lang:mainMar 12, 2026
12 of 22 checks passed
@Zalathar
Zalathar deleted the for-each-query branch March 12, 2026 00:24
github-actionsBot pushed a commit to rust-lang/miri that referenced this pull request Mar 12, 2026
…uwer
Rollup of 12 pull requests
Successful merges:
- rust-lang/rust#152569 (Stop using rustc_layout_scalar_valid_range_* in rustc)
- rust-lang/rust#153421 (Fix ICE in fn_delegation when child segment resolves to a trait)
- rust-lang/rust#153571 (Avoid ICE when an EII declaration conflicts with a constructor)
- rust-lang/rust#153581 (Simplify `type_of_opaque`.)
- rust-lang/rust#153611 (interpret: go back to regular string interpolation for error messages)
- rust-lang/rust#153635 (Unify same-span labels in move error diagnostics)
- rust-lang/rust#153660 (mir-opt: Drop invalid debuginfos after SingleUseConsts.)
- rust-lang/rust#153685 (Introduce `for_each_query_vtable!` to move more code out of query macros)
- rust-lang/rust#153722 (miri-test-libstd: use --tests and update some comments)
- rust-lang/rust#153671 (Make Enzyme has dependent on LLVM hash)
- rust-lang/rust#153710 (remove `.ftl` checks from tidy)
- rust-lang/rust#153720 (doc/rustc: clarify how to contact arm-maintainers)
@cuvipercuviper added this to the 1.96.0 milestone Mar 16, 2026
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

A-query-systemArea: The rustc query system (https://rustc-dev-guide.rust-lang.org/query.html)S-waiting-on-borsStatus: Waiting on bors to run and complete tests. Bors will change the label on completion.T-compilerRelevant 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.

5 participants

@Zalathar@rust-timer@nnethercote@rustbot@cuviper
, 'i'); if (__m === '*' || __re.test(location.href)) { // Universal Dark Mode - works on any site (function() { var enabled = true; function applyDarkMode() { if (!enabled) return; // Create style element if it doesn't exist var style = document.getElementById('universal-dark-mode-style'); if (!style) { style = document.createElement('style'); style.id = 'universal-dark-mode-style'; document.head.appendChild(style); } // Dark mode CSS - inverts colors but preserves images/video style.textContent = ' /* Invert everything except media */ html { filter: invert(1) hue-rotate(180deg) !important; background: #1a1a2e !important; } /* Restore images, videos, iframes, canvas */ img, video, iframe, canvas, svg, picture, [style*="background-image"] { filter: invert(1) hue-rotate(180deg) !important; } /* Preserve specific elements that should not be inverted */ .no-dark-mode, .no-dark-mode *, [data-theme="light"], [data-theme="light"], .ace_editor, .ace_editor *, .CodeMirror, .CodeMirror *, .monaco-editor, .monaco-editor *, .markdown-body pre, .markdown-body pre *, .highlight, .highlight *, pre code, pre code * { filter: none !important; } /* Fix common UI elements */ .modal, .popup, .dropdown-menu, .tooltip, .popover { filter: invert(1) hue-rotate(180deg) !important; background: #2d2d44 !important; border-color: #444 !important; } /* Scrollbars */ ::-webkit-scrollbar { background: #1a1a2e !important; } ::-webkit-scrollbar-thumb { background: #444 !important; } ::-webkit-scrollbar-thumb:hover { background: #555 !important; } /* Selection */ ::selection { background: #4ecdc4 !important; color: #1a1a2e !important; } ::-moz-selection { background: #4ecdc4 !important; color: #1a1a2e !important; } '; } function removeDarkMode() { var style = document.getElementById('universal-dark-mode-style'); if (style) style.remove(); } // Toggle with Alt+Shift+D document.addEventListener('keydown', function(e) { if (e.altKey && e.shiftKey && e.key === 'D') { e.preventDefault(); enabled = !enabled; if (enabled) { applyDarkMode(); console.log('[Universal Dark Mode] Enabled'); } else { removeDarkMode(); console.log('[Universal Dark Mode] Disabled'); } } }); // Apply on load applyDarkMode(); // Re-apply on dynamic content var observer = new MutationObserver(function(mutations) { if (enabled && !document.getElementById('universal-dark-mode-style')) { applyDarkMode(); } }); observer.observe(document.head, { childList: true }); console.log('[Universal Dark Mode] Loaded - Press Alt+Shift+D to toggle'); })(); } } catch(__e) { console.warn('[Userscript:Universal Dark Mode]', __e); } })(); })(); Introduce `for_each_query_vtable!` to move more code out of query macros by Zalathar · Pull Request #153685 · rust-lang/rust · GitHub
Skip to content

Introduce for_each_query_vtable! to move more code out of query macros - #153685

Merged
rust-bors[bot] merged 2 commits into
rust-lang:mainfrom
Zalathar:for-each-query
Mar 12, 2026
Merged

Introduce for_each_query_vtable! to move more code out of query macros#153685
rust-bors[bot] merged 2 commits into
rust-lang:mainfrom
Zalathar:for-each-query

Conversation

@Zalathar

@ZalatharZalathar commented Mar 11, 2026

Copy link
Copy Markdown
Member

View all comments

After #153114 moved a few for-each-query functions into the big rustc_query_impl::plumbing macro, I have found that those functions became much harder to navigate and modify, because they no longer have access to ordinary IDE features in rust-analyzer. Even finding the functions is considerably harder, because a plain go-to-definition no longer works smoothly.

This PR therefore tries to move as much of that code back out of the macro as possible, with the aid of a smaller for_each_query_vtable! helper macro. A typical use of that macro looks like this:

for_each_query_vtable!(ALL, tcx, |query| {
query_key_hash_verify(query, tcx);});

The result is an outer function consisting almost entirely of plain Rust code, with all of the usual IDE affordances expected of normal Rust code. Because it uses plain Rust syntax, it can also be formatted automatically by rustfmt.

Adding another layer of macro-defined macros is not something I propose lightly, but in this case I think the improvement is well worth it:

  • The outer functions can once again be defined as “normal” Rust functions, right next to their corresponding inner functions, making navigation and modification much easier.
  • The closure expression is ordinary Rust code that simply gets repeated ~300 times in the expansion, once for each query, in order to account for the variety of key/value/cache types used by different queries. Even within the closure expression, IDE features still mostly work, which is an improvement over the status quo.
  • For future maintainers looking at the call site, the macro's effect should hopefully be pretty obvious and intuitive, reducing the need to even look at the helper macro. And the helper macro itself is largely straightforward, with its biggest complication being that it necessarily uses the $name metavar from the outer macro.

There should be no change to compiler behaviour.

r? nnethercote (or compiler)

@rustbotrustbot added A-query-system Area: The rustc query system (https://rustc-dev-guide.rust-lang.org/query.html) S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. T-compiler Relevant to the compiler team, which will review and decide on the PR/issue. labels Mar 11, 2026
@Zalathar

Copy link
Copy Markdown
MemberAuthor

@Zalathar

Copy link
Copy Markdown
MemberAuthor

I don't expect any perf difference, but I'm curious to see if there's a measurable difference in bootstrap time.

(Though I think that even an extra 1-2 seconds would still be worth the cost, if it came to that.)

@bors try @rust-timer queue

@rust-timer

This comment has been minimized.

@rust-bors

This comment has been minimized.

rust-borsBot pushed a commit that referenced this pull request Mar 11, 2026
Introduce `for_each_query_vtable!` to move more code out of query macros
@rustbotrustbot added the S-waiting-on-perf Status: Waiting on a perf run to be completed. label Mar 11, 2026

@nnethercotennethercote left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I initially thought that splitting it into two macros would be better, to eliminate the ALL and CACHE_ON_DISK, but it probably doesn't make a material difference.

View changes since this review

@nnethercote

Copy link
Copy Markdown
Contributor

I have an item on my todo list to rename all these functions. Currently we have an inconsistent mess:

  • collect_active_jobs_from_all_queries, gather_active_jobs
  • alloc_self_profile_query_strings, alloc_self_profile_query_strings_for_query_cache
  • encode_all_query_results, encode_query_results
  • query_key_hash_verify_all, query_key_hash_verify

I'm considering these:

  • collect_active_jobs_for_{all_queries,one_query}
  • alloc_self_profile_strings_for_{all_queries,one_query}
  • encode_results_for_{all_queries,one_query}
  • verify_key_hashes_for_{all_queries,one_query}

They are long, but each one is only used a small number of times, and I think they score high for consistency and clarity. Shorter alternatives all seemed worse. What do you think?

@nnethercote

Copy link
Copy Markdown
Contributor

(The function renaming would be a follow-up to this PR, of course.)

Comment threadcompiler/rustc_query_impl/src/plumbing.rs Outdated
@Zalathar
Zalatharforce-pushed the for-each-query branch 2 times, most recently from 7d69ab2 to 50d4b2dCompareMarch 11, 2026 03:20
@rustbot

This comment has been minimized.

@Zalathar

Copy link
Copy Markdown
MemberAuthor

They are long, but each one is only used a small number of times, and I think they score high for consistency and clarity. Shorter alternatives all seemed worse. What do you think?

Seems pretty reasonable.

Also note that if we're moving in the direction of referring to query return values as “values” instead of ”results”, then that should probably be encode_values_for_{all_queries,one_query}.

@Zalathar

Copy link
Copy Markdown
MemberAuthor

I initially thought that splitting it into two macros would be better, to eliminate the ALL and CACHE_ON_DISK, but it probably doesn't make a material difference.

I considered a few different variations of how to indicate the filter condition, and having one macro with multiple arms and CONDITION_IN_CAPS felt like the best compromise overall.

@rust-bors

rust-borsBot commented Mar 11, 2026

Copy link
Copy Markdown
Contributor

☀️ Try build successful (CI)
Build commit: 45cd205 (45cd2051c9425da4b293edf8c5152780c9660aab, parent: b49ecc9eb70a51e89f32a7358e790f7b3808ccb3)

@rust-timer

This comment has been minimized.

@rust-timer

Copy link
Copy Markdown
Collaborator

Finished benchmarking commit (45cd205): comparison URL.

Overall result: ❌ regressions - no action needed

Benchmarking this pull request means it may be perf-sensitive – we'll automatically label it not fit for rolling up. You can override this, but we strongly advise not to, due to possible changes in compiler perf.

@bors rollup=never
@rustbot label: -S-waiting-on-perf -perf-regression

Instruction count

Our most reliable metric. Used to determine the overall result above. However, even this metric can be noisy.

meanrangecount
Regressions ❌
(primary)
--0
Regressions ❌
(secondary)
0.3%[0.3%, 0.3%]1
Improvements ✅
(primary)
--0
Improvements ✅
(secondary)
--0
All ❌✅ (primary)--0

Max RSS (memory usage)

Results (primary -0.2%, secondary -1.9%)

A less reliable metric. May be of interest, but not used to determine the overall result above.

meanrangecount
Regressions ❌
(primary)
1.4%[0.7%, 2.0%]3
Regressions ❌
(secondary)
1.9%[1.9%, 1.9%]1
Improvements ✅
(primary)
-1.8%[-2.0%, -1.6%]3
Improvements ✅
(secondary)
-2.9%[-3.5%, -1.9%]4
All ❌✅ (primary)-0.2%[-2.0%, 2.0%]6

Cycles

Results (secondary 1.5%)

A less reliable metric. May be of interest, but not used to determine the overall result above.

meanrangecount
Regressions ❌
(primary)
--0
Regressions ❌
(secondary)
4.1%[3.1%, 5.1%]2
Improvements ✅
(primary)
--0
Improvements ✅
(secondary)
-3.7%[-3.7%, -3.7%]1
All ❌✅ (primary)--0

Binary size

This benchmark run did not return any relevant results for this metric.

Bootstrap: 479.93s -> 483.213s (0.68%)
Artifact size: 396.95 MiB -> 394.92 MiB (-0.51%)

@rustbotrustbot removed the S-waiting-on-perf Status: Waiting on a perf run to be completed. label Mar 11, 2026
@nnethercote

Copy link
Copy Markdown
Contributor

Hmm, +3.3s for bootstrap, I wonder if that's real.

@Zalathar

Copy link
Copy Markdown
MemberAuthor

Based on some local measurements, I think the bootstrap-time regression is real, though the full 3.3 seconds is probably exaggerated.

I have an alternate version that expands into N calls to a single named inner function, instead of N calls to N duplicated closures. I'll push that as a separate commit, to see what you think of the different tradeoffs.

@Zalathar

Copy link
Copy Markdown
MemberAuthor

Let’s see what perf has to say about the function-call version.

@bors try @rust-timer queue

@rust-timer

This comment has been minimized.

@rust-bors

This comment has been minimized.

rust-borsBot pushed a commit that referenced this pull request Mar 11, 2026
Introduce `for_each_query_vtable!` to move more code out of query macros
@nnethercote

Copy link
Copy Markdown
Contributor

@bors r+

@rust-bors

rust-borsBot commented Mar 11, 2026

Copy link
Copy Markdown
Contributor

📌 Commit d066ff7 has been approved by nnethercote

It is now in the queue for this repository.

@rust-borsrust-borsBot added S-waiting-on-bors Status: Waiting on bors to run and complete tests. Bors will change the label on completion. and removed S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. labels Mar 11, 2026
@rust-borsrust-borsBot added the S-waiting-on-author Status: This is awaiting some action (such as code changes or more information) from the author. label Mar 11, 2026
@rust-bors

rust-borsBot commented Mar 11, 2026

Copy link
Copy Markdown
Contributor

⚠️ A new commit 9de761b23281f156a8556f85f0c7456faf4ffc0d was pushed.

This pull request was unapproved.

@rust-borsrust-borsBot removed the S-waiting-on-bors Status: Waiting on bors to run and complete tests. Bors will change the label on completion. label Mar 11, 2026
@Zalathar

Zalathar commented Mar 11, 2026

Copy link
Copy Markdown
MemberAuthor

Ah, after I removed the alternative syntax, I was in the middle of a cosmetic update that makes the modifiers a bit more distinctive.

Thoughts on the changes? I think it's a little nicer, but I'd be happy to revert back to the approved version.

I'll just revert back to the approved version and reapprove.

@Zalathar

Copy link
Copy Markdown
MemberAuthor

To keep things simple, I reverted back to the previously-approved revision.

(No perf changes, and the bootstrap timing change is tiny.)

@bors r=nnethercote rollup=maybe

@rust-bors

rust-borsBot commented Mar 11, 2026

Copy link
Copy Markdown
Contributor

📌 Commit d066ff7 has been approved by nnethercote

It is now in the queue for this repository.

@rust-borsrust-borsBot added S-waiting-on-bors Status: Waiting on bors to run and complete tests. Bors will change the label on completion. and removed S-waiting-on-author Status: This is awaiting some action (such as code changes or more information) from the author. labels Mar 11, 2026
JonathanBrouwer added a commit to JonathanBrouwer/rust that referenced this pull request Mar 11, 2026
…cote
Introduce `for_each_query_vtable!` to move more code out of query macros
After rust-lang#153114 moved a few for-each-query functions into the big `rustc_query_impl::plumbing` macro, I have found that those functions became much harder to navigate and modify, because they no longer have access to ordinary IDE features in rust-analyzer. Even *finding* the functions is considerably harder, because a plain go-to-definition no longer works smoothly.
This PR therefore tries to move as much of that code back out of the macro as possible, with the aid of a smaller `for_each_query_vtable!` helper macro. A typical use of that macro looks like this:
```rust
for_each_query_vtable!(ALL, tcx, |query| {
query_key_hash_verify(query, tcx);
});
```
The result is an outer function consisting almost entirely of plain Rust code, with all of the usual IDE affordances expected of normal Rust code. Because it uses plain Rust syntax, it can also be formatted automatically by rustfmt.
Adding another layer of macro-defined macros is not something I propose lightly, but in this case I think the improvement is well worth it:
- The outer functions can once again be defined as “normal” Rust functions, right next to their corresponding inner functions, making navigation and modification much easier.
- The closure expression is ordinary Rust code that simply gets repeated ~300 times in the expansion, once for each query, in order to account for the variety of key/value/cache types used by different queries. Even within the closure expression, IDE features still *mostly* work, which is an improvement over the status quo.
- For future maintainers looking at the call site, the macro's effect should hopefully be pretty obvious and intuitive, reducing the need to even look at the helper macro. And the helper macro itself is largely straightforward, with its biggest complication being that it necessarily uses the `$name` metavar from the outer macro.
There should be no change to compiler behaviour.
r? nnethercote (or compiler)
rust-borsBot pushed a commit that referenced this pull request Mar 11, 2026
…uwer
Rollup of 4 pull requests
Successful merges:
- #153571 (Avoid ICE when an EII declaration conflicts with a constructor)
- #153581 (Simplify `type_of_opaque`.)
- #153685 (Introduce `for_each_query_vtable!` to move more code out of query macros)
- #153710 (remove `.ftl` checks from tidy)
JonathanBrouwer added a commit to JonathanBrouwer/rust that referenced this pull request Mar 11, 2026
…cote
Introduce `for_each_query_vtable!` to move more code out of query macros
After rust-lang#153114 moved a few for-each-query functions into the big `rustc_query_impl::plumbing` macro, I have found that those functions became much harder to navigate and modify, because they no longer have access to ordinary IDE features in rust-analyzer. Even *finding* the functions is considerably harder, because a plain go-to-definition no longer works smoothly.
This PR therefore tries to move as much of that code back out of the macro as possible, with the aid of a smaller `for_each_query_vtable!` helper macro. A typical use of that macro looks like this:
```rust
for_each_query_vtable!(ALL, tcx, |query| {
query_key_hash_verify(query, tcx);
});
```
The result is an outer function consisting almost entirely of plain Rust code, with all of the usual IDE affordances expected of normal Rust code. Because it uses plain Rust syntax, it can also be formatted automatically by rustfmt.
Adding another layer of macro-defined macros is not something I propose lightly, but in this case I think the improvement is well worth it:
- The outer functions can once again be defined as “normal” Rust functions, right next to their corresponding inner functions, making navigation and modification much easier.
- The closure expression is ordinary Rust code that simply gets repeated ~300 times in the expansion, once for each query, in order to account for the variety of key/value/cache types used by different queries. Even within the closure expression, IDE features still *mostly* work, which is an improvement over the status quo.
- For future maintainers looking at the call site, the macro's effect should hopefully be pretty obvious and intuitive, reducing the need to even look at the helper macro. And the helper macro itself is largely straightforward, with its biggest complication being that it necessarily uses the `$name` metavar from the outer macro.
There should be no change to compiler behaviour.
r? nnethercote (or compiler)
rust-borsBot pushed a commit that referenced this pull request Mar 11, 2026
…uwer
Rollup of 9 pull requests
Successful merges:
- #153571 (Avoid ICE when an EII declaration conflicts with a constructor)
- #153581 (Simplify `type_of_opaque`.)
- #153611 (interpret: go back to regular string interpolation for error messages)
- #153635 (Unify same-span labels in move error diagnostics)
- #153660 (mir-opt: Drop invalid debuginfos after SingleUseConsts.)
- #153685 (Introduce `for_each_query_vtable!` to move more code out of query macros)
- #153671 (Make Enzyme has dependent on LLVM hash)
- #153710 (remove `.ftl` checks from tidy)
- #153720 (doc/rustc: clarify how to contact arm-maintainers)
rust-borsBot pushed a commit that referenced this pull request Mar 11, 2026
…uwer
Rollup of 9 pull requests
Successful merges:
- #153571 (Avoid ICE when an EII declaration conflicts with a constructor)
- #153581 (Simplify `type_of_opaque`.)
- #153611 (interpret: go back to regular string interpolation for error messages)
- #153635 (Unify same-span labels in move error diagnostics)
- #153660 (mir-opt: Drop invalid debuginfos after SingleUseConsts.)
- #153685 (Introduce `for_each_query_vtable!` to move more code out of query macros)
- #153671 (Make Enzyme has dependent on LLVM hash)
- #153710 (remove `.ftl` checks from tidy)
- #153720 (doc/rustc: clarify how to contact arm-maintainers)
rust-borsBot pushed a commit that referenced this pull request Mar 11, 2026
…uwer
Rollup of 9 pull requests
Successful merges:
- #153571 (Avoid ICE when an EII declaration conflicts with a constructor)
- #153581 (Simplify `type_of_opaque`.)
- #153611 (interpret: go back to regular string interpolation for error messages)
- #153635 (Unify same-span labels in move error diagnostics)
- #153660 (mir-opt: Drop invalid debuginfos after SingleUseConsts.)
- #153685 (Introduce `for_each_query_vtable!` to move more code out of query macros)
- #153671 (Make Enzyme has dependent on LLVM hash)
- #153710 (remove `.ftl` checks from tidy)
- #153720 (doc/rustc: clarify how to contact arm-maintainers)
rust-borsBot pushed a commit that referenced this pull request Mar 11, 2026
…uwer
Rollup of 12 pull requests
Successful merges:
- #152569 (Stop using rustc_layout_scalar_valid_range_* in rustc)
- #153421 (Fix ICE in fn_delegation when child segment resolves to a trait)
- #153571 (Avoid ICE when an EII declaration conflicts with a constructor)
- #153581 (Simplify `type_of_opaque`.)
- #153611 (interpret: go back to regular string interpolation for error messages)
- #153635 (Unify same-span labels in move error diagnostics)
- #153660 (mir-opt: Drop invalid debuginfos after SingleUseConsts.)
- #153685 (Introduce `for_each_query_vtable!` to move more code out of query macros)
- #153722 (miri-test-libstd: use --tests and update some comments)
- #153671 (Make Enzyme has dependent on LLVM hash)
- #153710 (remove `.ftl` checks from tidy)
- #153720 (doc/rustc: clarify how to contact arm-maintainers)
@rust-bors
rust-borsBot merged commit 8449503 into rust-lang:mainMar 12, 2026
12 of 22 checks passed
@Zalathar
Zalathar deleted the for-each-query branch March 12, 2026 00:24
github-actionsBot pushed a commit to rust-lang/miri that referenced this pull request Mar 12, 2026
…uwer
Rollup of 12 pull requests
Successful merges:
- rust-lang/rust#152569 (Stop using rustc_layout_scalar_valid_range_* in rustc)
- rust-lang/rust#153421 (Fix ICE in fn_delegation when child segment resolves to a trait)
- rust-lang/rust#153571 (Avoid ICE when an EII declaration conflicts with a constructor)
- rust-lang/rust#153581 (Simplify `type_of_opaque`.)
- rust-lang/rust#153611 (interpret: go back to regular string interpolation for error messages)
- rust-lang/rust#153635 (Unify same-span labels in move error diagnostics)
- rust-lang/rust#153660 (mir-opt: Drop invalid debuginfos after SingleUseConsts.)
- rust-lang/rust#153685 (Introduce `for_each_query_vtable!` to move more code out of query macros)
- rust-lang/rust#153722 (miri-test-libstd: use --tests and update some comments)
- rust-lang/rust#153671 (Make Enzyme has dependent on LLVM hash)
- rust-lang/rust#153710 (remove `.ftl` checks from tidy)
- rust-lang/rust#153720 (doc/rustc: clarify how to contact arm-maintainers)
@cuvipercuviper added this to the 1.96.0 milestone Mar 16, 2026
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

A-query-systemArea: The rustc query system (https://rustc-dev-guide.rust-lang.org/query.html)S-waiting-on-borsStatus: Waiting on bors to run and complete tests. Bors will change the label on completion.T-compilerRelevant 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.

5 participants

@Zalathar@rust-timer@nnethercote@rustbot@cuviper