fulfill #[expect] expectations from derive generated code#158943
fulfill #[expect] expectations from derive generated code#158943Albab-Hasan wants to merge 5 commits into
#[expect] expectations from derive generated code#158943Conversation
an `#[expect]` on an item now covers the impls `#[derive]` generates from it. lint level building recognizes a derive generated impl and applies the derived from items `#[expect]` attrs to it reusing their expectation ids. a lint triggered in the derived code is suppressed and fulfills the original expectation because the id is literally the same one. one written attr is one expectation. fulfilled from either site. reported exactly once when genuinely unfulfilled. copying the attr during expansion was tried before and reverted because `cfg`/`cfg_attr` processing re-parses the derive input from tokens and attr ids dont survive that. here identity never travels through token streams so theres nothing to desync. fixes rust-lang#150553
…for expectation inheritance
|
@Urgau hey can u pls look into this? sorry for the bother |
|
Thanks, that looks better. I will take a closer look tomorrow or Monday. You can switch to ready for review. |
|
@bors try @rust-timer queue |
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
…try> fulfill `#[expect]` expectations from derive generated code
This comment has been minimized.
This comment has been minimized.
|
Finished benchmarking commit (c23f6fe): comparison URL. Overall result: ❌✅ regressions and improvements - no action neededBenchmarking means the PR may be perf-sensitive. Consider adding rollup=never if this change is not fit for rolling up. @rustbot label: -S-waiting-on-perf -perf-regression Instruction countOur most reliable metric. Used to determine the overall result above. However, even this metric can be noisy.
Max RSS (memory usage)Results (primary 2.6%, secondary 1.7%)A less reliable metric. May be of interest, but not used to determine the overall result above.
CyclesResults (secondary 5.1%)A less reliable metric. May be of interest, but not used to determine the overall result above.
Binary sizeThis perf run didn't have relevant results for this metric. Bootstrap: 489.358s -> 489.445s (0.02%) |
| levels.add_command_line(); | ||
| } | ||
|
|
||
| levels.inherit_derive_expectations(owner); |
There was a problem hiding this comment.
Can you add a comment in
explaining why#[expect] is not on that list and pointing to this code?
| } | ||
| let hir::OwnerNode::Item(item) = tcx.hir_owner_node(owner) else { return }; | ||
| let hir::ItemKind::Impl(impl_) = &item.kind else { return }; | ||
| if !item.span.in_derive_expansion() { |
There was a problem hiding this comment.
Have you tested what happens with a proc-macro?
Could you add a test case with Span::call_site, Span::mixed_site and Span::def_site.
@petrochenkov I know you've worked on spans/hygiene data before. Do you know if we can trust the ExpnData will always be right?
There was a problem hiding this comment.
Of course not, procedural macros can assign any spans they want to the produced tokens.
There was a problem hiding this comment.
The general approach from #152289 seems right to me, compared to what this PR attempts to do.
Maybe in some modified form, with expects downgrated to allows or something.
Not sure why it relied on AttrIds being preserved. The mental model is that any proc macro generates tokens, and the tokens are then parsed. Built-in proc macros do optimize things by generating AST directly and skipping the parsing, but that's only an optimization, and the observable behavior should be as if the tokens were produced and parsed.
There was a problem hiding this comment.
That's what I also though, thanks for confirming it.
@Albab-Hasan unless there is a way to not rely (at all!) on the spans (and it's hygiene data), this approach seems like a dead-end.
There was a problem hiding this comment.
I'll look into it; see if anything can be done. if not I'll close this pr
There was a problem hiding this comment.
Maybe in some modified form, with
expects downgrated toallows or something.
I proposed that to T-lang, but they explicitly wants #[expect] to act as one, since a warning may only be emitted in the derived code.
Not sure why it relied on
AttrIds being preserved.
That's how the implementation of expectation works. StableLintExpectationId takes an attr_index.
There was a problem hiding this comment.
#[expect]to act as one, since a warning may only be emitted in the derived code.
Then it does require introducing some new infrastructure to preserve "item grouping", to implement this properly.
In #158980 we have a similar situation for cfg traces for derived impls used by rustdoc, but the traces can be best effort and use hacks.
Co-authored-by: Urgau <3616612+Urgau@users.noreply.github.com>
… hygiene Proc macros can assign arbitrary spans to the tokens they produce, so span expansion data cannot prove an impl came from a derive. Gate expectation inheritance on is_builtin_derived instead, and change that helper to read expn_that_defined, the def collector's record of which expansion created the definition, which token spans cannot influence. Only builtin derive macros are covered; a new test checks that a proc-macro derive emitting automatically_derived impls with call_site, mixed_site or def_site spans never inherits or fulfills expectations.
|
the impl is now recognized through the gate also requires the expansion to be a builtin derive, this also holds under the tokens-then-parse model @petrochenkov described. if builtin derives went through print and reparse the impl would still be collected under the same derive the check itself is |
|
I like the idea with Both this feature and #158980 ideally need some proper design, accounting for macro calls in all positions, not just derives in item positions.
|
I guess that depends if we want user derives to behave the same as the builtin one. We currently only duplicate |
|
checked the other positions on master before answering the scope question. non- moving it into so id keep this builtin derives only and leave user derives and other positions to the follow-up design. what do you think? |
|
@bors try @rust-timer queue |
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
…try> fulfill `#[expect]` expectations from derive generated code
This comment has been minimized.
This comment has been minimized.
|
Finished benchmarking commit (58c0d17): comparison URL. Overall result: ❌ regressions - no action neededBenchmarking means the PR may be perf-sensitive. Consider adding rollup=never if this change is not fit for rolling up. @rustbot label: -S-waiting-on-perf -perf-regression Instruction countOur most reliable metric. Used to determine the overall result above. However, even this metric can be noisy.
Max RSS (memory usage)Results (primary 4.8%, secondary 1.2%)A less reliable metric. May be of interest, but not used to determine the overall result above.
CyclesResults (secondary 1.1%)A less reliable metric. May be of interest, but not used to determine the overall result above.
Binary sizeResults (primary 0.1%, secondary 0.1%)A less reliable metric. May be of interest, but not used to determine the overall result above.
Bootstrap: 491.028s -> 491.058s (0.01%) |
|
The perf regressions are exclusively in the derive benchmark, it has 300 derives. Seems quite unavoidable. Unless you maybe see a way to optimize it @Albab-Hasan? |
|
i think i can roughly halve it by gating first on the impls own |
|
retime pls |
|
@bors try @rust-timer queue |
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
…try> fulfill `#[expect]` expectations from derive generated code
This comment has been minimized.
This comment has been minimized.
|
Finished benchmarking commit (5f44591): comparison URL. Overall result: ❌ regressions - no action neededBenchmarking means the PR may be perf-sensitive. Consider adding rollup=never if this change is not fit for rolling up. @rustbot label: -S-waiting-on-perf -perf-regression Instruction countOur most reliable metric. Used to determine the overall result above. However, even this metric can be noisy.
Max RSS (memory usage)This perf run didn't have relevant results for this metric. CyclesResults (primary -2.5%)A less reliable metric. May be of interest, but not used to determine the overall result above.
Binary sizeThis perf run didn't have relevant results for this metric. Bootstrap: 486.808s -> 488.065s (0.26%) |
|
is this good or would more optimization be preffered? |
|
Thanks, that's plenty optimized. I will take another look in the next days. |
View all comments
an
#[expect]on an item now covers the impls#[derive]generates from it. done at lint level building by reusing the items own expectation ids. no expansion changes at all so thecfg/cfg_attrattr id desync that forced the revert of #152289 in #153055 cant happen.context in the issue thread starting at #150553 (comment)
fixes #150553
r? @Urgau