Skip to content

Commit ec0008a

Browse files
Rollup merge of #113091 - GuillaumeGomez:prevent-cfg-merge-reexport, r=rustdoc
Don't merge cfg and doc(cfg) attributes for re-exports Fixes #112881. ## Explanations When re-exporting things with different `cfg`s there are two things that can happen: * The re-export uses a subset of `cfg`s, this subset is sufficient so that the item will appear exactly with the subset * The re-export uses a non-subset of `cfg`s (e.g. like the example I posted just above where the re-export is ungated), if the non-subset `cfg`s are active (e.g. compiling that example on windows) then this will be a compile error as the item doesn't exist to re-export, if the subset `cfg`s are active it behaves like 1. ### Glob re-exports? **This only applies to non-glob inlined re-exports.** For glob re-exports the item may or may not exist to be re-exported (potentially the `cfg`s on the path up until the glob can be removed, and only `cfg`s on the globbed item itself matter), for non-inlined re-exports see #85043. cc `@Nemo157` r? `@notriddle`
2 parents d253bf6 + 823148f commit ec0008a

File tree

5 files changed

+78
-49
lines changed

5 files changed

+78
-49
lines changed

src/librustdoc/clean/mod.rs

+42-34
Original file line numberDiff line numberDiff line change
@@ -2646,6 +2646,40 @@ fn filter_tokens_from_list(
26462646
tokens
26472647
}
26482648

2649+
fn filter_doc_attr_ident(ident: Symbol, is_inline: bool) -> bool {
2650+
if is_inline {
2651+
ident == sym::hidden || ident == sym::inline || ident == sym::no_inline
2652+
} else {
2653+
ident == sym::cfg
2654+
}
2655+
}
2656+
2657+
/// Remove attributes from `normal` that should not be inherited by `use` re-export.
2658+
/// Before calling this function, make sure `normal` is a `#[doc]` attribute.
2659+
fn filter_doc_attr(normal: &mut ast::NormalAttr, is_inline: bool) {
2660+
match normal.item.args {
2661+
ast::AttrArgs::Delimited(ref mut args) => {
2662+
let tokens = filter_tokens_from_list(&args.tokens, |token| {
2663+
!matches!(
2664+
token,
2665+
TokenTree::Token(
2666+
Token {
2667+
kind: TokenKind::Ident(
2668+
ident,
2669+
_,
2670+
),
2671+
..
2672+
},
2673+
_,
2674+
) if filter_doc_attr_ident(*ident, is_inline),
2675+
)
2676+
});
2677+
args.tokens = TokenStream::new(tokens);
2678+
}
2679+
ast::AttrArgs::Empty | ast::AttrArgs::Eq(..) => {}
2680+
}
2681+
}
2682+
26492683
/// When inlining items, we merge their attributes (and all the reexports attributes too) with the
26502684
/// final reexport. For example:
26512685
///
@@ -2672,13 +2706,6 @@ fn add_without_unwanted_attributes<'hir>(
26722706
is_inline: bool,
26732707
import_parent: Option<DefId>,
26742708
) {
2675-
// If it's not `#[doc(inline)]`, we don't want all attributes, otherwise we keep everything.
2676-
if !is_inline {
2677-
for attr in new_attrs {
2678-
attrs.push((Cow::Borrowed(attr), import_parent));
2679-
}
2680-
return;
2681-
}
26822709
for attr in new_attrs {
26832710
if matches!(attr.kind, ast::AttrKind::DocComment(..)) {
26842711
attrs.push((Cow::Borrowed(attr), import_parent));
@@ -2687,33 +2714,14 @@ fn add_without_unwanted_attributes<'hir>(
26872714
let mut attr = attr.clone();
26882715
match attr.kind {
26892716
ast::AttrKind::Normal(ref mut normal) => {
2690-
if let [ident] = &*normal.item.path.segments
2691-
&& let ident = ident.ident.name
2692-
&& ident == sym::doc
2693-
{
2694-
match normal.item.args {
2695-
ast::AttrArgs::Delimited(ref mut args) => {
2696-
let tokens = filter_tokens_from_list(&args.tokens, |token| {
2697-
!matches!(
2698-
token,
2699-
TokenTree::Token(
2700-
Token {
2701-
kind: TokenKind::Ident(
2702-
sym::hidden | sym::inline | sym::no_inline,
2703-
_,
2704-
),
2705-
..
2706-
},
2707-
_,
2708-
),
2709-
)
2710-
});
2711-
args.tokens = TokenStream::new(tokens);
2712-
attrs.push((Cow::Owned(attr), import_parent));
2713-
}
2714-
ast::AttrArgs::Empty | ast::AttrArgs::Eq(..) => {
2715-
attrs.push((Cow::Owned(attr), import_parent));
2716-
}
2717+
if let [ident] = &*normal.item.path.segments {
2718+
let ident = ident.ident.name;
2719+
if ident == sym::doc {
2720+
filter_doc_attr(normal, is_inline);
2721+
attrs.push((Cow::Owned(attr), import_parent));
2722+
} else if ident != sym::cfg {
2723+
// If it's not a `cfg()` attribute, we keep it.
2724+
attrs.push((Cow::Owned(attr), import_parent));
27172725
}
27182726
}
27192727
}

src/librustdoc/html/render/print_item.rs

+2-11
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,3 @@
1-
use clean::AttributesExt;
2-
31
use rustc_data_structures::captures::Captures;
42
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
53
use rustc_hir as hir;
@@ -465,16 +463,9 @@ fn item_module(w: &mut Buffer, cx: &mut Context<'_>, item: &clean::Item, items:
465463

466464
clean::ImportItem(ref import) => {
467465
let stab_tags = if let Some(import_def_id) = import.source.did {
468-
let ast_attrs = tcx.get_attrs_unchecked(import_def_id);
469-
let import_attrs = Box::new(clean::Attributes::from_ast(ast_attrs));
470-
471466
// Just need an item with the correct def_id and attrs
472-
let import_item = clean::Item {
473-
item_id: import_def_id.into(),
474-
attrs: import_attrs,
475-
cfg: ast_attrs.cfg(tcx, &cx.cache().hidden_cfg),
476-
..myitem.clone()
477-
};
467+
let import_item =
468+
clean::Item { item_id: import_def_id.into(), ..myitem.clone() };
478469

479470
let stab_tags = Some(extra_info_tags(&import_item, item, tcx).to_string());
480471
stab_tags

tests/rustdoc/reexport-cfg.rs

+30
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
// This test ensures that only the re-export `cfg` will be displayed and that it won't
2+
// include `cfg`s from the previous chained items.
3+
4+
#![crate_name = "foo"]
5+
#![feature(doc_auto_cfg, doc_cfg)]
6+
7+
mod foo {
8+
#[cfg(not(feature = "foo"))]
9+
pub struct Bar;
10+
11+
#[doc(cfg(not(feature = "bar")))]
12+
pub struct Bar2;
13+
}
14+
15+
// @has 'foo/index.html'
16+
// @has - '//*[@class="item-name"]' 'BabarNon-lie'
17+
#[cfg(not(feature = "lie"))]
18+
pub use crate::foo::Bar as Babar;
19+
20+
// @has - '//*[@class="item-name"]' 'Babar2Non-cake'
21+
#[doc(cfg(not(feature = "cake")))]
22+
pub use crate::foo::Bar2 as Babar2;
23+
24+
// @has - '//*[@class="item-table"]/li' 'pub use crate::Babar as Elephant;Non-robot'
25+
#[cfg(not(feature = "robot"))]
26+
pub use crate::Babar as Elephant;
27+
28+
// @has - '//*[@class="item-table"]/li' 'pub use crate::Babar2 as Elephant2;Non-cat'
29+
#[doc(cfg(not(feature = "cat")))]
30+
pub use crate::Babar2 as Elephant2;

tests/rustdoc/reexport-stability-tags-deprecated-and-portability.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -27,15 +27,15 @@ pub mod mod1 {
2727
pub mod mod2 {
2828
// @has - '//code' 'pub use tag::Portability;'
2929
// @!has - '//span' 'Deprecated'
30-
// @has - '//span' 'sync'
30+
// @!has - '//span' 'sync'
3131
pub use tag::Portability;
3232
}
3333

3434
// @has foo/mod3/index.html
3535
pub mod mod3 {
3636
// @has - '//code' 'pub use tag::Both;'
3737
// @has - '//span' 'Deprecated'
38-
// @has - '//span' 'sync'
38+
// @!has - '//span' 'sync'
3939
pub use tag::Both;
4040
}
4141

tests/rustdoc/reexport-stability-tags-unstable-and-portability.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ pub mod mod1 {
3535
pub mod mod2 {
3636
// @has - '//code' 'pub use tag::Portability;'
3737
// @!has - '//span' 'Experimental'
38-
// @has - '//span' 'sync'
38+
// @!has - '//span' 'sync'
3939
#[stable(feature = "rust1", since = "1.0.0")]
4040
pub use tag::Portability;
4141
}
@@ -45,7 +45,7 @@ pub mod mod2 {
4545
pub mod mod3 {
4646
// @has - '//code' 'pub use tag::Both;'
4747
// @has - '//span' 'Experimental'
48-
// @has - '//span' 'sync'
48+
// @!has - '//span' 'sync'
4949
#[stable(feature = "rust1", since = "1.0.0")]
5050
pub use tag::Both;
5151
}

0 commit comments

Comments
 (0)