Skip to content

Fix doc_cfg not working as expected on trait impls#153964

Open
GuillaumeGomez wants to merge 4 commits intorust-lang:mainfrom
GuillaumeGomez:fix-trait-impl-doc-cfg
Open

Fix doc_cfg not working as expected on trait impls#153964
GuillaumeGomez wants to merge 4 commits intorust-lang:mainfrom
GuillaumeGomez:fix-trait-impl-doc-cfg

Conversation

@GuillaumeGomez
Copy link
Member

Fixes #153655.

I spent waaaaay too much time on this fix. So the current issue is that rustdoc gets its items in two passes:

  1. All items
  2. Trait/blanket/auto impls

Because of that, the trait impls are not stored "correctly" in the rustdoc AST, meaning that the propagate_doc_cfg pass doesn't work correctly on them. So initially, I tried to "clean" the impls at the same time as the other items. However, it created a monstruous amount of bugs and issues and after two days, I decided to give up on this approach (might be worth fixing that in the future!). You can see what I tried here.

So instead, since the impls are stored at the end, I create placeholders for impls and in propagate_doc_cfg, I store the cfg "context" (more clear when reading the code 😛) and re-use it later on when the "real" impl comes up.

r? @lolbinarycat

@rustbot rustbot added A-rustdoc-json Area: Rustdoc JSON backend S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. T-rustdoc Relevant to the rustdoc team, which will review and decide on the PR/issue. T-rustdoc-frontend Relevant to the rustdoc-frontend team, which will review and decide on the web UI/UX output. labels Mar 16, 2026
@rustbot

This comment has been minimized.

@GuillaumeGomez GuillaumeGomez changed the title Fix trait impl doc cfg Fix doc_cfg not working as expected on trait impls Mar 16, 2026
@rust-log-analyzer

This comment has been minimized.

@GuillaumeGomez
Copy link
Member Author

Not great that ImplItem and PlaceholderImplItem need to be handled in rustdoc lints. :-/

@GuillaumeGomez
Copy link
Member Author

And CI passed. \o/

Copy link
Contributor

@lolbinarycat lolbinarycat left a comment

Choose a reason for hiding this comment

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

Code looks good to me but I still need to do a more in-depth investigation of the logic. For now, here's some nits and clarifying questions.

View changes since this review

impl_: &hir::Impl<'tcx>,
def_id: LocalDefId,
cx: &mut DocContext<'tcx>,
// If `renamed` is some, then this is an inlined impl and it will be handled later on in the
Copy link
Contributor

Choose a reason for hiding this comment

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

nit: ambiguous pronoun, this would be less ambiguous if "this" was replaced with an actual name.


clean::ImplItem(..) => {}

// They have no use anymore, so always remove them.
Copy link
Contributor

Choose a reason for hiding this comment

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

nit: great comments explain why code does something.

@@ -0,0 +1,59 @@
// This test ensures that `doc_cfg` feature is working as expected on trait impls.
Copy link
Contributor

Choose a reason for hiding this comment

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

just to be sure: we do have a test for non-trait impls, right? we definitely don't want to regress that.

also, do we have a test for non-auto doc(cfg(...)) on trait items?

Copy link
Member Author

@GuillaumeGomez GuillaumeGomez Mar 17, 2026

Choose a reason for hiding this comment

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

Doesn't hurt to add one in the same test I guess. Gonna add a test for non-auto doc(cfg(...)) too.

match item.kind {
ItemKind::Impl(ref impl_) => return clean_impl(impl_, item.owner_id.def_id, cx),
ItemKind::Impl(ref impl_) => {
return clean_impl(impl_, item.owner_id.def_id, cx, renamed);
Copy link
Contributor

Choose a reason for hiding this comment

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

what does it mean for an impl to be renamed?

Copy link
Member Author

Choose a reason for hiding this comment

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

The explanation is on the clean_impl function but I can copy/paste it here too.

@GuillaumeGomez GuillaumeGomez force-pushed the fix-trait-impl-doc-cfg branch from ce71ac8 to 2dd7677 Compare March 17, 2026 11:47
@rustbot

This comment has been minimized.

@GuillaumeGomez
Copy link
Member Author

Added comments and greatly extended the tests.

@rust-log-analyzer

This comment has been minimized.

@GuillaumeGomez
Copy link
Member Author

Seems like a flaky failure. Restarted CI.

Copy link
Contributor

@lolbinarycat lolbinarycat left a comment

Choose a reason for hiding this comment

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

I took a closer look at the actual logic this time and it seems solid and straightforwards, I can't come up with any edge cases that it would cause problems in.

My only issue of immediate relevance is rustc_span::symbol::kw::Impl and renamed being used in a somewhat unintuitive way, not sure what the best way to address that is but it definitely has an impact on code readability. I also found some missing test coverage but that's mostly unrelated so that can be handled in a followup PR if you want.

View changes since this review

| clean::ProvidedAssocConstItem(..)
| clean::ImplAssocConstItem(..)
| clean::RequiredAssocTypeItem(..)
| clean::PlaceholderImplItem
Copy link
Contributor

Choose a reason for hiding this comment

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

This made me realize that we don't actually have a test for how rustdoc::missing_doc_code_examples interacts with inherent impls (we do have them for trait impls, which is what is relevant to this PR, and what I was initially checking).

here's a search for all the test files using that lint

Copy link
Member Author

Choose a reason for hiding this comment

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

Gonna send another PR for it then. :)

Comment on lines +206 to +209
clean::PlaceholderImplItem => {
// The "real" impl items are handled below.
return;
}
Copy link
Contributor

Choose a reason for hiding this comment

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

note: we do have test coverage for doc coverage involving both types of impl. good.

Comment on lines +89 to +95
if let ItemKind::ImplItem(_) = item.kind
&& let Some(cfg_info) = self.impl_cfg_info.remove(&item.item_id)
{
self.cfg_info = cfg_info;
}

if let ItemKind::PlaceholderImplItem = item.kind {
Copy link
Contributor

Choose a reason for hiding this comment

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

nit: if let with no new bindings introduced. might be more intuitive if these were written with matches!? but this pattern is used a bit around rustdoc, so if you'd rather keep it how it is that's fine.

Copy link
Member Author

@GuillaumeGomez GuillaumeGomez Mar 18, 2026

Choose a reason for hiding this comment

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

I tend to prefer inline code over macros if I can, and I have to admit I find this let binding funny. Brain fart of the day I guess. ^^'

Comment on lines +430 to +438
self.add_to_current_mod(
item,
if impl_.of_trait.is_none() {
None
} else {
Some(rustc_span::symbol::kw::Impl)
},
None,
);
Copy link
Contributor

Choose a reason for hiding this comment

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

This seems like a little bit of a magic value, I'd at least like if this special value was documented somewhere, perhaps on the doc comment of Module::items. I understand the use of a sentinel here because the alternative involves adding a new field to the tuple in the items Vec, or refactoring that into a more principled enum, which I'm sure would be quite the undertaking.

Actually, this isn't quite a sentinel value, is it, because Impl items in this context don't actually care about the inner value of renamed, just if it is None, correct?

Copy link
Member Author

Choose a reason for hiding this comment

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

Yeah. I'll add a comment to make that clear though because it really comes out of nowhere.

@GuillaumeGomez GuillaumeGomez force-pushed the fix-trait-impl-doc-cfg branch from 2dd7677 to 3f0f7d7 Compare March 18, 2026 15:49
@GuillaumeGomez
Copy link
Member Author

I added code comments to explain that the symbol is used as a sentinel value.

Comment on lines +436 to +440
if impl_.of_trait.is_none() {
None
} else {
Some(rustc_span::symbol::kw::Impl)
},
Copy link
Member

Choose a reason for hiding this comment

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

Would replacing parameter type Option<Symbol> with Option<BikeshedTy> be possible / much of a hassle where BikeshedTy is a new type that could be defined like enum BikeshedTy { BikeshedName(Symbol), BikeshedAnon }? I haven't read the rest of the diff, lol

Copy link
Member Author

@GuillaumeGomez GuillaumeGomez Mar 18, 2026

Choose a reason for hiding this comment

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

Context: this argument is what an inlined item is renamed into. So no, I don't want to rename it. 😝

JonathanBrouwer added a commit to JonathanBrouwer/rust that referenced this pull request Mar 19, 2026
…amples-improvement, r=lolbinarycat

Don't emit rustdoc `missing_doc_code_examples` lint on impl items

@lolbinarycat realized in [this comment](rust-lang#153964 (comment)) that we weren't testing some cases for the `missing_doc_code_examples` lint. Turns out that it was not handling this case well. =D

So in short: `missing_doc_code_examples` lint should not be emitted on impl items and this PR fixes that.

r? @lolbinarycat
JonathanBrouwer added a commit to JonathanBrouwer/rust that referenced this pull request Mar 19, 2026
…amples-improvement, r=lolbinarycat

Don't emit rustdoc `missing_doc_code_examples` lint on impl items

@lolbinarycat realized in [this comment](rust-lang#153964 (comment)) that we weren't testing some cases for the `missing_doc_code_examples` lint. Turns out that it was not handling this case well. =D

So in short: `missing_doc_code_examples` lint should not be emitted on impl items and this PR fixes that.

r? @lolbinarycat
Zalathar added a commit to Zalathar/rust that referenced this pull request Mar 20, 2026
…amples-improvement, r=lolbinarycat

Don't emit rustdoc `missing_doc_code_examples` lint on impl items

@lolbinarycat realized in [this comment](rust-lang#153964 (comment)) that we weren't testing some cases for the `missing_doc_code_examples` lint. Turns out that it was not handling this case well. =D

So in short: `missing_doc_code_examples` lint should not be emitted on impl items and this PR fixes that.

r? @lolbinarycat
@rust-bors

This comment has been minimized.

@GuillaumeGomez GuillaumeGomez force-pushed the fix-trait-impl-doc-cfg branch from 3f0f7d7 to 2752dc5 Compare March 20, 2026 16:49
@rustbot
Copy link
Collaborator

rustbot commented Mar 20, 2026

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

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

@rustbot
Copy link
Collaborator

rustbot commented Mar 20, 2026

⚠️ Warning ⚠️

  • There are issue links (such as #123) in the commit messages of the following commits.
    Please move them to the PR description, to avoid spamming the issues with references to the commit, and so this bot can automatically canonicalize them to avoid issues with subtree.

@GuillaumeGomez
Copy link
Member Author

Fixed merge conflict.

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

Labels

A-rustdoc-json Area: Rustdoc JSON backend S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. T-rustdoc Relevant to the rustdoc team, which will review and decide on the PR/issue. T-rustdoc-frontend Relevant to the rustdoc-frontend team, which will review and decide on the web UI/UX output.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

rustdoc reports wrong config conditions for impl LowerExp for integers

5 participants