Tracking issue for `#[doc(cfg(…))]`, `#[doc(cfg_hide(…))]` and `doc_auto_cfg`
This is a tracking issue for the #[doc(cfg(…))] attribute (feature: doc_cfg) introduced in #43348 and #[doc(cfg_hide(…))] (feature: doc_cfg_hide) attribute introduced in #89596, along with the doc_auto_cfg feature introduced in https://github.com/rust-lang/rust/pull/90502.
Steps:
- [x] Implement: #43348
- [x] ~~Fix syntax mismatches: #84437~~ (fixed in #84442)
- [x] Adjust documentation (see instructions on forge) (https://github.com/rust-lang/rust/pull/92818)
- [ ] Stabilization PR (see instructions on forge): #79263
(cc #1998)
#[cfg(rustdoc)] is also gated on this issue but seems distinct (and less risky). Could we FCP that portion in particular?
I think that #[cfg(rustdoc)], when applied to structs, should automatically skip any non-public members. That would greatly reduce the amount of extra typing required by crates like Nix.
I was just trying this out for documenting crate features, it "works" but if this is a potential usecase it would be nice to special case the rendering for it:
There is also the issue that it repeats every feature on every item in a page:
When I last attempted to do something about rendering features I found it much more useful to separately keep track of "all required features" to render at the top of the items page and "newly introduced features" to render on the sub-items on the page, so you don't get this distracting repetition on every item.
We tried out this feature in Syn (https://github.com/dtolnay/syn/pull/734) and decided against using it yet.
What I am happy with
I like how the message turns out at the top of the doc page of a single type or function.

We had previously displayed this information using an italicized note, which was less noticeable.

What I am not happy with
Our index page becomes extremely noisy. I wish there were a way to not show all of these in our case. It is enough to have this information on the type's individual page. Cfg combinations are not among the most important information to show on the index page.

Also inheriting the same note onto every public field seems unnecessary in our use case.

The links in the opening post have gone dead.
What's the status of this? I've been using it on the time crate for as long as I can remember, and a number of other crates have been doing so as well.
For searchability: this is feature doc_cfg.
I changed the rendering of feature="foo" cfgs in #75330, which vastly simplifies the display on module index pages like shown in the syn screenshot above. I have also just opened #77672 to address the other point @dtolnay had, that there is no need to repeat the exact same cfg rendering over and over when it is already implied by context.
Other than those changes, there are bugs around trait implementation handling such as #68100, I want to try and create an exhaustive test covering trait implementations once #77672 is done and fix their handling.
After that, I feel like this would be ready for stabilization, it's had quite thorough usage on docs.rs already, so when rendering is all fixed we can rebuild the documentation for some large crates like tokio that use it and check whether there's other edgecase bugs remaining.
I'm wondering: Would it not make sense to generate doc_cfg hints automatically for any #[cfg(...)] items, without also needing to type #[doc(cfg(...))]?
So the following
#[cfg(all(target_feature = "avx", target_feature = "avx2"))]
#[doc(cfg(all(target_feature = "avx", target_feature = "avx2")))]
pub mod avx;
could just be
#[cfg(all(target_feature = "avx", target_feature = "avx2"))]
pub mod avx;
Otherwise, we're duplicating information unnecessarily, right?
...pretty much
In the general case yes, but there are quite a few crates using things like internal cfg's generated by their build.rs for compiler version detection that would not want to show those cfg to their users.
What about the opposite - having #[doc(cfg(x))] also imply #[cfg(x)]? I can't imagine a scenario where you wouldn't want to have that.
Not sure how hard that would be to implement, though - maybe @petrochenkov would know?
I'm wondering: Would it not make sense to generate doc_cfg hints automatically for any #[cfg(...)] items, without also needing to type #[doc(cfg(...))]?
Issue with that is if you want to implement the same function on different platforms in different ways. It shouldn't show up as gated on the current platform, but as not gated at all... or if it's only implemented on a set of platforms, then as that list.
So if there is such an implication, it should be opt in, eg via an empty #[doc(cfg)] tag. Maybe one can have a feature to make it opt out for a region of code, or an entire crate, but that requires manual review of the code, so can't be the default.
having #[doc(cfg(x))] also imply #[cfg(x)]?
IMO it's strange if #[doc(...)] influences normal code.
This is mostly looking good for syn. Filed one bug regarding the rendering of doc cfg on impls of empty traits: #79279.
One situation where it would be nice to have doc_cfg but doesn't currently seem to be feasible is on derive-generated implementations. Even if the provider of the derive wanted to, they'd have to manually accept an equivalent attribute to doc_cfg, only to pass it on.
Not something worth holding up stabilization over, but just something I noticed when adding in more attributes in some of my code.
Can't we have something like a feature-selector, a ui for selecting which feature to show?
I think https://github.com/rust-lang/rust/issues/84437 needs to be fixed before stabilizing this.
Can't we have something like a feature-selector, a ui for selecting which feature to show?
@aobatact the more features we add to doc(cfg), the longer it will be before it's stabilized. I would rather stabilize an MVP and then we can add features later.
There are some issues around how the #[doc(cfg)] annotations propagate from module to the items contained within, IIRC. It does only work in some circumstances (though I don't remember which ones, so I can't file a bug…)
That said, I don't think it or any other presentation concerns need to block the stabilization of the attribute itself – I don't believe the output of the rustdoc falls under the stability guarantees, so we can always fix that later.
One situation where it would be nice to have doc_cfg but doesn't currently seem to be feasible is on derive-generated implementations. Even if the provider of the derive wanted to, they'd have to manually accept an equivalent attribute to doc_cfg, only to pass it on.
Do you want to show the cfg message on both the type and the impl? I'm having trouble understanding the use-case - when would that be necessary?
So you can put #[doc(cfg)] on a module and it will show up on the types within (or at least used to), but only in some cases – again I don't recall exactly what the circumstances were. This helps when you have #[doc(cfg(...))] #[cfg(any(docs, ...)] mod a_ton_of_optional_functionality; and want to avoid having to annotate with #[doc(cfg)] everything within the module, but you ultimately end up having to annotate everything anyway, because propagation is not working quite right.
So you can put #[doc(cfg)] on a module and it will show up on the types within (or at least used to), but only in some cases – again I don't recall exactly what the circumstances were
This is unfortunately not super actionable, but please do open an issue if you can figure out how to replicate it!
I can only speak anecdotally, but I haven't run into any issues with this feature aside from the aforementioned derived traits behind a cfg gate (which shouldn't be a blocker imo).
@jyn514 https://github.com/rust-lang/rust/issues/83428 is the same issue that I was hitting. As I said originally, though:
That said, I don't think it or any other presentation concerns need to block the stabilization of the attribute itself – I don't believe the output of the rustdoc falls under the stability guarantees, so we can always fix that later.
I actually recently saw a case of the doc-cfg hint being rendered on some items when no doc(cfg()) attribute is applied to those items or any of their parents.
The items in question are all of the methods on this type: https://docs.rs/ruma/0.0.3/ruma/serde/struct.Raw.html
The doc(cfg()) attribute being rendered does exist in the ruma crate, but only in one place: https://docs.rs/ruma/0.0.3/src/ruma/lib.rs.html#103
One thing that may be nice would be the ability to provide user-defined text for the "x". I use a number of special features like thread_impl="c11". While these typically don't appear in the public api, having "This is only supported on thread implementation c11" in internal documentation, rather than "This is only supported on thread_impl="c11"" might be nice.
Not necessarily a blocking feature, though. The way I'd imagine this would be an optional second argument that gives a user-defined representation for the cfg key. In the above case, you'd get #[doc(cfg(thread_impl="c11","thread implementation"))] or something similar.
Do you want to show the cfg message on both the type and the impl? I'm having trouble understanding the use-case - when would that be necessary?
I just hit a case where I'd like the cfg message on the derived impl but not the type (the derive attribute itself is applied in a cfg_attr attribute). In particular, it's a no_std library that optionally derives some std-only traits if the "std" feature is enabled. With doc_cfg, all my explicit impls of std-only traits are correctly documented as such; but I can't similarly annotate derived ones.
I can't similarly annotate derived ones.
I don't think this can be fixed on rustdoc's end; rust doesn't allow users to apply attributes to derived traits. We're planning to make doc(cfg) enabled by default for any #[cfg] attribute, would that solve your issue? https://github.com/rust-lang/rust/pull/89596
We're planning to make
doc(cfg)enabled by default for any#[cfg]attribute, would that solve your issue?
It certainly would!