Tracking issue for #[doc(cfg(…))], #[doc(cfg_hide(…))] and doc_auto_cfg

8b9c270
Opened by kennytm at 2025-04-11 07:38:21

This is a tracking issue for the #[doc(cfg(...))] attribute introduced in #43348.

Steps:

(cc #1998)

  1. 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)
    • [x] RFC (rust-lang/rfcs#3631)
    • [ ] Stabilization PR (see instructions on forge): #79263

    (cc #1998)

    jyn at 2021-04-22 13:57:12

  2. #[cfg(rustdoc)] is also gated on this issue but seems distinct (and less risky). Could we FCP that portion in particular?

    Steven Fackler at 2019-01-07 23:05:02

  3. 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.

    Alan Somers at 2019-01-30 17:26:28

  4. 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:


    <img width="940" alt="Screenshot 2019-07-04 at 12 35 06" src="https://user-images.githubusercontent.com/81079/60660487-2b2a1680-9e58-11e9-9b28-163c9814a14e.png">
    <img width="454" alt="Screenshot 2019-07-04 at 12 35 27" src="https://user-images.githubusercontent.com/81079/60660526-3f6e1380-9e58-11e9-89c6-dd93088dd374.png">

    Nemo157 at 2019-07-04 10:42:06

  5. There is also the issue that it repeats every feature on every item in a page:

    <img width="602" alt="Screenshot 2019-07-04 at 14 17 45" src="https://user-images.githubusercontent.com/81079/60666094-7fd48e00-9e66-11e9-9440-f3a5c249e871.png">

    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.

    Nemo157 at 2019-07-04 12:22:37

  6. We tried out this feature in Syn (https://github.com/dtolnay/syn/pull/734) and decided against using it yet.

    <br>

    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.

    <p align="center"><img src="https://user-images.githubusercontent.com/1940490/71430597-cd55e900-269a-11ea-94df-638b8289a0db.png" width="80%"></p>

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

    <p align="center"><img src="https://user-images.githubusercontent.com/1940490/71430661-2c1b6280-269b-11ea-9ec4-5f4071f7fd53.png" width="80%"></p> <br>

    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.

    <p align="center"><img src="https://user-images.githubusercontent.com/1940490/71430398-8c110980-2699-11ea-81eb-457fa0c25e83.png" width="80%"></p>

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

    <p align="center"><img src="https://user-images.githubusercontent.com/1940490/71430401-8fa49080-2699-11ea-95bd-a37397faeae5.png" width="80%"></p>

    David Tolnay at 2019-12-25 03:21:25

  7. The links in the opening post have gone dead.

    Lokathor at 2020-05-06 16:59:28

  8. 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.

    Jacob Pratt at 2020-09-24 06:11:37

  9. For searchability: this is feature doc_cfg.

    Nemo157 at 2020-10-07 21:20:17

  10. 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.

    Nemo157 at 2020-10-07 21:30:41

  11. 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?

    Árni Dagur at 2020-10-07 22:34:34

  12. ...pretty much

    Lokathor at 2020-10-07 22:36:02

  13. 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.

    Nemo157 at 2020-10-08 07:45:26

  14. 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.

    jyn at 2020-10-15 16:29:13

  15. Not sure how hard that would be to implement, though - maybe @petrochenkov would know?

    jyn at 2020-10-15 16:30:01

  16. 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.

    est31 at 2020-11-20 09:24:07

  17. This is mostly looking good for syn. Filed one bug regarding the rendering of doc cfg on impls of empty traits: #79279.

    David Tolnay at 2020-11-21 21:53:00

  18. 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.

    Jacob Pratt at 2020-11-23 08:05:25

  19. Can't we have something like a feature-selector, a ui for selecting which feature to show?

    aobat at 2021-04-02 14:15:58

  20. 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.

    jyn at 2021-04-22 13:48:12

  21. 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.

    Simonas Kazlauskas at 2021-05-07 12:33:53

  22. 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?

    jyn at 2021-05-07 13:21:44

  23. 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.

    Simonas Kazlauskas at 2021-05-07 14:09:44

  24. 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!

    jyn at 2021-05-07 14:25:09

  25. 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).

    Jacob Pratt at 2021-05-07 16:17:42

  26. @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.

    Simonas Kazlauskas at 2021-05-07 16:54:54

  27. 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

    Jonas Platte at 2021-05-07 17:53:48

  28. 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.

    Connor Horman at 2021-08-22 17:00:32

  29. 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.

    eggyal at 2021-10-07 03:55:35

  30. 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

    jyn at 2021-10-07 07:36:42

  31. We're planning to make doc(cfg) enabled by default for any #[cfg] attribute, would that solve your issue?

    It certainly would!

    eggyal at 2021-10-07 08:29:21

  32. Though, because of how #[cfg_attr(foo, derive(Bar))] works that won't be detected by #89596, it might be possible to extend it to do so.

    Nemo157 at 2021-10-07 09:30:27

  33. To summarise on current status:

    Bugs

    • [ ] https://github.com/rust-lang/rust/issues/85043
    • [ ] https://github.com/rust-lang/rust/issues/88743
    • [ ] https://github.com/rust-lang/rust/issues/83428

    UI Improvements

    • [ ] https://github.com/rust-lang/rust/issues/87957
    • [ ] https://github.com/rust-lang/rust/issues/73922

    So, the decision now that needs to be taken is, when do we want to stabilise this? Now? or after the above mentioned bugs have been fixed?

    Pavan Kumar Sunkara at 2021-10-10 12:37:32

  34. #89596 made #[doc(cfg)] implicit when #[feature(doc_cfg)] is enabled. It also added #[doc(cfg_hide(...))]. So by "stabilizing" I guess you should specify which feature(s) to be stabilized:

    • the render #[cfg] as #[doc(cfg)] behavior?
    • the #[doc(cfg)] attribute?
    • the #[doc(cfg_hide)] attribute?

    kennytm at 2021-10-10 15:41:36

  35. I found the following bug:

    #![feature(doc_cfg)]
    
    pub struct A;
    
    #[cfg(feature = "test")]
    impl Clone for A {
        fn clone(&self) -> Self {
            Self {}
        }
    }
    
    #[cfg(feature = "test")]
    mod test {
        use crate::A;
    
        impl Copy for A {}
    
        #[cfg(feature = "test")]
        impl PartialEq for A {
            fn eq(&self, _: &Self) -> bool {
                true
            }
        }
    }
    

    image As you can see, Copy doesn't show a note, but PartialEq does because it is marked explicitly. Is this somehow related to #83428 or should I file a separate bug report?

    daxpedda at 2021-10-14 11:28:12

  36. It's the same thing as #83428, private modules don't properly participate in the tree of cfg that rustdoc sees.

    Nemo157 at 2021-10-14 11:37:47

  37. Currently #[cfg(any(feature = "danger", test))] shows up as: <img width="392" alt="grafik" src="https://user-images.githubusercontent.com/1645124/145498862-dd978a31-3e11-4429-abc4-2c82094ae608.png">

    I know doc_cfg allows to overwrite, but whats the purpose of showing the test tag in documentation? Is there already an opinion on this matter that I missed?

    daxpedda at 2021-12-10 00:57:02

  38. Seems like that should be excluded by default.

    Jacob Pratt at 2021-12-10 00:58:52

  39. Happy to take a PR for that :) look in src/librustdoc for where it checks whether cfg_hide is active and add test to the default set.

    jyn at 2021-12-10 02:09:14

  40. I looked into it, it seems to me that it's a bit more complicated. cfg_hide only filters out exact matches, so filtering test won't filter test out of any(feature = "x", test).

    daxpedda at 2021-12-10 09:09:24

  41. After contemplating a couple of solutions, I was wondering if we shouldn't fix this behavior on a different level. Currently #![doc(cfg_hide(feature = "x"))] won't hide x in #[cfg(any(feature = "x", feature = "y"))] or #[cfg(all(feature = "x", feature = "y"))]. cfg_hide only works on exact matches, does that make sense?

    The most straightforward way to me to implement this is to transform Attributes after parsing them, removing anything that should be hidden. This can include test of course. But if we don't want to change cfg_hide, we could also do this for test only.

    Any guidance would be appreciated.

    daxpedda at 2021-12-10 09:55:51

  42. @daxpedda since it looks nontrivial, could you open a separate issue to discuss it on?

    Nemo157 at 2021-12-10 10:22:12

  43. #89596 made #[doc(cfg)] implicit when #[feature(doc_cfg)] is enabled.

    I'm confused. I thought that it worked before, but now it somehow doesn't? Was this behaviour reversed?

    // lib.rs
    #![feature(doc_cfg)]
    
    #[cfg(feature = "a")]
    pub struct What;
    
    # Cargo.toml
    [package]
    name = "rustdoc_no_doccfg"
    version = "0.1.0"
    edition = "2021"
    
    # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
    
    [dependencies]
    
    [features]
    a = []
    
    ; cargo +nightly doc --all-features --open
    

    screenshot of rustdoc output showing that feature is not shown another screenshot of rustdoc output showing that feature is not shown

    ; cargo +nightly --version
    cargo 1.59.0-nightly (fcef61230 2021-12-17)
    ; rustdoc +nightly --version
    rustdoc 1.59.0-nightly (cfa3fe5af 2021-12-31)
    

    (adding #[doc(cfg(...))] fixes this, but it seemed like it's not required anymore)

    waffle at 2022-01-02 00:02:20

  44. Ah, so since #90502 the implication of #[doc(cfg(...))] by #[cfg(...)] needs a different feature, doc_auto_cfg. It's weird that this wasn't mentioned in this tracked issue at all.

    waffle at 2022-01-02 00:08:04

  45. https://github.com/rust-lang/rust/pull/90502 split that feature out into a separate doc_auto_cfg feature, which is as of yet undocumented (I opened https://github.com/rust-lang/rust/issues/92484 for that).

    Nemo157 at 2022-01-02 00:11:19

  46. This feature currently doesn't document feature gated function arguments:

    fn frobnify(#[cfg(feature = "bar")] _bar: ()) {}
    

    Tim Vilgot Mikael Fredenberg at 2022-01-24 08:13:57

  47. Whats blocking stabilization here? It seems like the feature is complete, and people are using it. If there's tweaks to how documentation is rendered, surely that could happen after stabilization? Devs can already opt out of this for their crates by not adding #[doc(...)] attributes in their code.

    Are we just waiting on a write-up being merged into the core rust documentation?

    I use stable rust, and I find issues like this very frustrating - where there's functionally complete, working compiler features sitting for years behind a flag thats unavailable in stable because ??. It makes stable feel like rust's forgotten stepchild, rather than the main & recommended version of the compiler.

    Seph Gentle at 2022-03-15 03:39:36

  48. I agree with @josephg, this functionality feels relatively mature and is used all over the place on docs.rs. At this point doing any kind of backwards-incompatible change would break a ton of crate documentation on docs.rs so it feels almost de-facto stable. And since this is still unstable, locally-built documentation feels incomplete, to the extent that I end up running RUSTDOCFLAGS='--cfg docsrs' cargo +nightly doc to build local documentation just for #[doc(cfg(…))].

    Lily Ballard at 2022-04-16 00:06:22

  49. Perhaps this raises a wider issue re stabilisation: if docs.rs runs on nightly/applies unstable features, then those features are at risk of becoming "de facto stabilised". Perhaps this was already (or should be) raised/discussed elsewhere, but it seems that perhaps this is a Bad Thing.

    eggyal at 2022-04-16 07:37:41

  50. docs.rs generates documentation once and stores it as is. If it looks good at the time of generation, it will remain that way indefinitely. While changing the way this functionality works today would affect the documentation output if a new version of the crate was published after such a change, it is also pretty clear cut that the crate opts into nightly functionality knowingly by asking docs.rs to use an unstable feature with the specific version of the Rust that docs.rs happens to be using at the time.

    I don't see the risk as significant here. With that context I'm also opposed to freezing the current functionality or rushing the stabilization in case we have in mind any improvements we'd like to make.


    Are we just waiting on a write-up being merged into the core rust documentation? I use stable rust, and I find issues like this very frustrating...

    A great way to have this particular itch scratched is to contribute some work towards scratching it. One thing that's missing for the stabilization is a stabilization report which could among other things give an objective overview of the known issues and why they don't block the stabilization of this feature. It should be posted as a comment on this issue.

    Simonas Kazlauskas at 2022-04-16 19:56:34

  51. https://github.com/rust-lang/rust/pull/89596 was merged a while ago. Is there anything else remaining to be done in here? Otherwise I can open a stabilization PR like https://github.com/rust-lang/rust/pull/79263.

    Guillaume Gomez at 2022-05-23 14:14:54

  52. I'm not aware of any blockers. I have been using this for many months without issue, as have many other large crates.

    Jacob Pratt at 2022-05-23 14:30:01

  53. Same on my side but I was thinking that maybe I was missing something.

    Do you think we can stabilize it @rust-lang/rustdoc ?

    Guillaume Gomez at 2022-05-23 14:35:59

  54. I'm wondering about this and here. Screenshot_20220523_173414

    It's a bit ambiguous what and entails. It can be interpreted by users that enabling either of the two features is enough for getting that function.

    Maybe "Requires crate features http and cache" would make it clearer?

    est31 at 2022-05-23 15:44:10

  55. Requires windows seems a bit weird but I'm fine with it.

    Guillaume Gomez at 2022-05-23 15:48:12

  56. Stabilization of this would be a massive quality of life improvement.

    Naja Melan at 2022-05-23 15:59:56

  57. For clarity, the stabilization is regarding the attribute itself. How it's displayed, like everything else in docs, can change to be improved. So wording isn't a blocker.

    Jacob Pratt at 2022-05-23 17:14:16

  58. Is the plan to only stabilize doc(cfg), or all three features? If the latter, feature(doc_auto_cfg) probably needs to have an explicit opt-in like #![doc(auto_cfg)] added so that we don't start just showing cfgs on crates that aren't prepared for it (and maybe a plan to make that default active in a future edition); and some usage reports for cfg_hide would be nice.

    Nemo157 at 2022-05-23 18:51:02

  59. Only doc(cfg) iiuc.

    Guillaume Gomez at 2022-05-23 19:55:25

  60. However I think most people in here are very likely talking about doc_auto_cfg. Might be better to clarify beforehand.

    Guillaume Gomez at 2022-05-23 19:56:38

  61. Does cfg_hide currently not support hide not() feature?

    #[cfg(any(all(windows, feature = "winapi"), all(doc, not(doctest))))]
    pub use win_debug_sink::*;
    

    I need not(doctest) here because without it cargo test will run doctests in the win_debug_sink mod on a platform other than Windows.

    In the head of my lib.rs:

    #![cfg_attr(
        all(doc, CHANNEL_NIGHTLY), // `CHANNEL_NIGHTLY` is passed by `build.rs`
        feature(doc_auto_cfg, doc_cfg_hide),
        doc(cfg_hide(doc))
    )]
    

    It generates badge: Available on Windows and crate feature winapi, or non-doctest only.

    It's good that the doc is properly hidden. But if I add a doc(cfg_hide(doctest)), the badge just disappeared, instead if I add a doc(cfg_hide(not(doctest))), the badge is back, but it doesn't seem to be doing anything.


    Or consider another solution, maybe we should remove doc and doctest in the same way as we did in issue #91740?


    BTW, the implementation in #91740 also only removes test but not not(test), the latter makes the badge disappear. Looks like a bug.

    MRE:

    #![feature(doc_auto_cfg)]
    
    // #[cfg(any(doc, test))] // OK
    #[cfg(any(doc, not(test)))] // badge disappear
    pub fn foo() {}
    

    Asuna at 2022-06-13 18:10:19

  62. Please open a separate issue and link to this one so it can be fixed.

    Guillaume Gomez at 2022-06-13 18:21:37

  63. Is the way with defining a doc_auto_cfg feature still supported currently? And in the future?

    Stefan Schindler at 2022-06-13 21:52:05

  64. What do you mean? If we will keep supporting #[doc(cfg(...))]? If so yes, the syntax will be kept.

    Guillaume Gomez at 2022-06-13 21:54:52

  65. There used to be a feature the the docs.rs renderer enabled, like play.rust-lang.org, so as a crate author I could enable specific features for the respective builds.

    Also, I found this example that could solve the same problem: https://github.com/rust-lang/docs.rs/blob/369e1bb0ed5f0b4c14f6ecaa01013094c7d234dd/templates/core/Cargo.toml.example

    [package.metadata.docs.rs]
    
    # Features to pass to Cargo (default: [])
    features = ["feature1", "feature2"]
    
    # Whether to pass `--all-features` to Cargo (default: false)
    all-features = true
    

    Stefan Schindler at 2022-06-13 22:00:02

  66. I am very lost. This is not linked to that (at least not directly). doc(cfg(...)) is used to show the cfgs independently or the current cfg.

    Guillaume Gomez at 2022-06-13 22:01:47

  67. Could we get a small warning triangle or a similar marker with hover at declaration site? Consider this example:

    Screenshot 2022-12-06 at 13-57-54 Foo in foo - Rust

    The conditionality is not immediately visible, the user has to scroll down. For small enums this is OK but large enums that have each variant extensively documented are a problem. If one doesn't scroll down to check if it requires a feature it could result in annoying "why it says it doesn't exist?" confusion.

    Martin Habovštiak at 2022-12-06 13:15:36

  68. Adding a small warning sign beside the variant (and nothing else) could be enough I suppose. We still need to write an RFC for all this feature though.

    Guillaume Gomez at 2022-12-06 13:17:43

  69. Is anyone already working on creating an RFC?

    Thayne McCombs at 2022-12-06 19:47:06

  70. Not that I know. I have it in my TODO list.

    Guillaume Gomez at 2022-12-06 19:48:57

  71. As a reminder, this is a tracking issue for stabilizing doc_cfg. Bug reports should go in separate issues to avoid pinging the 30+ people watching this issue, unless you think the bug is so severe it should block stabilization. Suggestions for enhancements should also go in separate issues.


    As far as I can tell, the current status is that the stabilization PR (https://github.com/rust-lang/rust/pull/100883) is blocked on deciding whether doc_auto_cfg should be on by default or not (and whether we should let crate authors control whether it's on or just force it on). The discussion for that is in https://rust-lang.zulipchat.com/#narrow/stream/266220-rustdoc/topic/Discussion.20about.20.60doc_cfg*.60.20features.20stabilization/.

    jyn at 2022-12-16 22:42:34

  72. Thanks for the sum up. We actually decided to go through an RFC that started to be written because too many elements need to be discussed. More information in the next weeks.

    Guillaume Gomez at 2022-12-17 06:52:52

  73. Since I see an RFC is being written, I take the opportunity to share my case, since I wanted to use doc_cfg to show that a particular function is only available on the absence of a feature. But it seems that's not currently possible.

    This does result in: "Available on feature safe only".

    #[cfg(feature = "safe")]
    #[doc(cfg(feature = "safe"))]
    pub fn safe_fn() {}
    

    But this results in: "Available on non-crate feature safe only". Instead of the expected: "Not available on feature safe".

    #[cfg(not(feature = "safe"))]
    #[doc(cfg(not(feature = "safe")))]
    pub fn unsafe_fn() {}
    

    I wonder if this is by design.

    José Luis Cruz at 2023-02-19 19:17:17

  74. I wonder if this is by design.

    Somewhat, yes. Cargo itself doesn't support negative features, so no effort was put into making them render well.

    Nemo157 at 2023-02-19 21:43:37

  75. Should the original post link to #100883 instead?

    Nic Hartley at 2023-03-25 01:21:46

  76. I'm running into a rather annoying problem with documenting features.

    I am writing currently a serde crate with multiple specifications for a specific format. I have a binary module that is documented with the following doc_cfg: any(feature = "be", feature = "le", feature = "varint"). Now, if I document one of the functions as present with just the be feature and inline their re-export I get this annoying display:

    image

    Of course, I tried with doc_cfg_hide, wrestling with the minimal documentation, but nothing seems to work for this. I can not inline the re-exports, but purposefully sacrificing usability is presumably a bug or at least something worth mentioning here. When I don't inline it, it looks like so:

    image

    My one gripe with the first selection is that even the order it's appended to is non-uniform, which bothers me, but that's not the core issue here.

    Is there some hack I'm unaware of besides not inlining items in documentation? I haven't seen this case discussed so far. Even if I simplified it to an internal feature (binary) it still displays, even if assumed to be enabled in context; either way, extraneous information is applied, and I have no say in omitting it.

    Sean C. Roach at 2023-04-16 02:08:28

  77. #[doc(no_inline)]

    Guillaume Gomez at 2023-04-16 08:55:15

  78. I believe #[doc(no_inline)] (as described here) is specifically the behavior I'm trying to avoid. As you can see, binary is a public module.

    image

    I understand this is stylistic, but every serde_* crate uses #[doc(inline)] on their re-exported functions. This is the behavior I want.

    The behavior I don't want is my inability to omit the automatically appended features. It introduces a ton of noise. Even if I make some "internal" feature named binary, it still adds itself (non-uniformly in terms of order) to the re-exported functions. I've made this an issue here because it seems like not too rare of a use-case that makes documenting features so noisy that it becomes unhelpful at-a-glance.

    In summary, I can either not inline my re-exports, or deal with unhelpful documented features; it seems like a bug that I can't simply do both, even if it means manually overriding the item at its declaration to say exactly what I want to document.

    Sean C. Roach at 2023-04-16 19:02:06

  79. It should certainly be possible to simplify be and std and (be or le or varint) to be and std, IIRC there are already some simplifications applied to the cfgs so this would just require extending those. It'd be good to open a separate issue with a small testcase.

    Nemo157 at 2023-05-03 15:34:41

  80. @Nemo157 see #104991

    est31 at 2023-05-03 16:20:11

  81. We'll need https://github.com/rust-lang/rust/issues/103300 to be fixed beforehand as well.

    Guillaume Gomez at 2023-11-09 12:41:46

  82. I noticed in https://github.com/gfx-rs/wgpu/pull/4935#discussion_r1436658697 that it would be very nice if we could add custom names to cfgs. This is currently done by Rustdoc for known cfgs here: https://github.com/rust-lang/rust/blob/2b1365b34f0d5ee43944c4266a625923a7b312dd/src/librustdoc/clean/cfg.rs#L488-L590

    Maybe something like doc(cfg_rename(foo = "Foo"))?

    daxpedda at 2024-01-12 10:55:46

  83. I just found this doesn't appear to support version(..) cfg. I currently workaround the lack of version predicate by having a build script detect the rustc version and output a cfg. I thought adding #[cfg_attr(docsrs, doc(cfg(any(feature = "std", version("1.77.0")))))] would cause it to render properly but it just fails to build with "invalid predicate" message. I tried adding #![feature(cfg_version)] without any luck.

    Martin Habovštiak at 2024-07-03 12:55:06

  84. version(...) is an internal rustc attribute, so it's not supposed to be used outside of std.

    Guillaume Gomez at 2024-07-03 13:24:55

  85. It isn't, see #64796

    Martin Habovštiak at 2024-07-03 13:34:44

  86. This issue is 5 years old and doesn't seem to have been updated much since then. And the only place where the attribute is used is in std libs. However it can be used with a nightly rustc:

    #[cfg(version = "1.70.0")]
    fn foo() {}
    
    fn main() {}
    

    gives:

    error[E0658]: `cfg(version)` is experimental and subject to change
     --> src/main.rs:1:7
      |
    1 | #[cfg(version = "1.70.0")]
      |       ^^^^^^^^^^^^^^^^^^
      |
      = note: see issue #64796 <https://github.com/rust-lang/rust/issues/64796> for more information
    
    For more information about this error, try `rustc --explain E0658`.
    

    But in any case, until there is a clear position on whether or not this attribute should be rustc internal only or not, I don't think there is anything to be done.

    Guillaume Gomez at 2024-07-03 13:44:25

  87. The issue I linked is literally a tracking issue for an accepted RFC. It's not internal, it's supposed to be usable in nightly with syntax version("1.77.0"), not version = "1.77.0". It should be processed by rustdoc correctly to give us a view how things might look once both features are stable.

    Martin Habovštiak at 2024-07-03 14:22:32

  88. @GuillaumeGomez frankly I have no idea what you're thinking of, but you're unquestionably confusing two different features.

    Jacob Pratt at 2024-07-03 15:07:44

  89. Likely yes...

    Guillaume Gomez at 2024-07-03 15:08:50

  90. Just poking around: it appears that the doc_auto_cfg feature links here, but there's no docs in the unstable book for it and the feature doesn't seem to match what's proposed in the RFC. Is this just not implemented, or is the syntax different and this just isn't documented?

    Clar Fon at 2024-08-31 19:41:29

  91. The RFC (which is still under discussion so maybe not its final form) proposes something slightly different than what's currently implemented and adds more attributes to give more control.

    Currently, to enable this feature, you use #![doc(auto_cfg)] and that's it.

    Guillaume Gomez at 2024-08-31 19:43:55

  92. Two years ago on https://github.com/rust-lang/rust/pull/100883 I asked about the possibility of stabilizing #[doc(cfg(...)) without #[doc(auto_cfg)] on the principle that the former seems to be well-understood, while the latter is a more complex feature that has ongoing discussion about how exactly it should work.

    At the time, the response was that stabilizing #[doc(cfg(...))] by itself wouldn't provide a good user experience, and that there would potentially be ecosystem churn from people adding it all over and then removing it once #[doc(auto_cfg)] was ready.

    But ... it's been two years, and neither is stabilized. I could have been using #[doc(cfg(...)] all this time. It's pretty frustrating to have a ready-to-stabilize feature I want be blocked on a vaguely-related feature that I don't particularly care about.

    Can #[doc(cfg(...))] please be stabilized? Feel free to put some verbiage in the release notes like "if you're planning to use #[doc(auto_cfg)] in the future then please hold on until that arrives" if there's still a concern about ecosystem churn.

    John Millikin at 2024-10-16 13:39:48

  93. @jmillikin This needs an RFC to be stabilized. That's currently awaiting FCP (it needs 3 more checkboxes): https://github.com/rust-lang/rfcs/pull/3631#issuecomment-2208528823

    Jacob Pratt at 2024-10-17 04:55:23

  94. I understand why #[doc(auto_cfg)] needs an RFC.

    Why would #[doc(cfg(...))] need an RFC?

    John Millikin at 2024-10-17 05:11:07

  95. It's a new, non-trivial language feature. They don't get added on a whim; there's a process to follow.

    Jacob Pratt at 2024-10-17 05:32:33

  96. While it feels like one feature may be easier to stabilise, I can't imagine that filing a shorter RFC just for doc(cfg(...)) will go any faster. Plus, once the RFC for both features is added, I think it would be reasonable to stabilise just that feature since it doesn't really need any more work done.

    So, I get the impatience, just, this is pretty much all volunteer work, so, it's gonna take a while for folks to set aside the time to review everything and sign off on it.

    Clar Fon at 2024-10-17 18:43:32

  97. For reference, writing the following at the top of lib.rs will make feature-gated stuff documented properly on docs.rs, while still having your program compiling in stable rust:

    #![cfg_attr(docsrs, feature(doc_auto_cfg))]
    

    Tim (Theemathas) Chirananthavat at 2024-10-25 09:08:44

  98. #[cfg_attr(docsrs), ...] doesn't help for people who are trying to run rustdoc as part of their build and/or CI process, so it would be nice to get support for at least #[doc(cfg(...))] stabilized.

    John Millikin at 2024-10-25 10:55:24

  99. It's all or nothing. RFC is open and waiting for reviews. Sadly there is nothing more we can do about it.

    The cfg_attr trick also works with features. Nothing prevents you do to run your CI in nightly. It's not the best but until the RFC is merged and the feature implemented (this part should be pretty quick), nothing else can be done.

    Guillaume Gomez at 2024-10-25 11:12:58

  100. I'm sorry, this may be a really dumb question, but why is it "all or nothing"?

    I don't understand why #[doc(cfg(...))] can't be stabilized as an MVP, independent of #[doc(auto_cfg)]. They're both already implemented, and from the perspective of writing a stabilization report and/or updating the reference the former feature seems a lot easier to document (since it's entirely explicit annotations by the author).

    John Millikin at 2024-10-25 11:39:41

  101. Theoretically it could be done separately, but it wouldn't be done any faster (which seems to be what you truly want). There is nothing that can be done to speed up stabilization (at least that's within the code of conduct).

    Jacob Pratt at 2024-10-25 11:44:35

  102. Theoretically it could be done separately, but it wouldn't be done any faster (which seems to be what you truly want). There is nothing that can be done to speed up stabilization (at least that's within the code of conduct).

    I've frequently seen subsets of a complex feature stabilize separately, most famously the various parts of async stabilizing as the design was iterated on. I've also seen existing RFCs get split up into an MVP and a follow-on with more complexity but better ergonomics.

    It could be that there's some aspect of how #[doc(cfg(...))] and #[doc(auto_cfg)] interact that I'm missing due to lack of rustc internals knowledge, but from an outside perspective it's not obvious why #[doc(cfg(....))] couldn't be split off and stabilized by itself (e.g. in 1.85 or 1.86), and then #[doc(auto_cfg))] can stabilize on its own timeframe (presumably >= 1.90).

    John Millikin at 2024-10-25 11:51:18

  103. Note that when features are split up it's generally because there are concerns, unresolved questions, or simply too much work to do all at once. None of that applies here. The only blocker (pending concerns being raised) is checkboxes.

    Jacob Pratt at 2024-10-25 11:54:33

  104. In addition to what @jhpratt said: because it would need to go through an RFC, which means asking people to write another RFC and yet other people to review it. We have limited bandwidth and most contributors are not paid to do so and we're also facing a huge burn-out issue across the project as well so it wouldn't help in this regard either.

    Guillaume Gomez at 2024-10-25 11:55:28

  105. I've pinged the people that the FCP is waiting for (no flak intended towards any of these wonderful people), hopefully that can speed up the progress a little bit.

    Mads Marquart at 2024-10-25 12:06:51

    1. Please don't.
    2. Likely not.

    Guillaume Gomez at 2024-10-25 12:08:22

  106. Apologies then.

    Mads Marquart at 2024-10-25 12:48:04

  107. #[cfg_attr(docsrs), ...] doesn't help for people who are trying to run rustdoc as part of their build and/or CI process

    @jmillikin This is the solution I have been using.

    Cargo.toml

    [package.metadata.docs.rs]
    all-features = true
    
    [build-dependencies]
    rustc_version = "0.4.1"
    

    build.rs

    use rustc_version::{version_meta, Channel};
    
    fn main() {
        // Set cfg flags depending on release channel
        let channel = match version_meta().unwrap().channel {
            Channel::Stable => "CHANNEL_STABLE",
            Channel::Beta => "CHANNEL_BETA",
            Channel::Nightly => "CHANNEL_NIGHTLY",
            Channel::Dev => "CHANNEL_DEV",
        };
        println!("cargo:rustc-cfg={}", channel)
    }
    

    lib.rs

    #![cfg_attr(all(doc, CHANNEL_NIGHTLY), feature(doc_auto_cfg))]
    

    Then run nightly in your CI script, doc_auto_cfg will only be enabled when using nightly toolchain. So this works very well with CI and docs.rs and doesn't affect library users.

    Asuna at 2024-10-25 20:31:41

  108. The way I have it set up:

    Cargo.toml:

    [package.metadata.docs.rs]
    all-features = true
    rustdoc-args = ["--cfg", "docsrs"]
    

    lib.rs:

    #![cfg_attr(docsrs, feature(doc_cfg, doc_auto_cfg))]
    

    CI (mimicking docs.rs settings), with the nightly toolchain:

    env RUSTDOCFLAGS='--cfg docsrs -D warnings' cargo doc --all-features
    

    @jmillikin, does that not solve your problem?

    Bogdan Opanchuk at 2024-10-25 20:54:52

  109. I noticed today that feature flags on derived traits don't get annotated and there's no obvious way to add an annotation

    e.g.:

    #![feature(doc_auto_cfg)]
    #![feature(doc_cfg)]
    
    use std::fmt;
    
    // this doesn't display the feature flag
    #[cfg_attr(unix, derive(Debug))]
    pub struct Foo;
    
    // this works
    #[cfg(unix)]
    // #[doc(cfg(unix))] // if not using auto_cfg
    impl fmt::Display for Foo {
        fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
            write!(f, "Foo")
        }
    }
    

    rendered with cargo-docs-rs: Image

    Is there a way that this should be able to work, or is it a known missing part of this? If the latter, I'd note that it's likely not a blocking one IMO, but a nice to have.

    Josh McKinney at 2024-11-29 00:00:38

  110. I'm not sure how that even could work theoretically, given that #[cfg_attr] is evaluated first.

    Jacob Pratt at 2024-11-29 00:21:56

  111. Perhaps something like the following?:

    #[cfg_attr(unix, derive(Debug))]
    #[doc(cfg_impl(unix, Debug))]
    struct Foo;
    

    What is it about the code generated by the compiler derive attribute that makes it not able to be annotated the same way a manual impl might be?

    Josh McKinney at 2024-11-29 01:01:14

  112. As another method to what @joshka said, one could introduce a #[doc(cfg_attr(...))] attribute and make cfg_attr expand to it in addition to #[derive(Debug)]. It would be ignored by rustdoc, as making sense of it should be job of the derive macros: one would need to add support to all the derive macros to recognize that #[doc(cfg_attr(...))] attribute and transform it to a #[doc(cfg(...))] on the impl block.

    The advantage would be that it's automatic compared to cfg_impl, but it would need derive authors to opt into this.

    If you don't do such a transformation, like in @joshka 's proposal, rustdoc would need some way to find the right impl block (thanks to generics there can be multiple). Eg it could put the note on all impl blocks that come from expansions (Span::from_expansion).

    There is also the whole question of what to do in the case the cfg evaluates to false and the derive macro does not run. You can't just create a fake impl Debug for Foo, as you need to get the generic params right: it could just as well be a impl<T: Debug + SomeTraitFromFooTypeDecl> for Foo<T>. Probably the impl block would just not be shown in that case.

    est31 at 2024-11-29 01:14:05

  113. I thought about this some more...it may be possible if the attribute is stored along with an annotation as to how it was enabled (if not by nature of not needing to be). This is already done to an extent as far as I'm aware, as diagnostics knows about cfged out items.

    Jacob Pratt at 2024-11-29 01:15:26

  114. To be clear, my cfg_impl proposal was not a fully formed / thought out one. It was very off the cuff and I expect there's likely many downsides to be explored before jumping on that idea. My knowledge of the implementation necessary for this is fairly limited.

    Josh McKinney at 2024-11-29 01:42:45

  115. It's supposed to work. It's a known issue: https://github.com/rust-lang/rust/issues/103300

    The problem is rustc doesn't provide information when expanding items under cfg_attr. The best way here would be to add the corresponding cfg attribute on each generated item.

    Guillaume Gomez at 2024-11-29 11:26:20

  116. For those only subscribed to the tracking issue, the RFC is currently in FCP: https://github.com/rust-lang/rfcs/pull/3631#issuecomment-2701673067

    Jacob Pratt at 2025-03-12 02:41:46

  117. when this is stabilized, the feature flag should be ignored, as many packages have #![cfg_attr(docsrs, feature(doc_auto_cfg))], and removing this feature all together would mean that docs.rs's continuous rebuilds would break for packages until they added a new release that removed the cfg_attr line.

    lolbinarycat at 2025-04-10 22:40:11

  118. @lolbinarycat docs.rs is building using a nightly compiler, so it won't cause E0554. Use of stabilized feature will only emit a stable_features lint e.g.

    warning: the feature `if_while_or_patterns` has been stable since 1.33.0 and no longer requires an attribute to enable
     --> src/main.rs:1:28
      |
    1 | #![feature(range_is_empty, if_while_or_patterns)]
      |                            ^^^^^^^^^^^^^^^^^^^^
      |
      = note: `#[warn(stable_features)]` on by default
    
    warning: the feature `range_is_empty` has been stable since 1.47.0 and no longer requires an attribute to enable
     --> src/main.rs:1:12
      |
    1 | #![feature(range_is_empty, if_while_or_patterns)]
      |            ^^^^^^^^^^^^^^
    

    I don't see how the existing practice is going to break any packages.

    kennytm at 2025-04-11 05:32:33

  119. ah, alright, i wasn't sure what happens to stabilized features. i suppose its only removed features that have their identifiers removed without a trace.

    maybe it could break some crates that have deny(warnings), but that could be worked around by making docs.rs use --cap-lints.

    lolbinarycat at 2025-04-11 05:44:33

  120. it is already using --cap-lints warn 5 years ago (rust-lang/docs.rs#659)

    kennytm at 2025-04-11 06:55:04

  121. looks like everythings already been thought of, then.

    lolbinarycat at 2025-04-11 07:38:21