Skip to content
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

rustdoc: doc_cfg hints not shown on reexports from private modules #83428

Closed
MarijnS95 opened this issue Mar 23, 2021 · 6 comments · Fixed by #101006
Closed

rustdoc: doc_cfg hints not shown on reexports from private modules #83428

MarijnS95 opened this issue Mar 23, 2021 · 6 comments · Fixed by #101006
Labels
C-bug Category: This is a bug. F-doc_cfg `#![feature(doc_cfg)]` T-rustdoc Relevant to the rustdoc team, which will review and decide on the PR/issue.

Comments

@MarijnS95
Copy link
Contributor

From gtk-rs/gir#1079

Given the following Rust code with in-line annotations of the expected behaviour:

#![feature(doc_cfg)]

#[doc(cfg(feature = "foobar"))]
pub mod imp_pub {
    /// Feature on `struct` in public module shows, despite no `doc_cfg` directly on the `struct`
    pub struct BarPub {}
}
// This only shows Re-exports, but doesn't place the type in the top-level module
#[doc(cfg(feature = "foobar"))]
pub use crate::imp_pub::*;

#[doc(cfg(feature = "foobar"))]
mod imp_priv {
    /// Feature on `struct` in private module is never shown
    pub struct BarPriv {}
    impl BarPriv {
        /// Oddly enough the feature guard _is_ shown here
        pub fn test() {}
    }
}
#[doc(cfg(feature = "foobar"))]
pub use crate::imp_priv::*;

#[doc(cfg(feature = "foobar"))]
mod imp_priv_2 {
    /// In a private module `doc_cfg` has to be placed directly on the `struct`
    #[doc(cfg(feature = "foobar"))]
    pub struct Bar {}
    impl Bar {
        /// The explicit feature guard is hidden here because it is _implied_ from the surrounding [`Bar`] type
        #[doc(cfg(feature = "foobar"))]
        pub fn test() {}
    }
}
#[doc(cfg(feature = "foobar"))]
pub use crate::imp_priv_2::*;

On:

me:gtk-rs/ $ rustc +nightly -Vv
rustc 1.53.0-nightly (5d04957a4 2021-03-22)
binary: rustc
commit-hash: 5d04957a4b4714f71d38326fc96a0b0ef6dc5800
commit-date: 2021-03-22
host: x86_64-unknown-linux-gnu
release: 1.53.0-nightly
LLVM version: 12.0.0

The issue

rustdoc does not seem to be able to generate feature requirement labels on types in private modules (mod imp_priv) that are publicly reexported (pub use crate::imp_priv::*;). The labels do not show up on the module overview nor struct page, but do propagate into items like functions for the given type.

Observed

This renders the BarPriv type without any feature requirement, neither in the module overview:

image

Nor on the struct page:

image

Note that the label is propagated onto pub fn test() {} (does not have an explicit #[doc(cfg())]), rustdoc at least understood that!

Expected output

It is supposed to render the feature requirement for foobar like Bar, both in the module overview above as on the struct page:

image

Bonus

It seems tricky to combine feature requirements on the mod and pub use reexport. In the case above they are the same, but what if:

#[doc(cfg(feature = "foo"))]
mod priv;
#[doc(cfg(feature = "bar"))]
pub use priv::*;

The type is only publicly available when foo and bar are specified. Specifying foo is fine but makes the contents of priv unreachable through the current module, specifying only bar should result in a "module priv not found" error.

CC @GuillaumeGomez

@jonas-schievink jonas-schievink added C-bug Category: This is a bug. T-rustdoc Relevant to the rustdoc team, which will review and decide on the PR/issue. labels Mar 23, 2021
@jyn514 jyn514 added the F-doc_cfg `#![feature(doc_cfg)]` label Mar 24, 2021
@jplatte
Copy link
Contributor

jplatte commented Apr 6, 2021

This also affects re-exports of entire crates. Unfortunately there the fix is not clear at all, since the "parent" crate is obviously not guaranteed to have the same features as the crate being re-exported.

@MarijnS95
Copy link
Contributor Author

@jplatte Within the same crate as well; it's not about the features that are enabled (though it is relevant which are available) but about the combined #[cfg] restrictions that are placed on the definition and reexport. Simplest I can think of is a union of all features (but gets complicated quick when inversions and all vs any is used) and later perhaps simplifying based on feature relations (if a implies b there is no need to display b as requirement, if either definition or reexport requires a).

That's necessary to cleanly solve crate reexports, since you effectively want to ensure that the top-level crate feature a implies feature <reexported-crate>/b and hide it. If the whole resolver is made smart enough (perhaps this already exists, I'm not too familiar with Cargo) it could even throw warnings when there exist feature combinations that would lead to a compiler error (ie. explicitly reexporting a symbol that is not available for a certain set of features).

@Nemo157
Copy link
Member

Nemo157 commented Oct 14, 2021

I wonder if this is just an ordering issue of the passes:

STRIP_PRIVATE,
STRIP_PRIV_IMPORTS,
PROPAGATE_DOC_CFG,

The private modules have disappeared by the point where we pass all the doc(cfg) data down so we don't see them.

@MarijnS95
Copy link
Contributor Author

@Nemo157 Thanks for the suggestion - I moved PROPAGATE_DOC_CFG before STRIP_PRIVATE and STRIP_PRIV_IMPORTS (I've never built rustc/rustdoc from source, pleasantly surprised that ./x.py b only took just under 7min on a ThreadRipper 🥳) but it doesn't change anything to the generated output unfortunately :(

@Kixunil
Copy link
Contributor

Kixunil commented Nov 11, 2021

I observe this on public items as well:

pub mod foo {
    #![doc(cfg(feature = "foo"))]
    pub struct Foo;
}

#[doc(cfg(feature = "foo"))]
pub use foo::Foo;

Does not show the badge at re-exports.

@GuillaumeGomez
Copy link
Member

So from the following code:

#[doc(cfg(feature = "foobar"))]
mod imp_priv {
    /// Feature on `struct` in private module is never shown
    pub struct BarPriv {}
    impl BarPriv {
        /// Oddly enough the feature guard _is_ shown here
        pub fn test() {}
    }
}
#[doc(cfg(feature = "foobar"))]
pub use crate::imp_priv::*;

BarPriv is stripped and then inlined. The stripped version contains all the correct cfg information but the inlined one doesn't. Checking what's the best course here: either cloning the stripped item or propagating when inlining.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
C-bug Category: This is a bug. F-doc_cfg `#![feature(doc_cfg)]` T-rustdoc Relevant to the rustdoc team, which will review and decide on the PR/issue.
Projects
None yet
Development

Successfully merging a pull request may close this issue.

8 participants