diff --git a/compiler/rustc_ast_passes/src/feature_gate.rs b/compiler/rustc_ast_passes/src/feature_gate.rs index 077ab06d82dde..6c27101667cf3 100644 --- a/compiler/rustc_ast_passes/src/feature_gate.rs +++ b/compiler/rustc_ast_passes/src/feature_gate.rs @@ -320,6 +320,7 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> { gate_doc!( include => external_doc cfg => doc_cfg + cfg_hide => doc_cfg_hide masked => doc_masked notable_trait => doc_notable_trait keyword => doc_keyword diff --git a/compiler/rustc_feature/src/active.rs b/compiler/rustc_feature/src/active.rs index 7ae7e0094c6d1..3a31ad4090e0c 100644 --- a/compiler/rustc_feature/src/active.rs +++ b/compiler/rustc_feature/src/active.rs @@ -655,6 +655,9 @@ declare_features! ( /// Allows unsizing coercions in `const fn`. (active, const_fn_unsize, "1.53.0", Some(64992), None), + /// Allows `#[doc(cfg_hide(...))]`. + (active, doc_cfg_hide, "1.53.0", Some(43781), None), + // ------------------------------------------------------------------------- // feature-group-end: actual feature gates // ------------------------------------------------------------------------- diff --git a/compiler/rustc_passes/src/check_attr.rs b/compiler/rustc_passes/src/check_attr.rs index d57cba6420f7b..0b7597247cda6 100644 --- a/compiler/rustc_passes/src/check_attr.rs +++ b/compiler/rustc_passes/src/check_attr.rs @@ -628,6 +628,7 @@ impl CheckAttrVisitor<'tcx> { // plugins: removed, but rustdoc warns about it itself sym::alias | sym::cfg + | sym::cfg_hide | sym::hidden | sym::html_favicon_url | sym::html_logo_url diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index 4be187c5208cd..ec520e2cc2b20 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -346,6 +346,7 @@ symbols! { cfg_attr_multi, cfg_doctest, cfg_eval, + cfg_hide, cfg_panic, cfg_sanitize, cfg_target_feature, @@ -477,6 +478,7 @@ symbols! { doc, doc_alias, doc_cfg, + doc_cfg_hide, doc_keyword, doc_masked, doc_notable_trait, diff --git a/library/alloc/src/lib.rs b/library/alloc/src/lib.rs index 3a5dcec668ff6..cf23f131522b2 100644 --- a/library/alloc/src/lib.rs +++ b/library/alloc/src/lib.rs @@ -62,7 +62,10 @@ html_root_url = "https://doc.rust-lang.org/nightly/", html_playground_url = "https://play.rust-lang.org/", issue_tracker_base_url = "https://github.com/rust-lang/rust/issues/", - test(no_crate_inject, attr(allow(unused_variables), deny(warnings))) + test(no_crate_inject, attr(allow(unused_variables), deny(warnings))), +)] +#![cfg_attr(not(bootstrap), + doc(cfg_hide(not(test), not(any(test, bootstrap)), target_has_atomic = "ptr")) )] #![no_std] #![needs_allocator] @@ -146,6 +149,8 @@ #![feature(associated_type_bounds)] #![feature(slice_group_by)] #![feature(decl_macro)] +#![feature(doc_cfg)] +#![cfg_attr(not(bootstrap), feature(doc_cfg_hide))] // Allow testing this library #[cfg(test)] diff --git a/library/core/src/lib.rs b/library/core/src/lib.rs index 0e2c140c367a9..9da8ba254629b 100644 --- a/library/core/src/lib.rs +++ b/library/core/src/lib.rs @@ -55,7 +55,30 @@ html_playground_url = "https://play.rust-lang.org/", issue_tracker_base_url = "https://github.com/rust-lang/rust/issues/", test(no_crate_inject, attr(deny(warnings))), - test(attr(allow(dead_code, deprecated, unused_variables, unused_mut))) + test(attr(allow(dead_code, deprecated, unused_variables, unused_mut))), +)] +#![cfg_attr(not(bootstrap), + doc(cfg_hide( + not(test), + target_pointer_width = "16", + target_pointer_width = "32", + target_pointer_width = "64", + target_has_atomic = "8", + target_has_atomic = "16", + target_has_atomic = "32", + target_has_atomic = "64", + target_has_atomic = "ptr", + target_has_atomic_equal_alignment = "8", + target_has_atomic_equal_alignment = "16", + target_has_atomic_equal_alignment = "32", + target_has_atomic_equal_alignment = "64", + target_has_atomic_equal_alignment = "ptr", + target_has_atomic_load_store = "8", + target_has_atomic_load_store = "16", + target_has_atomic_load_store = "32", + target_has_atomic_load_store = "64", + target_has_atomic_load_store = "ptr", + )) )] #![no_core] #![warn(deprecated_in_future)] @@ -109,6 +132,7 @@ #![feature(custom_inner_attributes)] #![feature(decl_macro)] #![feature(doc_cfg)] +#![cfg_attr(not(bootstrap), feature(doc_cfg_hide))] #![cfg_attr(bootstrap, feature(doc_spotlight))] #![cfg_attr(not(bootstrap), feature(doc_notable_trait))] #![feature(duration_consts_2)] diff --git a/library/std/src/lib.rs b/library/std/src/lib.rs index 0ab9f490fd420..a9881a619faff 100644 --- a/library/std/src/lib.rs +++ b/library/std/src/lib.rs @@ -194,7 +194,10 @@ html_playground_url = "https://play.rust-lang.org/", issue_tracker_base_url = "https://github.com/rust-lang/rust/issues/", test(no_crate_inject, attr(deny(warnings))), - test(attr(allow(dead_code, deprecated, unused_variables, unused_mut))) + test(attr(allow(dead_code, deprecated, unused_variables, unused_mut))), +)] +#![cfg_attr(not(bootstrap), + doc(cfg_hide(not(test), not(any(test, bootstrap)))) )] // Don't link to std. We are std. #![no_std] @@ -259,6 +262,7 @@ #![feature(custom_test_frameworks)] #![feature(decl_macro)] #![feature(doc_cfg)] +#![cfg_attr(not(bootstrap), feature(doc_cfg_hide))] #![feature(doc_keyword)] #![feature(doc_masked)] #![cfg_attr(bootstrap, feature(doc_spotlight))] diff --git a/library/std/src/os/raw/mod.rs b/library/std/src/os/raw/mod.rs index 50464a050c706..954a78f00d77a 100644 --- a/library/std/src/os/raw/mod.rs +++ b/library/std/src/os/raw/mod.rs @@ -46,6 +46,7 @@ macro_rules! type_alias { } type_alias! { "char.md", c_char = u8, NonZero_c_char = NonZeroU8; +#[doc(cfg(all()))] #[cfg(any( all( target_os = "linux", @@ -88,6 +89,7 @@ type_alias! { "char.md", c_char = u8, NonZero_c_char = NonZeroU8; all(target_os = "fuchsia", target_arch = "aarch64") ))]} type_alias! { "char.md", c_char = i8, NonZero_c_char = NonZeroI8; +#[doc(cfg(all()))] #[cfg(not(any( all( target_os = "linux", @@ -136,12 +138,16 @@ type_alias! { "ushort.md", c_ushort = u16, NonZero_c_ushort = NonZeroU16; } type_alias! { "int.md", c_int = i32, NonZero_c_int = NonZeroI32; } type_alias! { "uint.md", c_uint = u32, NonZero_c_uint = NonZeroU32; } type_alias! { "long.md", c_long = i32, NonZero_c_long = NonZeroI32; +#[doc(cfg(all()))] #[cfg(any(target_pointer_width = "32", windows))] } type_alias! { "ulong.md", c_ulong = u32, NonZero_c_ulong = NonZeroU32; +#[doc(cfg(all()))] #[cfg(any(target_pointer_width = "32", windows))] } type_alias! { "long.md", c_long = i64, NonZero_c_long = NonZeroI64; +#[doc(cfg(all()))] #[cfg(all(target_pointer_width = "64", not(windows)))] } type_alias! { "ulong.md", c_ulong = u64, NonZero_c_ulong = NonZeroU64; +#[doc(cfg(all()))] #[cfg(all(target_pointer_width = "64", not(windows)))] } type_alias! { "longlong.md", c_longlong = i64, NonZero_c_longlong = NonZeroI64; } type_alias! { "ulonglong.md", c_ulonglong = u64, NonZero_c_ulonglong = NonZeroU64; } diff --git a/library/std/src/sys/windows/ext/raw.rs b/library/std/src/sys/windows/ext/raw.rs index 5014e008eb599..0ef3adade5c83 100644 --- a/library/std/src/sys/windows/ext/raw.rs +++ b/library/std/src/sys/windows/ext/raw.rs @@ -7,8 +7,10 @@ use crate::os::raw::c_void; #[stable(feature = "raw_ext", since = "1.1.0")] pub type HANDLE = *mut c_void; #[cfg(target_pointer_width = "32")] +#[doc(cfg(all()))] #[stable(feature = "raw_ext", since = "1.1.0")] pub type SOCKET = u32; #[cfg(target_pointer_width = "64")] +#[doc(cfg(all()))] #[stable(feature = "raw_ext", since = "1.1.0")] pub type SOCKET = u64; diff --git a/src/librustdoc/clean/inline.rs b/src/librustdoc/clean/inline.rs index 3986167bac8d3..e35768e137cb7 100644 --- a/src/librustdoc/clean/inline.rs +++ b/src/librustdoc/clean/inline.rs @@ -296,7 +296,14 @@ fn merge_attrs( if let Some(inner) = new_attrs { if let Some(new_id) = parent_module { let diag = cx.sess().diagnostic(); - Attributes::from_ast(diag, old_attrs, Some((inner, new_id))) + let doc_cfg_active = cx.tcx.features().doc_cfg; + Attributes::from_ast( + diag, + old_attrs, + Some((inner, new_id)), + doc_cfg_active, + &cx.hidden_cfg, + ) } else { let mut both = inner.to_vec(); both.extend_from_slice(old_attrs); diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index 6b04157d9530f..95cb24c5d2e30 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -124,7 +124,8 @@ impl Clean for doctree::Module<'_> { impl Clean for [ast::Attribute] { fn clean(&self, cx: &mut DocContext<'_>) -> Attributes { - Attributes::from_ast(cx.sess().diagnostic(), self, None) + let doc_cfg_active = cx.tcx.features().doc_cfg; + Attributes::from_ast(cx.sess().diagnostic(), self, None, doc_cfg_active, &cx.hidden_cfg) } } diff --git a/src/librustdoc/clean/types.rs b/src/librustdoc/clean/types.rs index 607a634c1bced..1d377ec194619 100644 --- a/src/librustdoc/clean/types.rs +++ b/src/librustdoc/clean/types.rs @@ -811,29 +811,6 @@ pub struct RenderedLink { } impl Attributes { - /// Extracts the content from an attribute `#[doc(cfg(content))]`. - crate fn extract_cfg(mi: &ast::MetaItem) -> Option<&ast::MetaItem> { - use rustc_ast::NestedMetaItem::MetaItem; - - if let ast::MetaItemKind::List(ref nmis) = mi.kind { - if nmis.len() == 1 { - if let MetaItem(ref cfg_mi) = nmis[0] { - if cfg_mi.has_name(sym::cfg) { - if let ast::MetaItemKind::List(ref cfg_nmis) = cfg_mi.kind { - if cfg_nmis.len() == 1 { - if let MetaItem(ref content_mi) = cfg_nmis[0] { - return Some(content_mi); - } - } - } - } - } - } - } - - None - } - /// Reads a `MetaItem` from within an attribute, looks for whether it is a /// `#[doc(include="file")]`, and returns the filename and contents of the file as loaded from /// its expansion. @@ -893,10 +870,11 @@ impl Attributes { diagnostic: &::rustc_errors::Handler, attrs: &[ast::Attribute], additional_attrs: Option<(&[ast::Attribute], DefId)>, + doc_cfg_active: bool, + hidden_cfg: &FxHashSet, ) -> Attributes { let mut doc_strings: Vec = vec![]; let mut sp = None; - let mut cfg = Cfg::True; let mut doc_line = 0; fn update_need_backline(doc_strings: &mut Vec, frag: &DocFragment) { @@ -943,36 +921,27 @@ impl Attributes { if sp.is_none() { sp = Some(attr.span); } - None - } else { - if attr.has_name(sym::doc) { - if let Some(mi) = attr.meta() { - if let Some(cfg_mi) = Attributes::extract_cfg(&mi) { - // Extracted #[doc(cfg(...))] - match Cfg::parse(cfg_mi) { - Ok(new_cfg) => cfg &= new_cfg, - Err(e) => diagnostic.span_err(e.span, e.msg), - } - } else if let Some((filename, contents)) = Attributes::extract_include(&mi) - { - let line = doc_line; - doc_line += contents.as_str().lines().count(); - let frag = DocFragment { - line, - span: attr.span, - doc: contents, - kind: DocFragmentKind::Include { filename }, - parent_module, - need_backline: false, - indent: 0, - }; - update_need_backline(&mut doc_strings, &frag); - doc_strings.push(frag); - } + return None; + } else if attr.has_name(sym::doc) { + if let Some(mi) = attr.meta() { + if let Some((filename, contents)) = Attributes::extract_include(&mi) { + let line = doc_line; + doc_line += contents.as_str().lines().count(); + let frag = DocFragment { + line, + span: attr.span, + doc: contents, + kind: DocFragmentKind::Include { filename }, + parent_module, + need_backline: false, + indent: 0, + }; + update_need_backline(&mut doc_strings, &frag); + doc_strings.push(frag); } } - Some(attr.clone()) } + Some(attr.clone()) }; // Additional documentation should be shown before the original documentation @@ -984,6 +953,50 @@ impl Attributes { .filter_map(clean_attr) .collect(); + 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 = attrs + .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| diagnostic.span_err(e.span, e.msg)).ok() + }) + .fold(Cfg::True, |cfg, new_cfg| cfg & new_cfg) + } else { + attrs + .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| diagnostic.span_err(e.span, e.msg)).ok() + }) + .filter(|cfg| !hidden_cfg.contains(cfg)) + .fold(Cfg::True, |cfg, new_cfg| cfg & new_cfg) + } + } else { + Cfg::True + }; + // treat #[target_feature(enable = "feat")] attributes as if they were // #[doc(cfg(target_feature = "feat"))] attributes as well for attr in attrs.lists(sym::target_feature) { diff --git a/src/librustdoc/core.rs b/src/librustdoc/core.rs index be7bff1a29c2b..6a4859c6920ca 100644 --- a/src/librustdoc/core.rs +++ b/src/librustdoc/core.rs @@ -32,7 +32,7 @@ use std::rc::Rc; use crate::clean; use crate::clean::inline::build_external_trait; -use crate::clean::{AttributesExt, TraitWithExtraInfo, MAX_DEF_IDX}; +use crate::clean::{cfg::Cfg, AttributesExt, TraitWithExtraInfo, MAX_DEF_IDX}; use crate::config::{Options as RustdocOptions, OutputFormat, RenderOptions}; use crate::formats::cache::Cache; use crate::passes::{self, Condition::*, ConditionalPass}; @@ -84,6 +84,8 @@ crate struct DocContext<'tcx> { crate inlined: FxHashSet, /// Used by `calculate_doc_coverage`. crate output_format: OutputFormat, + /// Cfg that have been hidden via #![doc(cfg_hide(...))] + crate hidden_cfg: FxHashSet, } impl<'tcx> DocContext<'tcx> { @@ -432,6 +434,7 @@ crate fn run_global_ctxt( inlined: FxHashSet::default(), output_format, render_options, + hidden_cfg: FxHashSet::default(), }; // Small hack to force the Sized trait to be present. diff --git a/src/librustdoc/doctest.rs b/src/librustdoc/doctest.rs index 6f6ed0eb68413..20897854a5167 100644 --- a/src/librustdoc/doctest.rs +++ b/src/librustdoc/doctest.rs @@ -1092,8 +1092,15 @@ impl<'a, 'hir, 'tcx> HirCollector<'a, 'hir, 'tcx> { sp: Span, nested: F, ) { + let doc_cfg_active = self.tcx.features().doc_cfg; let attrs = self.tcx.hir().attrs(hir_id); - let mut attrs = Attributes::from_ast(self.sess.diagnostic(), attrs, None); + let mut attrs = Attributes::from_ast( + self.sess.diagnostic(), + attrs, + None, + doc_cfg_active, + &FxHashSet::default(), + ); if let Some(ref cfg) = attrs.cfg { 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 f1d79ab097b9f..a6227d0980ed7 100644 --- a/src/librustdoc/html/render/print_item.rs +++ b/src/librustdoc/html/render/print_item.rs @@ -284,10 +284,13 @@ fn item_module(w: &mut Buffer, cx: &Context<'_>, item: &clean::Item, items: &[cl clean::ImportItem(ref import) => { let (stab, stab_tags) = if let Some(import_def_id) = import.source.did { + let doc_cfg_active = cx.tcx().features().doc_cfg; let import_attrs = Box::new(clean::Attributes::from_ast( cx.tcx().sess().diagnostic(), cx.tcx().get_attrs(import_def_id), None, + doc_cfg_active, + &Default::default(), // TODO: this looks wrong )); // Just need an item with the correct def_id and attrs diff --git a/src/librustdoc/lib.rs b/src/librustdoc/lib.rs index 26aaf0db6f620..05ec059f5bddd 100644 --- a/src/librustdoc/lib.rs +++ b/src/librustdoc/lib.rs @@ -4,6 +4,7 @@ )] #![feature(rustc_private)] #![feature(array_methods)] +#![feature(bool_to_option)] #![feature(box_patterns)] #![feature(box_syntax)] #![feature(in_band_lifetimes)] diff --git a/src/librustdoc/visit_ast.rs b/src/librustdoc/visit_ast.rs index 3538182427a93..cf1fa3e51f1e0 100644 --- a/src/librustdoc/visit_ast.rs +++ b/src/librustdoc/visit_ast.rs @@ -3,6 +3,7 @@ use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_hir as hir; +use rustc_hir::CRATE_HIR_ID; use rustc_hir::def::{DefKind, Res}; use rustc_hir::def_id::DefId; use rustc_hir::Node; @@ -14,7 +15,7 @@ use rustc_span::{self, Span}; use std::mem; -use crate::clean::{self, AttributesExt, NestedAttributesExt}; +use crate::clean::{self, cfg::Cfg, AttributesExt, NestedAttributesExt}; use crate::core; use crate::doctree::*; @@ -71,13 +72,14 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> { } crate fn visit(mut self, krate: &'tcx hir::Crate<'_>) -> Module<'tcx> { + let tcx = self.cx.tcx; let span = krate.item.inner; let mut top_level_module = self.visit_mod_contents( span, &Spanned { span, node: hir::VisibilityKind::Public }, hir::CRATE_HIR_ID, &krate.item, - self.cx.tcx.crate_name, + tcx.crate_name, ); // Attach the crate's exported macros to the top-level module. // In the case of macros 2.0 (`pub macro`), and for built-in `derive`s or attributes as @@ -93,7 +95,6 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> { top_level_module.macros.push((def, None)); continue 'exported_macros; } - let tcx = self.cx.tcx; // Note: this is not the same as `.parent_module()`. Indeed, the latter looks // for the closest module _ancestor_, which is not necessarily a direct parent // (since a direct parent isn't necessarily a module, c.f. #77828). @@ -123,6 +124,27 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> { assert_eq!(cur_mod_def_id, macro_parent_def_id); cur_mod.macros.push((def, None)); } + + self.cx.hidden_cfg = tcx.hir().attrs(CRATE_HIR_ID) + .iter() + .filter(|attr| attr.has_name(sym::doc)) + .flat_map(|attr| attr.meta_item_list().into_iter().flatten()) + .filter(|attr| attr.has_name(sym::cfg_hide)) + .flat_map(|attr| { + attr.meta_item_list() + .unwrap_or(&[]) + .iter() + .filter_map(|attr| { + Some( + Cfg::parse(attr.meta_item()?) + .map_err(|e| self.cx.sess().diagnostic().span_err(e.span, e.msg)) + .ok()?, + ) + }) + .collect::>() + }) + .collect(); + self.cx.cache.exact_paths = self.exact_paths; top_level_module } diff --git a/src/test/rustdoc-ui/feature-gate-doc_cfg_hide.rs b/src/test/rustdoc-ui/feature-gate-doc_cfg_hide.rs new file mode 100644 index 0000000000000..17812018b9b7a --- /dev/null +++ b/src/test/rustdoc-ui/feature-gate-doc_cfg_hide.rs @@ -0,0 +1,7 @@ +#![doc(cfg_hide(test))] +//~^ ERROR `#[doc(cfg_hide)]` is experimental + +#[cfg(not(test))] +pub fn public_fn() {} +#[cfg(test)] +pub fn internal_use_only() {} diff --git a/src/test/rustdoc-ui/feature-gate-doc_cfg_hide.stderr b/src/test/rustdoc-ui/feature-gate-doc_cfg_hide.stderr new file mode 100644 index 0000000000000..ba42c7bbb05bc --- /dev/null +++ b/src/test/rustdoc-ui/feature-gate-doc_cfg_hide.stderr @@ -0,0 +1,14 @@ +error[E0658]: `#[doc(cfg_hide)]` is experimental + --> $DIR/feature-gate-doc_cfg_hide.rs:1:1 + | +LL | #![doc(cfg_hide(test))] + | ^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: see issue #43781 for more information + = help: add `#![feature(doc_cfg_hide)]` to the crate attributes to enable + +error: Compilation failed, aborting rustdoc + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0658`. diff --git a/src/test/rustdoc/doc-cfg-hide.rs b/src/test/rustdoc/doc-cfg-hide.rs new file mode 100644 index 0000000000000..b9d0d32313723 --- /dev/null +++ b/src/test/rustdoc/doc-cfg-hide.rs @@ -0,0 +1,32 @@ +#![crate_name = "oud"] +#![feature(doc_cfg, doc_cfg_hide)] + +#![doc(cfg_hide(feature = "solecism"))] + +// @has 'oud/struct.Solecism.html' +// @count - '//*[@class="stab portability"]' 0 +// compile-flags:--cfg feature="solecism" +#[cfg(feature = "solecism")] +pub struct Solecism; + +// @has 'oud/struct.Scribacious.html' +// @count - '//*[@class="stab portability"]' 1 +// @matches - '//*[@class="stab portability"]' 'crate feature solecism' +#[cfg(feature = "solecism")] +#[doc(cfg(feature = "solecism"))] +pub struct Scribacious; + +// @has 'oud/struct.Hyperdulia.html' +// @count - '//*[@class="stab portability"]' 1 +// @matches - '//*[@class="stab portability"]' 'crate feature hyperdulia' +// compile-flags:--cfg feature="hyperdulia" +#[cfg(feature = "solecism")] +#[cfg(feature = "hyperdulia")] +pub struct Hyperdulia; + +// @has 'oud/struct.Oystercatcher.html' +// @count - '//*[@class="stab portability"]' 1 +// @matches - '//*[@class="stab portability"]' 'crate features solecism and oystercatcher' +// compile-flags:--cfg feature="oystercatcher" +#[cfg(all(feature = "solecism", feature = "oystercatcher"))] +pub struct Oystercatcher; 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 0000000000000..92804d3729bba --- /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 0000000000000..36c2025785d0f --- /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;