Code change:
use std::sync::Arc; use crate::clean::cfg::Cfg; <ins> use crate::clean::inline::{load_attrs, merge_attrs}; </ins> use crate::clean::{Crate, Item}; use crate::core::DocContext; use crate::fold::DocFolder; use crate::passes::Pass; <ins> use rustc_hir::def_id::LocalDefId; </ins> pub(crate) const PROPAGATE_DOC_CFG: Pass = Pass { name: "propagate-doc-cfg", run: propagate_doc_cfg, description: "propagates `#[doc(cfg(...))]` to child items", }; <del> pub(crate) fn propagate_doc_cfg(cr: Crate, _: &mut DocContext<'_>) -> Crate { CfgPropagator { parent_cfg: None }.fold_crate(cr) </del> <ins> pub(crate) fn propagate_doc_cfg(cr: Crate, cx: &mut DocContext<'_>) -> Crate { CfgPropagator { parent_cfg: None, parent: None, cx }.fold_crate(cr) </ins> } <del> struct CfgPropagator { </del> <ins> struct CfgPropagator<'a, 'tcx> { </ins> parent_cfg: Option<Arc<Cfg>>, <ins> parent: Option<LocalDefId>, cx: &'a mut DocContext<'tcx>, </ins> } <del> impl DocFolder for CfgPropagator { </del> <ins> impl<'a, 'tcx> DocFolder for CfgPropagator<'a, 'tcx> { </ins> fn fold_item(&mut self, mut item: Item) -> Option<Item> { let old_parent_cfg = self.parent_cfg.clone(); <ins> if item.kind.is_non_assoc() && let Some(def_id) = item.item_id.as_def_id().and_then(|def_id| def_id.as_local()) { let hir = self.cx.tcx.hir(); let hir_id = hir.local_def_id_to_hir_id(def_id); let expected_parent = hir.get_parent_item(hir_id); // If parents are different, it means that `item` is a reexport and we need to compute // the actual `cfg` by iterating through its "real" parents. if self.parent != Some(expected_parent) { let mut attrs = Vec::new(); for (parent_hir_id, _) in hir.parent_iter(hir_id) { let def_id = hir.local_def_id(parent_hir_id).to_def_id(); attrs.extend_from_slice(load_attrs(self.cx, def_id)); } let (_, cfg) = merge_attrs(self.cx, None, item.attrs.other_attrs.as_slice(), Some(&attrs)); item.cfg = cfg; } } </ins> let new_cfg = match (self.parent_cfg.take(), item.cfg.take()) { (None, None) => None, (Some(rc), None) | (None, Some(rc)) => Some(rc),

Related discussion:
text: From Given the following Rust code with in-line annotations of the expected behaviour: On: does not seem to be able to generate feature requirement labels on types in private modules () that are publicly reexported (). The labels do not show up on the module overview nor page, but do propagate into items like functions for the given type. This renders the type without any feature requirement, neither in the module overview: ! Nor on the page: ! Note that the label is propagated onto (does not have an explicit ), at least understood that! It is supposed to render the feature requirement for like , both in the module overview above as on the page: ! It seems tricky to combine feature requirements on the and reexport. In the case above they are the same, but what if: The type is only publicly available when and are specified. Specifying is fine but makes the contents of unreachable through the current module, specifying only should result in a "module not found" error. CC
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.
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 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 vs is used) and later perhaps simplifying based on feature relations (if implies there is no need to display as requirement, if either definition or reexport requires ). That's necessary to cleanly solve crate reexports, since you effectively want to ensure that the top-level crate feature implies feature 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).
I wonder if this is just an ordering issue of the passes: The private modules have disappeared by the point where we pass all the data down so we don't see them.