about summary refs log tree commit diff
path: root/src/librustdoc
diff options
context:
space:
mode:
authorGuillaume Gomez <guillaume1.gomez@gmail.com>2023-12-15 11:51:23 +0100
committerGitHub <noreply@github.com>2023-12-15 11:51:23 +0100
commitec0008a915c3d27528a2df0eb420aed748b217f8 (patch)
treea56142d8f4e578b4b6064df07c49084271f32387 /src/librustdoc
parentd253bf61ad38a59cc579aee688f81a06c31283d3 (diff)
parent823148fa849eb9b6fb896a0ac1772a2be3bdb043 (diff)
downloadrust-ec0008a915c3d27528a2df0eb420aed748b217f8.tar.gz
rust-ec0008a915c3d27528a2df0eb420aed748b217f8.zip
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 https://github.com/rust-lang/rust/issues/85043.

cc `@Nemo157`
r? `@notriddle`
Diffstat (limited to 'src/librustdoc')
-rw-r--r--src/librustdoc/clean/mod.rs76
-rw-r--r--src/librustdoc/html/render/print_item.rs13
2 files changed, 44 insertions, 45 deletions
diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs
index 28ea662eab3..6631c427270 100644
--- a/src/librustdoc/clean/mod.rs
+++ b/src/librustdoc/clean/mod.rs
@@ -2646,6 +2646,40 @@ fn filter_tokens_from_list(
     tokens
 }
 
+fn filter_doc_attr_ident(ident: Symbol, is_inline: bool) -> bool {
+    if is_inline {
+        ident == sym::hidden || ident == sym::inline || ident == sym::no_inline
+    } else {
+        ident == sym::cfg
+    }
+}
+
+/// Remove attributes from `normal` that should not be inherited by `use` re-export.
+/// Before calling this function, make sure `normal` is a `#[doc]` attribute.
+fn filter_doc_attr(normal: &mut ast::NormalAttr, is_inline: bool) {
+    match normal.item.args {
+        ast::AttrArgs::Delimited(ref mut args) => {
+            let tokens = filter_tokens_from_list(&args.tokens, |token| {
+                !matches!(
+                    token,
+                    TokenTree::Token(
+                        Token {
+                            kind: TokenKind::Ident(
+                                ident,
+                                _,
+                            ),
+                            ..
+                        },
+                        _,
+                    ) if filter_doc_attr_ident(*ident, is_inline),
+                )
+            });
+            args.tokens = TokenStream::new(tokens);
+        }
+        ast::AttrArgs::Empty | ast::AttrArgs::Eq(..) => {}
+    }
+}
+
 /// When inlining items, we merge their attributes (and all the reexports attributes too) with the
 /// final reexport. For example:
 ///
@@ -2672,13 +2706,6 @@ fn add_without_unwanted_attributes<'hir>(
     is_inline: bool,
     import_parent: Option<DefId>,
 ) {
-    // If it's not `#[doc(inline)]`, we don't want all attributes, otherwise we keep everything.
-    if !is_inline {
-        for attr in new_attrs {
-            attrs.push((Cow::Borrowed(attr), import_parent));
-        }
-        return;
-    }
     for attr in new_attrs {
         if matches!(attr.kind, ast::AttrKind::DocComment(..)) {
             attrs.push((Cow::Borrowed(attr), import_parent));
@@ -2687,33 +2714,14 @@ fn add_without_unwanted_attributes<'hir>(
         let mut attr = attr.clone();
         match attr.kind {
             ast::AttrKind::Normal(ref mut normal) => {
-                if let [ident] = &*normal.item.path.segments
-                    && let ident = ident.ident.name
-                    && ident == sym::doc
-                {
-                    match normal.item.args {
-                        ast::AttrArgs::Delimited(ref mut args) => {
-                            let tokens = filter_tokens_from_list(&args.tokens, |token| {
-                                !matches!(
-                                    token,
-                                    TokenTree::Token(
-                                        Token {
-                                            kind: TokenKind::Ident(
-                                                sym::hidden | sym::inline | sym::no_inline,
-                                                _,
-                                            ),
-                                            ..
-                                        },
-                                        _,
-                                    ),
-                                )
-                            });
-                            args.tokens = TokenStream::new(tokens);
-                            attrs.push((Cow::Owned(attr), import_parent));
-                        }
-                        ast::AttrArgs::Empty | ast::AttrArgs::Eq(..) => {
-                            attrs.push((Cow::Owned(attr), import_parent));
-                        }
+                if let [ident] = &*normal.item.path.segments {
+                    let ident = ident.ident.name;
+                    if ident == sym::doc {
+                        filter_doc_attr(normal, is_inline);
+                        attrs.push((Cow::Owned(attr), import_parent));
+                    } else if ident != sym::cfg {
+                        // If it's not a `cfg()` attribute, we keep it.
+                        attrs.push((Cow::Owned(attr), import_parent));
                     }
                 }
             }
diff --git a/src/librustdoc/html/render/print_item.rs b/src/librustdoc/html/render/print_item.rs
index ff7ce01e807..5ca623f01f1 100644
--- a/src/librustdoc/html/render/print_item.rs
+++ b/src/librustdoc/html/render/print_item.rs
@@ -1,5 +1,3 @@
-use clean::AttributesExt;
-
 use rustc_data_structures::captures::Captures;
 use rustc_data_structures::fx::{FxHashMap, FxHashSet};
 use rustc_hir as hir;
@@ -465,16 +463,9 @@ fn item_module(w: &mut Buffer, cx: &mut Context<'_>, item: &clean::Item, items:
 
             clean::ImportItem(ref import) => {
                 let stab_tags = if let Some(import_def_id) = import.source.did {
-                    let ast_attrs = tcx.get_attrs_unchecked(import_def_id);
-                    let import_attrs = Box::new(clean::Attributes::from_ast(ast_attrs));
-
                     // Just need an item with the correct def_id and attrs
-                    let import_item = clean::Item {
-                        item_id: import_def_id.into(),
-                        attrs: import_attrs,
-                        cfg: ast_attrs.cfg(tcx, &cx.cache().hidden_cfg),
-                        ..myitem.clone()
-                    };
+                    let import_item =
+                        clean::Item { item_id: import_def_id.into(), ..myitem.clone() };
 
                     let stab_tags = Some(extra_info_tags(&import_item, item, tcx).to_string());
                     stab_tags