Skip to content

Implement RFC 3631: add rustdoc doc_cfg features #138907

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 12 commits into
base: master
Choose a base branch
from

Conversation

GuillaumeGomez
Copy link
Member

@GuillaumeGomez GuillaumeGomez commented Mar 24, 2025

Implementation of rust-lang/rfcs#3631.

This implementation actually resulted in a lot of simplifications:

  • All cfg computation is now done in one place: propagate_doc_cfg.rs. Because (trait) impls are not retrieved at the same time as the other items, we cannot perform this computation in the clean process, it needs to be after.
  • Because there is cfg inheritance, we can keep track of them in one place (in propagate_doc_cfg.rs), meaning we don't need to copy an item's attributes to its children anymore. Only exception: impl items. For them we clone only cfg attributes.
  • propagate_doc_cfg.rs is also now much simpler, much less need to keep track of parents, since everything we need is handled by the new CfgInfo type.
  • I also suspect that Cfg::simplify_with could either be removed or at least used directly into propagate_doc_cfg.rs when we compute cfgs. Considering how big the PR already is, I'll do it in a follow-up.

I didn't remove the doc_cfg* features in this PR because some dependencies used in rustc (like stdarch) are using it, so we need to have a nightly released with this PR before I can switch to the new feature.

r? ghost

@rustbot rustbot added A-attributes Area: Attributes (`#[…]`, `#![…]`) 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. T-libs Relevant to the library team, which will review and decide on the PR/issue. 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 24, 2025
@rust-log-analyzer

This comment has been minimized.

@petrochenkov
Copy link
Contributor

What remains to be done:

I'd also want to block the stabilization on landing #138844 to avoid a stable rustdoc feature relying on externally observable hacks in rustc.
The crater run in #138844 returned mostly clean, so I expect it to land soon.

@GuillaumeGomez
Copy link
Member Author

Noted! And that will be a nice improvement, thanks!

Just one thing left for the cfg expansion missing: #[cfg_attr(blabla, derive(Debug))]. In this case, the cfg is not kept in the generated derive items. It's been in my TODO list for a long time now. ^^'

@petrochenkov
Copy link
Contributor

Just one thing left for the cfg expansion missing: #[cfg_attr(blabla, derive(Debug))]

Do you mean like in #138515? :)

@GuillaumeGomez
Copy link
Member Author

You're my hero! Gonna need to handle this new attribute then. :)

@rust-log-analyzer

This comment has been minimized.

@bors
Copy link
Collaborator

bors commented Mar 25, 2025

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

@GuillaumeGomez GuillaumeGomez force-pushed the rfc-3631 branch 2 times, most recently from d88598f to db25eea Compare March 27, 2025 10:18
@rustbot rustbot added the A-run-make Area: port run-make Makefiles to rmake.rs label Mar 27, 2025
@rust-log-analyzer

This comment has been minimized.

@bors
Copy link
Collaborator

bors commented Mar 27, 2025

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

@GuillaumeGomez GuillaumeGomez force-pushed the rfc-3631 branch 2 times, most recently from b8cb424 to b581ce1 Compare March 28, 2025 23:54
@rust-log-analyzer

This comment has been minimized.

@rust-log-analyzer

This comment has been minimized.

@GuillaumeGomez GuillaumeGomez force-pushed the rfc-3631 branch 4 times, most recently from 71369a1 to fbee8a9 Compare April 1, 2025 15:52
@rust-log-analyzer

This comment has been minimized.

@GuillaumeGomez
Copy link
Member Author

Rebased and replaced usage of removed name_or_empty.

@bors
Copy link
Collaborator

bors commented May 6, 2025

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

@GuillaumeGomez
Copy link
Member Author

Fixed merge conflict.

@Manishearth
Copy link
Member

I'll try and take a look at this impl

Copy link
Member

@Manishearth Manishearth left a comment

Choose a reason for hiding this comment

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

Code generally looks good! Needs some docs and then we should be good to go, I think. Would ideally like a second review but overall I think it's fine.

@@ -776,3 +694,271 @@ will be split as follows:
"you today?",
]
```

Copy link
Member

Choose a reason for hiding this comment

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

These docs could probably use an editorial pass but I'd prefer to skip that for now, it's a separate step of the stabilization process. So I'm not reviewing these too closely, they seem to be roughly accurate.

@GuillaumeGomez
Copy link
Member Author

Added missing docs, renamed some functions too to be easier to understand what they do just by their name (doc is good but good naming is important too 😅). I applied the code improvement suggestion and improved the error message. Thanks a lot!

@rust-log-analyzer
Copy link
Collaborator

A job failed! Check out the build log: (web) (plain)

Click to see the possible cause of the failure (guessed by this bot)
#2 transferring dockerfile: 2.62kB done
#2 DONE 0.0s

#3 [internal] load metadata for docker.io/library/ubuntu:22.04
#3 ERROR: failed to copy: httpReadSeeker: failed open: unexpected status code https://registry-1.docker.io/v2/library/ubuntu/manifests/sha256:899ec23064539c814a4dbbf98d4baf0e384e4394ebc8638bea7bbe4cb8ef4e12: 429 Too Many Requests - Server message: toomanyrequests: You have reached your unauthenticated pull rate limit. https://www.docker.com/increase-rate-limit
------
 > [internal] load metadata for docker.io/library/ubuntu:22.04:
------
Dockerfile:1
--------------------
   1 | >>> FROM ubuntu:22.04
   2 |     
   3 |     ARG DEBIAN_FRONTEND=noninteractive
--------------------
ERROR: failed to solve: ubuntu:22.04: failed to resolve source metadata for docker.io/library/ubuntu:22.04: failed to copy: httpReadSeeker: failed open: unexpected status code https://registry-1.docker.io/v2/library/ubuntu/manifests/sha256:899ec23064539c814a4dbbf98d4baf0e384e4394ebc8638bea7bbe4cb8ef4e12: 429 Too Many Requests - Server message: toomanyrequests: You have reached your unauthenticated pull rate limit. https://www.docker.com/increase-rate-limit
Command failed. Attempt 2/5:
#0 building with "agitated_davinci" instance using docker-container driver

#1 [internal] load build definition from Dockerfile
#1 transferring dockerfile: 2.62kB done
#1 DONE 0.0s

#2 [internal] load metadata for docker.io/library/ubuntu:22.04
#2 ERROR: failed to copy: httpReadSeeker: failed open: unexpected status code https://registry-1.docker.io/v2/library/ubuntu/manifests/sha256:899ec23064539c814a4dbbf98d4baf0e384e4394ebc8638bea7bbe4cb8ef4e12: 429 Too Many Requests - Server message: toomanyrequests: You have reached your unauthenticated pull rate limit. https://www.docker.com/increase-rate-limit
------
 > [internal] load metadata for docker.io/library/ubuntu:22.04:
------
Dockerfile:1
--------------------
   1 | >>> FROM ubuntu:22.04
   2 |     
   3 |     ARG DEBIAN_FRONTEND=noninteractive
--------------------
ERROR: failed to solve: ubuntu:22.04: failed to resolve source metadata for docker.io/library/ubuntu:22.04: failed to copy: httpReadSeeker: failed open: unexpected status code https://registry-1.docker.io/v2/library/ubuntu/manifests/sha256:899ec23064539c814a4dbbf98d4baf0e384e4394ebc8638bea7bbe4cb8ef4e12: 429 Too Many Requests - Server message: toomanyrequests: You have reached your unauthenticated pull rate limit. https://www.docker.com/increase-rate-limit
Command failed. Attempt 3/5:
#0 building with "agitated_davinci" instance using docker-container driver

#1 [internal] load build definition from Dockerfile
#1 transferring dockerfile: 2.62kB done
#1 DONE 0.0s

#2 [internal] load metadata for docker.io/library/ubuntu:22.04
#2 ERROR: failed to copy: httpReadSeeker: failed open: unexpected status code https://registry-1.docker.io/v2/library/ubuntu/manifests/sha256:899ec23064539c814a4dbbf98d4baf0e384e4394ebc8638bea7bbe4cb8ef4e12: 429 Too Many Requests - Server message: toomanyrequests: You have reached your unauthenticated pull rate limit. https://www.docker.com/increase-rate-limit
------
 > [internal] load metadata for docker.io/library/ubuntu:22.04:
------
Dockerfile:1
--------------------
   1 | >>> FROM ubuntu:22.04
   2 |     
   3 |     ARG DEBIAN_FRONTEND=noninteractive
--------------------
ERROR: failed to solve: ubuntu:22.04: failed to resolve source metadata for docker.io/library/ubuntu:22.04: failed to copy: httpReadSeeker: failed open: unexpected status code https://registry-1.docker.io/v2/library/ubuntu/manifests/sha256:899ec23064539c814a4dbbf98d4baf0e384e4394ebc8638bea7bbe4cb8ef4e12: 429 Too Many Requests - Server message: toomanyrequests: You have reached your unauthenticated pull rate limit. https://www.docker.com/increase-rate-limit
Command failed. Attempt 4/5:
#0 building with "agitated_davinci" instance using docker-container driver

#1 [internal] load build definition from Dockerfile
#1 transferring dockerfile: 2.62kB done
#1 DONE 0.0s

#2 [internal] load metadata for docker.io/library/ubuntu:22.04
#2 ERROR: failed to copy: httpReadSeeker: failed open: unexpected status code https://registry-1.docker.io/v2/library/ubuntu/manifests/sha256:899ec23064539c814a4dbbf98d4baf0e384e4394ebc8638bea7bbe4cb8ef4e12: 429 Too Many Requests - Server message: toomanyrequests: You have reached your unauthenticated pull rate limit. https://www.docker.com/increase-rate-limit
------
 > [internal] load metadata for docker.io/library/ubuntu:22.04:
------
Dockerfile:1
--------------------
   1 | >>> FROM ubuntu:22.04
   2 |     
   3 |     ARG DEBIAN_FRONTEND=noninteractive
--------------------
ERROR: failed to solve: ubuntu:22.04: failed to resolve source metadata for docker.io/library/ubuntu:22.04: failed to copy: httpReadSeeker: failed open: unexpected status code https://registry-1.docker.io/v2/library/ubuntu/manifests/sha256:899ec23064539c814a4dbbf98d4baf0e384e4394ebc8638bea7bbe4cb8ef4e12: 429 Too Many Requests - Server message: toomanyrequests: You have reached your unauthenticated pull rate limit. https://www.docker.com/increase-rate-limit
Command failed. Attempt 5/5:
#0 building with "agitated_davinci" instance using docker-container driver

#1 [internal] load build definition from Dockerfile
#1 transferring dockerfile: 2.62kB done
#1 DONE 0.0s

#2 [internal] load metadata for docker.io/library/ubuntu:22.04
#2 ERROR: failed to copy: httpReadSeeker: failed open: unexpected status code https://registry-1.docker.io/v2/library/ubuntu/manifests/sha256:899ec23064539c814a4dbbf98d4baf0e384e4394ebc8638bea7bbe4cb8ef4e12: 429 Too Many Requests - Server message: toomanyrequests: You have reached your unauthenticated pull rate limit. https://www.docker.com/increase-rate-limit
------
 > [internal] load metadata for docker.io/library/ubuntu:22.04:
------
Dockerfile:1
--------------------
   1 | >>> FROM ubuntu:22.04
   2 |     
   3 |     ARG DEBIAN_FRONTEND=noninteractive
--------------------
ERROR: failed to solve: ubuntu:22.04: failed to resolve source metadata for docker.io/library/ubuntu:22.04: failed to copy: httpReadSeeker: failed open: unexpected status code https://registry-1.docker.io/v2/library/ubuntu/manifests/sha256:899ec23064539c814a4dbbf98d4baf0e384e4394ebc8638bea7bbe4cb8ef4e12: 429 Too Many Requests - Server message: toomanyrequests: You have reached your unauthenticated pull rate limit. https://www.docker.com/increase-rate-limit
The command has failed after 5 attempts.
##[error]Process completed with exit code 1.
Post job cleanup.

`#![doc(auto_cfg({$attr_name}(...)))]` expects a list of items

passes_doc_auto_cfg_hide_show_unexpected_item =
`#![doc(auto_cfg({$attr_name}(...)))]` only accepts identifiers or key/values items
Copy link
Member

Choose a reason for hiding this comment

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

nit:

Suggested change
`#![doc(auto_cfg({$attr_name}(...)))]` only accepts identifiers or key/values items
`#![doc(auto_cfg({$attr_name}(...)))]` only accepts identifiers or key/value items

}
MetaItemKind::List(list) => {
for item in list {
let Some(attr_name) = item.name() else { continue };
Copy link
Member

Choose a reason for hiding this comment

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

Shouldn't the else case emit an error since we've received an invalid entry for the auto_cfg list? E.g. doc(auto_cfg(42)) or doc(auto_cfg(foo::bar)).

Copy link
Member

Choose a reason for hiding this comment

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

Please add test cases for this missing error, along with the ones below.

);
} else if let Some(list) = item.meta_item_list() {
for item in list {
if item.meta_item_list().is_some() {
Copy link
Member

Choose a reason for hiding this comment

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

Shouldn't we also error if there is no meta item list but the item is an invalid cfg (e.g. a boolean, or a multi-segment path)?

hir_id,
item.span(),
errors::DocAutoCfgHideShowUnexpectedItem {
attr_name: attr_name.as_str(),
Copy link
Member

Choose a reason for hiding this comment

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

attr_name is either "hide" or "show" here, not the invalid cfg entry.

INVALID_DOC_ATTRIBUTES,
hir_id,
meta.span,
errors::DocAutoCfgHideShowExpectsList { attr_name: attr_name.as_str() },
Copy link
Member

Choose a reason for hiding this comment

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

Ditto.

fn default() -> Self {
Self {
hidden_cfg: [
Cfg::Cfg(sym::test, None),
Copy link
Member

Choose a reason for hiding this comment

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

I guess this answers my question above about why you removed test from the list of hidden cfgs 🙃

Any particular reason why you added it here though? The RFC specified only doc and doctest as hidden by default, not that we necessarily have to strictly follow that.

Comment on lines +1058 to +1059
/// This function checks if a same `cfg` is present in both `auto_cfg(hide(...))` and
/// `auto_cfg(show(...))` on the same item. If so, it emits an error.
Copy link
Member

Choose a reason for hiding this comment

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

nit: This function does more than just error handling since it also updates the cfg_info.hidden_cfg set. But the docs imply otherwise. Also, maybe use an enum instead of is_show: bool?

Comment on lines +1180 to +1191
if let Some(first_change) = changed_auto_active_status {
if cfg_info.auto_cfg_active != value {
tcx.sess.dcx().struct_span_err(
vec![first_change, attr.span],
"`auto_cfg` was disabled and enabled more than once on the same item",
).emit();
return None;
}
} else {
changed_auto_active_status = Some(attr.span);
}
cfg_info.auto_cfg_active = value;
Copy link
Member

Choose a reason for hiding this comment

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

Could you extract this as a closure and then use it in all 3 match arms? Or find some other way to avoid having 3 copies of this code.

Comment on lines +1124 to +1127
if !cfg_info.parent_is_doc_cfg {
cfg_info.current_cfg = Cfg::True;
cfg_info.parent_is_doc_cfg = true;
}
Copy link
Member

Choose a reason for hiding this comment

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

I'm a little bit confused about why we have cfg_info.parent_is_doc_cfg rather than a has_doc_cfg local variable. Maybe I'm missing something though. Can you help me understand what's going on with this flag better?

@@ -117,7 +116,7 @@ impl HirCollector<'_> {
) {
let ast_attrs = self.tcx.hir_attrs(self.tcx.local_def_id_to_hir_id(def_id));
if let Some(ref cfg) =
extract_cfg_from_attrs(ast_attrs.iter(), self.tcx, &FxHashSet::default())
extract_cfg_from_attrs(ast_attrs.iter(), self.tcx, &mut CfgInfo::default())
Copy link
Member

Choose a reason for hiding this comment

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

drive-by comment: Obviously this code existed before, but wondering if it'd make more sense to use the rustc cfg_matches logic instead here. Since we only care about the semantic meaning of the cfg not its display in rustdoc.

@rustbot rustbot added S-waiting-on-author Status: This is awaiting some action (such as code changes or more information) from the author. and removed S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. labels May 28, 2025
@@ -593,7 +594,7 @@ pub(crate) fn build_impl(
});
}

let (merged_attrs, cfg) = merge_attrs(cx, load_attrs(cx, did), attrs);
let (merged_attrs, cfg) = merge_attrs(cx, load_attrs(cx, did), attrs, &mut CfgInfo::default());
Copy link
Member

Choose a reason for hiding this comment

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

A little confused about the correctness of this. Seems like inlined impls should be subject to the auto_cfg specified for the place they're inlined into, but this puts them in a fresh context...?

@@ -1,5 +1,6 @@
#![doc(cfg_hide(test))]
//~^ ERROR `#[doc(cfg_hide)]` is experimental
// FIXME: Remove this file once feature is removed
Copy link
Member

Choose a reason for hiding this comment

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

Hasn't it been removed now?

Also, can you add some tests to make sure doc(auto_cfg) (perhaps with some different combinations of arguments, including none, to auto_cfg) and doc(cfg) are still feature-gated?

@bors
Copy link
Collaborator

bors commented May 28, 2025

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

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
A-attributes Area: Attributes (`#[…]`, `#![…]`) A-run-make Area: port run-make Makefiles to rmake.rs S-waiting-on-author Status: This is awaiting some action (such as code changes or more information) from the author. T-compiler Relevant to the compiler team, which will review and decide on the PR/issue. T-libs Relevant to the library team, which will review and decide on the PR/issue. 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.

8 participants