Skip to content

Commit b90dfc5

Browse files
committed
Auto merge of #155954 - cijiugechu:doc_cfg-decl-macro, r=<try>
rustdoc: preserve parent doc cfg for `macro_export` macros
2 parents f53b654 + 09e9d3f commit b90dfc5

5 files changed

Lines changed: 153 additions & 16 deletions

File tree

src/librustdoc/clean/mod.rs

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -95,12 +95,13 @@ pub(crate) fn clean_doc_module<'tcx>(doc: &DocModule<'tcx>, cx: &mut DocContext<
9595
// This covers the case where somebody does an import which should pull in an item,
9696
// but there's already an item with the same namespace and same name. Rust gives
9797
// priority to the not-imported one, so we should, too.
98-
items.extend(doc.items.values().flat_map(|(item, renamed, import_ids)| {
98+
items.extend(doc.items.values().flat_map(|entry| {
9999
// First, lower everything other than glob imports.
100+
let item = entry.item;
100101
if matches!(item.kind, hir::ItemKind::Use(_, hir::UseKind::Glob)) {
101102
return Vec::new();
102103
}
103-
let v = clean_maybe_renamed_item(cx, item, *renamed, import_ids);
104+
let v = clean_maybe_renamed_item(cx, item, entry.renamed, &entry.import_ids);
104105
for item in &v {
105106
if let Some(name) = item.name
106107
&& (cx.document_hidden() || !item.is_doc_hidden())
@@ -130,10 +131,11 @@ pub(crate) fn clean_doc_module<'tcx>(doc: &DocModule<'tcx>, cx: &mut DocContext<
130131
_ => unreachable!(),
131132
}
132133
}));
133-
items.extend(doc.items.values().flat_map(|(item, renamed, _)| {
134+
items.extend(doc.items.values().flat_map(|entry| {
134135
// Now we actually lower the imports, skipping everything else.
136+
let item = entry.item;
135137
if let hir::ItemKind::Use(path, hir::UseKind::Glob) = item.kind {
136-
clean_use_statement(item, *renamed, path, hir::UseKind::Glob, cx, &mut inserted)
138+
clean_use_statement(item, entry.renamed, path, hir::UseKind::Glob, cx, &mut inserted)
137139
} else {
138140
// skip everything else
139141
Vec::new()

src/librustdoc/clean/types.rs

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ use rustc_resolve::rustdoc::{
2525
DocFragment, add_doc_fragment, attrs_to_doc_fragments, inner_docs, span_of_fragments,
2626
};
2727
use rustc_session::Session;
28+
use rustc_span::def_id::CRATE_DEF_ID;
2829
use rustc_span::hygiene::MacroKind;
2930
use rustc_span::symbol::{Symbol, kw, sym};
3031
use rustc_span::{DUMMY_SP, FileName, Ident, Loc, RemapPathScopeComponents};
@@ -405,6 +406,23 @@ fn is_field_vis_inherited(tcx: TyCtxt<'_>, def_id: DefId) -> bool {
405406
}
406407

407408
impl Item {
409+
pub(crate) fn cfg_parent_ids_for_detached_item(&self, tcx: TyCtxt<'_>) -> Vec<LocalDefId> {
410+
let Some(def_id) = self.inline_stmt_id.or(self.item_id.as_local_def_id()) else {
411+
return Vec::new();
412+
};
413+
let mut ids = Vec::new();
414+
let mut next = def_id;
415+
while let Some(parent) = tcx.opt_local_parent(next) {
416+
if parent == CRATE_DEF_ID {
417+
break;
418+
}
419+
ids.push(parent);
420+
next = parent;
421+
}
422+
ids.reverse();
423+
ids
424+
}
425+
408426
/// Returns the effective stability of the item.
409427
///
410428
/// This method should only be called after the `propagate-stability` pass has been run.

src/librustdoc/passes/propagate_doc_cfg.rs

Lines changed: 41 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -51,12 +51,31 @@ fn add_only_cfg_attributes(attrs: &mut Vec<Attribute>, new_attrs: &[Attribute])
5151
}
5252
}
5353

54+
/// This function goes through the attributes list (`new_attrs`) and extracts the attributes that
55+
/// affect the cfg state propagated to detached items.
56+
fn add_cfg_state_attributes(attrs: &mut Vec<Attribute>, new_attrs: &[Attribute]) {
57+
for attr in new_attrs {
58+
if let Attribute::Parsed(AttributeKind::Doc(d)) = attr
59+
&& (!d.cfg.is_empty() || !d.auto_cfg.is_empty() || !d.auto_cfg_change.is_empty())
60+
{
61+
let mut new_attr = DocAttribute::default();
62+
new_attr.cfg = d.cfg.clone();
63+
new_attr.auto_cfg = d.auto_cfg.clone();
64+
new_attr.auto_cfg_change = d.auto_cfg_change.clone();
65+
attrs.push(Attribute::Parsed(AttributeKind::Doc(Box::new(new_attr))));
66+
} else if let Attribute::Parsed(AttributeKind::CfgTrace(..)) = attr {
67+
// If it's a `cfg()` attribute, we keep it.
68+
attrs.push(attr.clone());
69+
}
70+
}
71+
}
72+
5473
impl CfgPropagator<'_, '_> {
5574
// Some items need to merge their attributes with their parents' otherwise a few of them
5675
// (mostly `cfg` ones) will be missing.
5776
fn merge_with_parent_attributes(&mut self, item: &mut Item) {
5877
let mut attrs = Vec::new();
59-
// We only need to merge an item attributes with its parent's in case it's an impl as an
78+
// We need to merge an item attributes with its parent's in case it's an impl as an
6079
// impl might not be defined in the same module as the item it implements.
6180
//
6281
// Otherwise, `cfg_info` already tracks everything we need so nothing else to do!
@@ -69,6 +88,27 @@ impl CfgPropagator<'_, '_> {
6988
next_def_id = parent_def_id;
7089
}
7190
}
91+
// We also need to merge an item attributes with its parent's in case it's a macro with
92+
// the `#[macro_export]` attribute, because it might not be defined at crate root.
93+
if matches!(item.kind, ItemKind::MacroItem(_))
94+
&& item.inner.attrs.other_attrs.iter().any(|attr| {
95+
matches!(
96+
attr,
97+
rustc_hir::Attribute::Parsed(
98+
rustc_hir::attrs::AttributeKind::MacroExport { .. }
99+
)
100+
)
101+
})
102+
{
103+
for parent_def_id in &item.cfg_parent_ids_for_detached_item(self.cx.tcx) {
104+
let mut parent_attrs = Vec::new();
105+
add_cfg_state_attributes(
106+
&mut parent_attrs,
107+
load_attrs(self.cx.tcx, parent_def_id.to_def_id()),
108+
);
109+
merge_attrs(self.cx.tcx, &[], Some((&parent_attrs, None)), &mut self.cfg_info);
110+
}
111+
}
72112

73113
let (_, cfg) = merge_attrs(
74114
self.cx.tcx,

src/librustdoc/visit_ast.rs

Lines changed: 20 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ pub(crate) struct Module<'hir> {
3232
pub(crate) def_id: LocalDefId,
3333
pub(crate) renamed: Option<Symbol>,
3434
pub(crate) import_id: Option<LocalDefId>,
35-
/// The key is the item `ItemId` and the value is: (item, renamed, Vec<import_id>).
35+
/// The key is the item `ItemId`.
3636
/// We use `FxIndexMap` to keep the insert order.
3737
///
3838
/// `import_id` needs to be a `Vec` because we live in a dark world where you can have code
@@ -52,10 +52,7 @@ pub(crate) struct Module<'hir> {
5252
/// So in this case, we don't want to have two items but just one with attributes from all
5353
/// non-glob imports to be merged. Glob imports attributes are always ignored, whether they're
5454
/// shadowed or not.
55-
pub(crate) items: FxIndexMap<
56-
(LocalDefId, Option<Symbol>),
57-
(&'hir hir::Item<'hir>, Option<Symbol>, Vec<LocalDefId>),
58-
>,
55+
pub(crate) items: FxIndexMap<(LocalDefId, Option<Symbol>), ItemEntry<'hir>>,
5956

6057
/// (def_id, renamed) -> (res, local_import_id)
6158
///
@@ -70,6 +67,13 @@ pub(crate) struct Module<'hir> {
7067
pub(crate) foreigns: Vec<(&'hir hir::ForeignItem<'hir>, Option<Symbol>, Option<LocalDefId>)>,
7168
}
7269

70+
#[derive(Debug)]
71+
pub(crate) struct ItemEntry<'hir> {
72+
pub(crate) item: &'hir hir::Item<'hir>,
73+
pub(crate) renamed: Option<Symbol>,
74+
pub(crate) import_ids: Vec<LocalDefId>,
75+
}
76+
7377
impl Module<'_> {
7478
pub(crate) fn new(
7579
name: Symbol,
@@ -172,9 +176,10 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> {
172176
{
173177
let item = self.cx.tcx.hir_expect_item(local_def_id);
174178
let (ident, _, _) = item.expect_macro();
175-
top_level_module
176-
.items
177-
.insert((local_def_id, Some(ident.name)), (item, None, Vec::new()));
179+
top_level_module.items.insert(
180+
(local_def_id, Some(ident.name)),
181+
ItemEntry { item, renamed: None, import_ids: Vec::new() },
182+
);
178183
}
179184
}
180185

@@ -413,10 +418,14 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> {
413418
.unwrap()
414419
.items
415420
.entry(key)
416-
.and_modify(|v| v.2.push(import_id))
417-
.or_insert_with(|| (item, renamed, vec![import_id]));
421+
.and_modify(|v| v.import_ids.push(import_id))
422+
.or_insert_with(|| ItemEntry { item, renamed, import_ids: vec![import_id] });
418423
} else {
419-
self.modules.last_mut().unwrap().items.insert(key, (item, renamed, Vec::new()));
424+
self.modules
425+
.last_mut()
426+
.unwrap()
427+
.items
428+
.insert(key, ItemEntry { item, renamed, import_ids: Vec::new() });
420429
}
421430
}
422431
}
Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
// Regression test for <https://github.com/rust-lang/rust/issues/100916>
2+
//@ compile-flags: --cfg feature="routing"
3+
4+
#![crate_name = "foo"]
5+
#![feature(doc_cfg)]
6+
7+
#[cfg(feature = "routing")]
8+
pub mod routing {
9+
//@ has 'foo/macro.vpath.html' '//*[@class="stab portability"]' 'Available on crate feature routing only.'
10+
#[macro_export]
11+
macro_rules! vpath {
12+
() => {};
13+
}
14+
}
15+
16+
#[doc(cfg(feature = "manual"))]
17+
pub mod manual {
18+
//@ has 'foo/macro.manual_macro.html' '//*[@class="stab portability"]' 'Available on crate feature manual only.'
19+
#[macro_export]
20+
macro_rules! manual_macro {
21+
() => {};
22+
}
23+
}
24+
25+
#[doc(cfg(feature = "outer"))]
26+
pub mod outer {
27+
#[cfg(feature = "routing")]
28+
pub mod inner {
29+
//@ has 'foo/macro.nested_macro.html' '//*[@class="stab portability"]' 'Available on crate features outer and routing only.'
30+
#[macro_export]
31+
macro_rules! nested_macro {
32+
() => {};
33+
}
34+
}
35+
}
36+
37+
#[cfg(feature = "routing")]
38+
#[doc(auto_cfg = false)]
39+
pub mod auto_cfg_disabled {
40+
//@ count 'foo/macro.no_auto_cfg_macro.html' '//*[@class="stab portability"]' 0
41+
#[macro_export]
42+
macro_rules! no_auto_cfg_macro {
43+
() => {};
44+
}
45+
}
46+
47+
#[cfg(feature = "routing")]
48+
#[doc(auto_cfg(hide(feature = "routing")))]
49+
pub mod auto_cfg_hidden {
50+
//@ count 'foo/macro.hidden_cfg_macro.html' '//*[@class="stab portability"]' 0
51+
#[macro_export]
52+
macro_rules! hidden_cfg_macro {
53+
() => {};
54+
}
55+
}
56+
57+
#[cfg(feature = "routing")]
58+
#[doc(auto_cfg(hide(feature = "routing")))]
59+
pub mod auto_cfg_shown {
60+
#[doc(auto_cfg(show(feature = "routing")))]
61+
pub mod inner {
62+
//@ has 'foo/macro.shown_cfg_macro.html' '//*[@class="stab portability"]' 'Available on crate feature routing only.'
63+
#[macro_export]
64+
macro_rules! shown_cfg_macro {
65+
() => {};
66+
}
67+
}
68+
}

0 commit comments

Comments
 (0)