diff --git a/src/librustdoc/clean/types.rs b/src/librustdoc/clean/types.rs
index 5f80aded9d0b4..27eb56a9858b8 100644
--- a/src/librustdoc/clean/types.rs
+++ b/src/librustdoc/clean/types.rs
@@ -1013,7 +1013,6 @@ pub(crate) fn extract_cfg_from_attrs<'a, I: Iterator<Item = &'a hir::Attribute>
     tcx: TyCtxt<'_>,
     hidden_cfg: &FxHashSet<Cfg>,
 ) -> Option<Arc<Cfg>> {
-    let sess = tcx.sess;
     let doc_cfg_active = tcx.features().doc_cfg();
     let doc_auto_cfg_active = tcx.features().doc_auto_cfg();
 
@@ -1034,9 +1033,27 @@ pub(crate) fn extract_cfg_from_attrs<'a, I: Iterator<Item = &'a hir::Attribute>
             .filter(|attr| attr.has_name(sym::cfg))
             .peekable();
         if doc_cfg.peek().is_some() && doc_cfg_active {
-            doc_cfg
-                .filter_map(|attr| Cfg::parse(&attr).ok())
-                .fold(Cfg::True, |cfg, new_cfg| cfg & new_cfg)
+            let sess = tcx.sess;
+            doc_cfg.fold(Cfg::True, |mut cfg, item| {
+                if let Some(cfg_mi) =
+                    item.meta_item().and_then(|item| rustc_expand::config::parse_cfg(item, sess))
+                {
+                    // The result is unused here but we can gate unstable predicates
+                    rustc_attr_parsing::cfg_matches(
+                        cfg_mi,
+                        tcx.sess,
+                        rustc_ast::CRATE_NODE_ID,
+                        Some(tcx.features()),
+                    );
+                    match Cfg::parse(cfg_mi) {
+                        Ok(new_cfg) => cfg &= new_cfg,
+                        Err(e) => {
+                            sess.dcx().span_err(e.span, e.msg);
+                        }
+                    }
+                }
+                cfg
+            })
         } else if doc_auto_cfg_active {
             // If there is no `doc(cfg())`, then we retrieve the `cfg()` attributes (because
             // `doc(cfg())` overrides `cfg()`).
@@ -1053,40 +1070,6 @@ pub(crate) fn extract_cfg_from_attrs<'a, I: Iterator<Item = &'a hir::Attribute>
         Cfg::True
     };
 
-    for attr in attrs.clone() {
-        // #[doc]
-        if attr.doc_str().is_none() && attr.has_name(sym::doc) {
-            // #[doc(...)]
-            if let Some(list) = attr.meta_item_list() {
-                for item in list {
-                    // #[doc(hidden)]
-                    if !item.has_name(sym::cfg) {
-                        continue;
-                    }
-                    // #[doc(cfg(...))]
-                    if let Some(cfg_mi) = item
-                        .meta_item()
-                        .and_then(|item| rustc_expand::config::parse_cfg(item, sess))
-                    {
-                        // The result is unused here but we can gate unstable predicates
-                        rustc_attr_parsing::cfg_matches(
-                            cfg_mi,
-                            tcx.sess,
-                            rustc_ast::CRATE_NODE_ID,
-                            Some(tcx.features()),
-                        );
-                        match Cfg::parse(cfg_mi) {
-                            Ok(new_cfg) => cfg &= new_cfg,
-                            Err(e) => {
-                                sess.dcx().span_err(e.span, e.msg);
-                            }
-                        }
-                    }
-                }
-            }
-        }
-    }
-
     // treat #[target_feature(enable = "feat")] attributes as if they were
     // #[doc(cfg(target_feature = "feat"))] attributes as well
     for attr in hir_attr_lists(attrs, sym::target_feature) {