diff --git a/src/librustdoc/clean/inline.rs b/src/librustdoc/clean/inline.rs index 4a888b22332..39493f6edf8 100644 --- a/src/librustdoc/clean/inline.rs +++ b/src/librustdoc/clean/inline.rs @@ -318,10 +318,10 @@ fn merge_attrs( } else { Attributes::from_ast(&both, None) }, - both.cfg(cx.sess()), + both.cfg(cx.tcx), ) } else { - (old_attrs.clean(cx), old_attrs.cfg(cx.sess())) + (old_attrs.clean(cx), old_attrs.cfg(cx.tcx)) } } diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index a55d85f5841..41bc30fd398 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -1973,7 +1973,7 @@ fn clean_extern_crate( def_id: crate_def_id.into(), visibility: krate.vis.clean(cx), kind: box ExternCrateItem { src: orig_name }, - cfg: attrs.cfg(cx.sess()), + cfg: attrs.cfg(cx.tcx), }] } diff --git a/src/librustdoc/clean/types.rs b/src/librustdoc/clean/types.rs index 0e78fe7aec3..288644ff296 100644 --- a/src/librustdoc/clean/types.rs +++ b/src/librustdoc/clean/types.rs @@ -421,7 +421,7 @@ impl Item { kind, box ast_attrs.clean(cx), cx, - ast_attrs.cfg(cx.sess()), + ast_attrs.cfg(cx.tcx), ) } @@ -747,7 +747,7 @@ crate trait AttributesExt { fn other_attrs(&self) -> Vec; - fn cfg(&self, sess: &Session) -> Option>; + fn cfg(&self, tcx: TyCtxt<'_>) -> Option>; } impl AttributesExt for [ast::Attribute] { @@ -772,8 +772,52 @@ impl AttributesExt for [ast::Attribute] { self.iter().filter(|attr| attr.doc_str().is_none()).cloned().collect() } - fn cfg(&self, sess: &Session) -> Option> { - let mut cfg = Cfg::True; + fn cfg(&self, tcx: TyCtxt<'_>) -> Option> { + let sess = tcx.sess; + let doc_cfg_active = tcx.features().doc_cfg; + + trait SingleExt { + type Item; + fn single(self) -> Option; + } + + impl SingleExt for T { + type Item = T::Item; + fn single(self) -> Option { + let mut iter = self.into_iter(); + let item = iter.next()?; + iter.next().is_none().then_some(())?; + Some(item) + } + } + + let mut cfg = if doc_cfg_active { + let mut doc_cfg = self + .iter() + .filter(|attr| attr.has_name(sym::doc)) + .filter_map(|attr| Some(attr.meta_item_list()?.single()?)) + .filter(|attr| attr.has_name(sym::cfg)) + .filter_map(|attr| Some(attr.meta_item_list()?.single()?.meta_item()?.clone())) + .peekable(); + if doc_cfg.peek().is_some() { + doc_cfg + .filter_map(|attr| { + Cfg::parse(&attr).map_err(|e| sess.diagnostic().span_err(e.span, e.msg)).ok() + }) + .fold(Cfg::True, |cfg, new_cfg| cfg & new_cfg) + } else { + self + .iter() + .filter(|attr| attr.has_name(sym::cfg)) + .filter_map(|attr| Some(attr.meta_item_list()?.single()?.meta_item()?.clone())) + .filter_map(|attr| { + Cfg::parse(&attr).map_err(|e| sess.diagnostic().span_err(e.span, e.msg)).ok() + }) + .fold(Cfg::True, |cfg, new_cfg| cfg & new_cfg) + } + } else { + Cfg::True + }; for attr in self.iter() { // #[doc] diff --git a/src/librustdoc/doctest.rs b/src/librustdoc/doctest.rs index 43abcf095d8..8cf7b50fbd9 100644 --- a/src/librustdoc/doctest.rs +++ b/src/librustdoc/doctest.rs @@ -1123,7 +1123,7 @@ impl<'a, 'hir, 'tcx> HirCollector<'a, 'hir, 'tcx> { let ast_attrs = self.tcx.hir().attrs(hir_id); let mut attrs = Attributes::from_ast(ast_attrs, None); - if let Some(ref cfg) = ast_attrs.cfg(self.sess) { + if let Some(ref cfg) = ast_attrs.cfg(self.tcx) { if !cfg.matches(&self.sess.parse_sess, Some(&self.sess.features_untracked())) { return; } diff --git a/src/librustdoc/html/render/print_item.rs b/src/librustdoc/html/render/print_item.rs index 28b2eded7cc..e68e1223171 100644 --- a/src/librustdoc/html/render/print_item.rs +++ b/src/librustdoc/html/render/print_item.rs @@ -323,7 +323,7 @@ fn item_module(w: &mut Buffer, cx: &Context<'_>, item: &clean::Item, items: &[cl let import_item = clean::Item { def_id: import_def_id.into(), attrs: import_attrs, - cfg: ast_attrs.cfg(cx.sess()), + cfg: ast_attrs.cfg(cx.tcx()), ..myitem.clone() }; diff --git a/src/librustdoc/lib.rs b/src/librustdoc/lib.rs index efc8e31498a..d070ce22890 100644 --- a/src/librustdoc/lib.rs +++ b/src/librustdoc/lib.rs @@ -5,6 +5,7 @@ #![feature(rustc_private)] #![feature(array_methods)] #![feature(assert_matches)] +#![feature(bool_to_option)] #![feature(box_patterns)] #![feature(control_flow_enum)] #![feature(box_syntax)] diff --git a/src/test/rustdoc/doc-cfg-implicit-gate.rs b/src/test/rustdoc/doc-cfg-implicit-gate.rs new file mode 100644 index 00000000000..92804d3729b --- /dev/null +++ b/src/test/rustdoc/doc-cfg-implicit-gate.rs @@ -0,0 +1,7 @@ +// compile-flags:--cfg feature="worricow" +#![crate_name = "xenogenous"] + +// @has 'xenogenous/struct.Worricow.html' +// @count - '//*[@class="stab portability"]' 0 +#[cfg(feature = "worricow")] +pub struct Worricow; diff --git a/src/test/rustdoc/doc-cfg-implicit.rs b/src/test/rustdoc/doc-cfg-implicit.rs new file mode 100644 index 00000000000..36c2025785d --- /dev/null +++ b/src/test/rustdoc/doc-cfg-implicit.rs @@ -0,0 +1,31 @@ +#![crate_name = "funambulism"] +#![feature(doc_cfg)] + +// @has 'funambulism/struct.Disorbed.html' +// @count - '//*[@class="stab portability"]' 1 +// @matches - '//*[@class="stab portability"]' 'crate feature disorbed' +// compile-flags:--cfg feature="disorbed" +#[cfg(feature = "disorbed")] +pub struct Disorbed; + +// @has 'funambulism/struct.Aesthesia.html' +// @count - '//*[@class="stab portability"]' 1 +// @matches - '//*[@class="stab portability"]' 'crate feature aesthesia' +// compile-flags:--cfg feature="aesthesia" +#[doc(cfg(feature = "aesthesia"))] +pub struct Aesthesia; + +// @has 'funambulism/struct.Pliothermic.html' +// @count - '//*[@class="stab portability"]' 1 +// @matches - '//*[@class="stab portability"]' 'crate feature pliothermic' +// compile-flags:--cfg feature="epopoeist" +#[cfg(feature = "epopoeist")] +#[doc(cfg(feature = "pliothermic"))] +pub struct Pliothermic; + +// @has 'funambulism/struct.Simillimum.html' +// @count - '//*[@class="stab portability"]' 0 +// compile-flags:--cfg feature="simillimum" +#[cfg(feature = "simillimum")] +#[doc(cfg(all()))] +pub struct Simillimum;