From f6305dda38748c087474f2d129b58ddf7b29987e Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Mon, 22 Aug 2022 17:23:51 +0200 Subject: [PATCH 1/7] Stabilize doc_cfg, doc_auto_cfg and doc_cfg_hide features --- compiler/rustc_ast_passes/src/feature_gate.rs | 2 - compiler/rustc_feature/src/accepted.rs | 7 ++ compiler/rustc_feature/src/active.rs | 6 -- library/alloc/src/lib.rs | 4 +- library/core/src/lib.rs | 4 +- library/std/src/lib.rs | 4 +- src/doc/rustdoc/src/unstable-features.md | 82 ------------------- .../write-documentation/the-doc-attribute.md | 58 +++++++++++++ .../src/language-features/doc-cfg.md | 46 ----------- src/librustdoc/clean/types.rs | 40 ++++----- src/test/rustdoc-gui/src/lib2/lib.rs | 2 - src/test/rustdoc-gui/src/test_docs/lib.rs | 1 - src/test/rustdoc-ui/doc-cfg.rs | 2 - src/test/rustdoc-ui/doc-cfg.stderr | 8 +- .../rustdoc-ui/doc-test-rustdoc-feature.rs | 3 - .../doc-test-rustdoc-feature.stdout | 2 +- .../rustdoc-ui/feature-gate-doc_cfg_hide.rs | 7 -- .../feature-gate-doc_cfg_hide.stderr | 14 ---- src/test/rustdoc-ui/invalid-cfg.rs | 1 - src/test/rustdoc-ui/invalid-cfg.stderr | 4 +- src/test/rustdoc/doc-auto-cfg.rs | 1 - src/test/rustdoc/doc-cfg-hide.rs | 1 - src/test/rustdoc/doc-cfg-implicit-gate.rs | 2 +- src/test/rustdoc/doc-cfg-implicit.rs | 1 - src/test/rustdoc/doc-cfg-simplification.rs | 1 - src/test/rustdoc/doc-cfg-target-feature.rs | 2 - src/test/rustdoc/doc-cfg-traits.rs | 2 +- src/test/rustdoc/doc-cfg.rs | 1 - src/test/rustdoc/duplicate-cfg.rs | 1 - src/test/rustdoc/feature-gate-doc_auto_cfg.rs | 2 - src/test/rustdoc/issue-79201.rs | 2 - ...ability-tags-deprecated-and-portability.rs | 1 - ...stability-tags-unstable-and-portability.rs | 1 - .../ui/feature-gates/feature-gate-doc_cfg.rs | 2 - .../feature-gates/feature-gate-doc_cfg.stderr | 12 --- src/tools/rustfmt/tests/source/cfg_if/lib.rs | 2 +- src/tools/rustfmt/tests/target/cfg_if/lib.rs | 2 +- 37 files changed, 97 insertions(+), 236 deletions(-) delete mode 100644 src/doc/unstable-book/src/language-features/doc-cfg.md delete mode 100644 src/test/rustdoc-ui/feature-gate-doc_cfg_hide.rs delete mode 100644 src/test/rustdoc-ui/feature-gate-doc_cfg_hide.stderr delete mode 100644 src/test/ui/feature-gates/feature-gate-doc_cfg.rs delete mode 100644 src/test/ui/feature-gates/feature-gate-doc_cfg.stderr diff --git a/compiler/rustc_ast_passes/src/feature_gate.rs b/compiler/rustc_ast_passes/src/feature_gate.rs index 0017a28cf1b18..22fa7c4a9a79e 100644 --- a/compiler/rustc_ast_passes/src/feature_gate.rs +++ b/compiler/rustc_ast_passes/src/feature_gate.rs @@ -200,8 +200,6 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> { }} gate_doc!( - cfg => doc_cfg - cfg_hide => doc_cfg_hide masked => doc_masked notable_trait => doc_notable_trait ); diff --git a/compiler/rustc_feature/src/accepted.rs b/compiler/rustc_feature/src/accepted.rs index 5f7de94e72657..46a84ed346085 100644 --- a/compiler/rustc_feature/src/accepted.rs +++ b/compiler/rustc_feature/src/accepted.rs @@ -132,6 +132,13 @@ declare_features! ( (accepted, destructuring_assignment, "1.59.0", Some(71126), None), /// Allows `#[doc(alias = "...")]`. (accepted, doc_alias, "1.48.0", Some(50146), None), + /// Tells rustdoc to automatically generate `#[doc(cfg(...))]`. + (accepted, doc_auto_cfg, "1.65.0", Some(43781), None), + /// Allows `#[doc(cfg(...))]`. It adds information about under which condition an item is + /// available. + (accepted, doc_cfg, "1.65.0", Some(43781), None), + /// Allows `#[doc(cfg_hide(...))]`. + (accepted, doc_cfg_hide, "1.65.0", Some(43781), None), /// Allows `..` in tuple (struct) patterns. (accepted, dotdot_in_tuple_patterns, "1.14.0", Some(33627), None), /// Allows `..=` in patterns (RFC 1192). diff --git a/compiler/rustc_feature/src/active.rs b/compiler/rustc_feature/src/active.rs index 4c891fbf16e94..a32924088f525 100644 --- a/compiler/rustc_feature/src/active.rs +++ b/compiler/rustc_feature/src/active.rs @@ -378,12 +378,6 @@ declare_features! ( (active, deprecated_safe, "1.61.0", Some(94978), None), /// Allows having using `suggestion` in the `#[deprecated]` attribute. (active, deprecated_suggestion, "1.61.0", Some(94785), None), - /// Tells rustdoc to automatically generate `#[doc(cfg(...))]`. - (active, doc_auto_cfg, "1.58.0", Some(43781), None), - /// Allows `#[doc(cfg(...))]`. - (active, doc_cfg, "1.21.0", Some(43781), None), - /// Allows `#[doc(cfg_hide(...))]`. - (active, doc_cfg_hide, "1.57.0", Some(43781), None), /// Allows `#[doc(masked)]`. (active, doc_masked, "1.21.0", Some(44027), None), /// Allows `dyn* Trait` objects. diff --git a/library/alloc/src/lib.rs b/library/alloc/src/lib.rs index cadc2f5ad7798..170b389e0d9f6 100644 --- a/library/alloc/src/lib.rs +++ b/library/alloc/src/lib.rs @@ -190,8 +190,8 @@ #![feature(with_negative_coherence)] // // Rustdoc features: -#![feature(doc_cfg)] -#![feature(doc_cfg_hide)] +#![cfg_attr(bootstrap, feature(doc_cfg))] +#![cfg_attr(bootstrap, feature(doc_cfg_hide))] // Technically, this is a bug in rustdoc: rustdoc sees the documentation on `#[lang = slice_alloc]` // blocks is for `&[T]`, which also has documentation using this feature in `core`, and gets mad // that the feature-gate isn't enabled. Ideally, it wouldn't check for the feature gate for docs diff --git a/library/core/src/lib.rs b/library/core/src/lib.rs index a48290ea08ef0..404ecc4905421 100644 --- a/library/core/src/lib.rs +++ b/library/core/src/lib.rs @@ -181,11 +181,11 @@ #![feature(const_refs_to_cell)] #![feature(decl_macro)] #![feature(deprecated_suggestion)] -#![feature(doc_cfg)] +#![cfg_attr(bootstrap, feature(doc_cfg))] +#![cfg_attr(bootstrap, feature(doc_cfg_hide))] #![feature(doc_notable_trait)] #![feature(rustdoc_internals)] #![feature(exhaustive_patterns)] -#![feature(doc_cfg_hide)] #![feature(extern_types)] #![feature(fundamental)] #![feature(if_let_guard)] diff --git a/library/std/src/lib.rs b/library/std/src/lib.rs index 3131dd4726984..544d02b3349c3 100644 --- a/library/std/src/lib.rs +++ b/library/std/src/lib.rs @@ -245,8 +245,8 @@ #![feature(const_trait_impl)] #![feature(decl_macro)] #![feature(deprecated_suggestion)] -#![feature(doc_cfg)] -#![feature(doc_cfg_hide)] +#![cfg_attr(bootstrap, feature(doc_cfg))] +#![cfg_attr(bootstrap, feature(doc_cfg_hide))] #![feature(doc_masked)] #![feature(doc_notable_trait)] #![feature(dropck_eyepatch)] diff --git a/src/doc/rustdoc/src/unstable-features.md b/src/doc/rustdoc/src/unstable-features.md index 32b350074903e..bd14e0e9ac429 100644 --- a/src/doc/rustdoc/src/unstable-features.md +++ b/src/doc/rustdoc/src/unstable-features.md @@ -43,88 +43,6 @@ plain text. These features operate by extending the `#[doc]` attribute, and thus can be caught by the compiler and enabled with a `#![feature(...)]` attribute in your crate. -### `#[doc(cfg)]`: Recording what platforms or features are required for code to be present - - * Tracking issue: [#43781](https://github.com/rust-lang/rust/issues/43781) - -You can use `#[doc(cfg(...))]` to tell Rustdoc exactly which platform items appear on. -This has two effects: - -1. doctests will only run on the appropriate platforms, and -2. When Rustdoc renders documentation for that item, it will be accompanied by a banner explaining - that the item is only available on certain platforms. - -`#[doc(cfg)]` is intended to be used alongside [`#[cfg(doc)]`][cfg-doc]. -For example, `#[cfg(any(windows, doc))]` will preserve the item either on Windows or during the -documentation process. Then, adding a new attribute `#[doc(cfg(windows))]` will tell Rustdoc that -the item is supposed to be used on Windows. For example: - -```rust -#![feature(doc_cfg)] - -/// Token struct that can only be used on Windows. -#[cfg(any(windows, doc))] -#[doc(cfg(windows))] -pub struct WindowsToken; - -/// Token struct that can only be used on Unix. -#[cfg(any(unix, doc))] -#[doc(cfg(unix))] -pub struct UnixToken; - -/// Token struct that is only available with the `serde` feature -#[cfg(feature = "serde")] -#[doc(cfg(feature = "serde"))] -#[derive(serde::Deserialize)] -pub struct SerdeToken; -``` - -In this sample, the tokens will only appear on their respective platforms, but they will both appear -in documentation. - -`#[doc(cfg(...))]` was introduced to be used by the standard library and currently requires the -`#![feature(doc_cfg)]` feature gate. For more information, see [its chapter in the Unstable -Book][unstable-doc-cfg] and [its tracking issue][issue-doc-cfg]. - -### `doc_auto_cfg`: Automatically generate `#[doc(cfg)]` - - * Tracking issue: [#43781](https://github.com/rust-lang/rust/issues/43781) - -`doc_auto_cfg` is an extension to the `#[doc(cfg)]` feature. With it, you don't need to add -`#[doc(cfg(...)]` anymore unless you want to override the default behaviour. So if we take the -previous source code: - -```rust -#![feature(doc_auto_cfg)] - -/// Token struct that can only be used on Windows. -#[cfg(any(windows, doc))] -pub struct WindowsToken; - -/// Token struct that can only be used on Unix. -#[cfg(any(unix, doc))] -pub struct UnixToken; - -/// Token struct that is only available with the `serde` feature -#[cfg(feature = "serde")] -#[derive(serde::Deserialize)] -pub struct SerdeToken; -``` - -It'll render almost the same, the difference being that `doc` will also be displayed. To fix this, -you can use `doc_cfg_hide`: - -```rust -#![feature(doc_cfg_hide)] -#![doc(cfg_hide(doc))] -``` - -And `doc` won't show up anymore! - -[cfg-doc]: ./advanced-features.md -[unstable-doc-cfg]: ../unstable-book/language-features/doc-cfg.html -[issue-doc-cfg]: https://github.com/rust-lang/rust/issues/43781 - ### Adding your trait to the "Notable traits" dialog * Tracking issue: [#45040](https://github.com/rust-lang/rust/issues/45040) diff --git a/src/doc/rustdoc/src/write-documentation/the-doc-attribute.md b/src/doc/rustdoc/src/write-documentation/the-doc-attribute.md index e3b0864899980..e27f909863109 100644 --- a/src/doc/rustdoc/src/write-documentation/the-doc-attribute.md +++ b/src/doc/rustdoc/src/write-documentation/the-doc-attribute.md @@ -276,3 +276,61 @@ To get around this limitation, we just add `#[doc(alias = "lib_name_do_something on the `do_something` method and then it's all good! Users can now look for `lib_name_do_something` in our crate directly and find `Obj::do_something`. + +## `cfg` + +By default, if you use `#[cfg(...)]`: + +```rust +#[cfg(any(windows, doc))] +pub struct WindowsToken; +``` + +`rustdoc` will display this information in the rendered documentation. `#[doc(cfg(...))]` is needed +only if you want to override the default behaviour. + +`#[doc(cfg)]` is intended to be used alongside `#[cfg(doc)]` (described in [advanced features]). +For example, `#[cfg(any(windows, doc))]` will preserve the item either on Windows or during +the documentation process. Then, adding a new attribute `#[doc(cfg(windows))]` will tell Rustdoc +that the item is supposed to be used on Windows. For example: + +```rust +/// Token struct that can only be used on Windows. +#[cfg(any(windows, doc))] +#[doc(cfg(windows))] +pub struct WindowsToken; +/// Token struct that can only be used on Unix. +#[cfg(any(unix, doc))] +#[doc(cfg(unix))] +pub struct UnixToken; +/// Token struct that is only available with the `serde` feature +#[cfg(feature = "serde")] +#[doc(cfg(feature = "serde"))] +#[derive(serde::Deserialize)] +pub struct SerdeToken; +``` + +In this sample, the tokens will only appear on their respective platforms, but they will both appear +in documentation. + +If you want to hide some `cfg` information in your whole crate at once, take a look at `cfg_hide` +just below. + +[advanced features]: ../advanced-features.md + +## `cfg_hide` + +Just like `#[doc(cfg(...))]` can override the default behaviour, `cfg_hide` can completely hide +some `cfg`s to be displayed. For example: + +```rust +#[cfg(unix, feature = "internal-dev-stuff")] +pub struct Foo; +``` + +If you don't want the `internal-dev-stuff` feature to be ever displayed in the generated +documentation, you can add: + +```rust +#![doc(cfg_hide(feature = "internal-dev-stuff"))] +``` diff --git a/src/doc/unstable-book/src/language-features/doc-cfg.md b/src/doc/unstable-book/src/language-features/doc-cfg.md deleted file mode 100644 index b15f5ee66aba1..0000000000000 --- a/src/doc/unstable-book/src/language-features/doc-cfg.md +++ /dev/null @@ -1,46 +0,0 @@ -# `doc_cfg` - -The tracking issue for this feature is: [#43781] - ------- - -The `doc_cfg` feature allows an API be documented as only available in some specific platforms. -This attribute has two effects: - -1. In the annotated item's documentation, there will be a message saying "Available on - (platform) only". - -2. The item's doc-tests will only run on the specific platform. - -In addition to allowing the use of the `#[doc(cfg)]` attribute, this feature enables the use of a -special conditional compilation flag, `#[cfg(doc)]`, set whenever building documentation on your -crate. - -This feature was introduced as part of PR [#43348] to allow the platform-specific parts of the -standard library be documented. - -```rust -#![feature(doc_cfg)] - -#[cfg(any(windows, doc))] -#[doc(cfg(windows))] -/// The application's icon in the notification area (a.k.a. system tray). -/// -/// # Examples -/// -/// ```no_run -/// extern crate my_awesome_ui_library; -/// use my_awesome_ui_library::current_app; -/// use my_awesome_ui_library::windows::notification; -/// -/// let icon = current_app().get::(); -/// icon.show(); -/// icon.show_message("Hello"); -/// ``` -pub struct Icon { - // ... -} -``` - -[#43781]: https://github.com/rust-lang/rust/issues/43781 -[#43348]: https://github.com/rust-lang/rust/issues/43348 diff --git a/src/librustdoc/clean/types.rs b/src/librustdoc/clean/types.rs index f973fd0889ebc..455f013ee5b9b 100644 --- a/src/librustdoc/clean/types.rs +++ b/src/librustdoc/clean/types.rs @@ -873,8 +873,6 @@ impl AttributesExt for [ast::Attribute] { fn cfg(&self, tcx: TyCtxt<'_>, hidden_cfg: &FxHashSet) -> Option> { let sess = tcx.sess; - let doc_cfg_active = tcx.features().doc_cfg; - let doc_auto_cfg_active = tcx.features().doc_auto_cfg; fn single(it: T) -> Option { let mut iter = it.into_iter(); @@ -885,30 +883,22 @@ impl AttributesExt for [ast::Attribute] { Some(item) } - let mut cfg = if doc_cfg_active || doc_auto_cfg_active { - let mut doc_cfg = self - .iter() - .filter(|attr| attr.has_name(sym::doc)) - .flat_map(|attr| attr.meta_item_list().unwrap_or_default()) - .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.meta_item()?).ok()) - .fold(Cfg::True, |cfg, new_cfg| cfg & new_cfg) - } else if doc_auto_cfg_active { - self.iter() - .filter(|attr| attr.has_name(sym::cfg)) - .filter_map(|attr| single(attr.meta_item_list()?)) - .filter_map(|attr| { - Cfg::parse_without(attr.meta_item()?, hidden_cfg).ok().flatten() - }) - .fold(Cfg::True, |cfg, new_cfg| cfg & new_cfg) - } else { - Cfg::True - } + let mut doc_cfg = self + .iter() + .filter(|attr| attr.has_name(sym::doc)) + .flat_map(|attr| attr.meta_item_list().unwrap_or_default()) + .filter(|attr| attr.has_name(sym::cfg)) + .peekable(); + let mut cfg = if doc_cfg.peek().is_some() { + doc_cfg + .filter_map(|attr| Cfg::parse(attr.meta_item()?).ok()) + .fold(Cfg::True, |cfg, new_cfg| cfg & new_cfg) } else { - Cfg::True + self.iter() + .filter(|attr| attr.has_name(sym::cfg)) + .filter_map(|attr| single(attr.meta_item_list()?)) + .filter_map(|attr| Cfg::parse_without(attr.meta_item()?, hidden_cfg).ok().flatten()) + .fold(Cfg::True, |cfg, new_cfg| cfg & new_cfg) }; for attr in self.iter() { diff --git a/src/test/rustdoc-gui/src/lib2/lib.rs b/src/test/rustdoc-gui/src/lib2/lib.rs index 5a151ed7b687a..2655854485bd6 100644 --- a/src/test/rustdoc-gui/src/lib2/lib.rs +++ b/src/test/rustdoc-gui/src/lib2/lib.rs @@ -1,7 +1,5 @@ // ignore-tidy-linelength -#![feature(doc_cfg)] - pub mod another_folder; pub mod another_mod; diff --git a/src/test/rustdoc-gui/src/test_docs/lib.rs b/src/test/rustdoc-gui/src/test_docs/lib.rs index 1c066206c1f21..e048504d5aaf3 100644 --- a/src/test/rustdoc-gui/src/test_docs/lib.rs +++ b/src/test/rustdoc-gui/src/test_docs/lib.rs @@ -4,7 +4,6 @@ #![crate_name = "test_docs"] #![feature(rustdoc_internals)] -#![feature(doc_cfg)] /*! Enable the feature some-feature to enjoy diff --git a/src/test/rustdoc-ui/doc-cfg.rs b/src/test/rustdoc-ui/doc-cfg.rs index 354d76bc3c433..f4b3b76cf6cec 100644 --- a/src/test/rustdoc-ui/doc-cfg.rs +++ b/src/test/rustdoc-ui/doc-cfg.rs @@ -1,5 +1,3 @@ -#![feature(doc_cfg)] - #[doc(cfg(), cfg(foo, bar))] //~^ ERROR //~^^ ERROR diff --git a/src/test/rustdoc-ui/doc-cfg.stderr b/src/test/rustdoc-ui/doc-cfg.stderr index b379f6febe29f..fb16f14fa7d36 100644 --- a/src/test/rustdoc-ui/doc-cfg.stderr +++ b/src/test/rustdoc-ui/doc-cfg.stderr @@ -1,23 +1,23 @@ error: `cfg` predicate is not specified - --> $DIR/doc-cfg.rs:3:7 + --> $DIR/doc-cfg.rs:1:7 | LL | #[doc(cfg(), cfg(foo, bar))] | ^^^^^ error: multiple `cfg` predicates are specified - --> $DIR/doc-cfg.rs:3:23 + --> $DIR/doc-cfg.rs:1:23 | LL | #[doc(cfg(), cfg(foo, bar))] | ^^^ error: `cfg` predicate is not specified - --> $DIR/doc-cfg.rs:7:7 + --> $DIR/doc-cfg.rs:5:7 | LL | #[doc(cfg())] | ^^^^^ error: multiple `cfg` predicates are specified - --> $DIR/doc-cfg.rs:8:16 + --> $DIR/doc-cfg.rs:6:16 | LL | #[doc(cfg(foo, bar))] | ^^^ diff --git a/src/test/rustdoc-ui/doc-test-rustdoc-feature.rs b/src/test/rustdoc-ui/doc-test-rustdoc-feature.rs index bf334c67ecab7..ba25e689ccd73 100644 --- a/src/test/rustdoc-ui/doc-test-rustdoc-feature.rs +++ b/src/test/rustdoc-ui/doc-test-rustdoc-feature.rs @@ -3,12 +3,9 @@ // normalize-stdout-test: "src/test/rustdoc-ui" -> "$$DIR" // normalize-stdout-test "finished in \d+\.\d+s" -> "finished in $$TIME" -#![feature(doc_cfg)] - // Make sure `cfg(doc)` is set when finding doctests but not inside the doctests. /// ``` -/// #![feature(doc_cfg)] /// assert!(!cfg!(doc)); /// ``` #[cfg(doc)] diff --git a/src/test/rustdoc-ui/doc-test-rustdoc-feature.stdout b/src/test/rustdoc-ui/doc-test-rustdoc-feature.stdout index 5b07fc4c87af5..89b88bb650fa5 100644 --- a/src/test/rustdoc-ui/doc-test-rustdoc-feature.stdout +++ b/src/test/rustdoc-ui/doc-test-rustdoc-feature.stdout @@ -1,6 +1,6 @@ running 1 test -test $DIR/doc-test-rustdoc-feature.rs - Foo (line 10) ... ok +test $DIR/doc-test-rustdoc-feature.rs - Foo (line 8) ... ok test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in $TIME diff --git a/src/test/rustdoc-ui/feature-gate-doc_cfg_hide.rs b/src/test/rustdoc-ui/feature-gate-doc_cfg_hide.rs deleted file mode 100644 index 17812018b9b7a..0000000000000 --- a/src/test/rustdoc-ui/feature-gate-doc_cfg_hide.rs +++ /dev/null @@ -1,7 +0,0 @@ -#![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 deleted file mode 100644 index ba42c7bbb05bc..0000000000000 --- a/src/test/rustdoc-ui/feature-gate-doc_cfg_hide.stderr +++ /dev/null @@ -1,14 +0,0 @@ -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-ui/invalid-cfg.rs b/src/test/rustdoc-ui/invalid-cfg.rs index d237b8605c068..fd6a0ee74e39a 100644 --- a/src/test/rustdoc-ui/invalid-cfg.rs +++ b/src/test/rustdoc-ui/invalid-cfg.rs @@ -1,4 +1,3 @@ -#![feature(doc_cfg)] #[doc(cfg = "x")] //~ ERROR not followed by parentheses #[doc(cfg(x, y))] //~ ERROR multiple `cfg` predicates struct S {} diff --git a/src/test/rustdoc-ui/invalid-cfg.stderr b/src/test/rustdoc-ui/invalid-cfg.stderr index dae238b052b8a..165be84b4f01e 100644 --- a/src/test/rustdoc-ui/invalid-cfg.stderr +++ b/src/test/rustdoc-ui/invalid-cfg.stderr @@ -1,11 +1,11 @@ error: `cfg` is not followed by parentheses - --> $DIR/invalid-cfg.rs:2:7 + --> $DIR/invalid-cfg.rs:1:7 | LL | #[doc(cfg = "x")] | ^^^^^^^^^ help: expected syntax is: `cfg(/* predicate */)` error: multiple `cfg` predicates are specified - --> $DIR/invalid-cfg.rs:3:14 + --> $DIR/invalid-cfg.rs:2:14 | LL | #[doc(cfg(x, y))] | ^ diff --git a/src/test/rustdoc/doc-auto-cfg.rs b/src/test/rustdoc/doc-auto-cfg.rs index 7842ee69c9f67..a515d337e0796 100644 --- a/src/test/rustdoc/doc-auto-cfg.rs +++ b/src/test/rustdoc/doc-auto-cfg.rs @@ -1,4 +1,3 @@ -#![feature(doc_auto_cfg)] #![crate_name = "foo"] // @has foo/fn.foo.html diff --git a/src/test/rustdoc/doc-cfg-hide.rs b/src/test/rustdoc/doc-cfg-hide.rs index 636957fe9980d..24662c0362096 100644 --- a/src/test/rustdoc/doc-cfg-hide.rs +++ b/src/test/rustdoc/doc-cfg-hide.rs @@ -1,5 +1,4 @@ #![crate_name = "oud"] -#![feature(doc_auto_cfg, doc_cfg, doc_cfg_hide)] #![doc(cfg_hide(feature = "solecism"))] diff --git a/src/test/rustdoc/doc-cfg-implicit-gate.rs b/src/test/rustdoc/doc-cfg-implicit-gate.rs index 92804d3729bba..b287bfee5f4fd 100644 --- a/src/test/rustdoc/doc-cfg-implicit-gate.rs +++ b/src/test/rustdoc/doc-cfg-implicit-gate.rs @@ -2,6 +2,6 @@ #![crate_name = "xenogenous"] // @has 'xenogenous/struct.Worricow.html' -// @count - '//*[@class="stab portability"]' 0 +// @count - '//*[@class="stab portability"]' 1 #[cfg(feature = "worricow")] pub struct Worricow; diff --git a/src/test/rustdoc/doc-cfg-implicit.rs b/src/test/rustdoc/doc-cfg-implicit.rs index 5d17a4ede6adc..ec6238dbfc305 100644 --- a/src/test/rustdoc/doc-cfg-implicit.rs +++ b/src/test/rustdoc/doc-cfg-implicit.rs @@ -1,5 +1,4 @@ #![crate_name = "funambulism"] -#![feature(doc_auto_cfg, doc_cfg)] // @has 'funambulism/struct.Disorbed.html' // @count - '//*[@class="stab portability"]' 1 diff --git a/src/test/rustdoc/doc-cfg-simplification.rs b/src/test/rustdoc/doc-cfg-simplification.rs index 633df661be026..b42e94a1ee85b 100644 --- a/src/test/rustdoc/doc-cfg-simplification.rs +++ b/src/test/rustdoc/doc-cfg-simplification.rs @@ -1,5 +1,4 @@ #![crate_name = "globuliferous"] -#![feature(doc_cfg)] // @has 'globuliferous/index.html' // @count - '//*[@class="stab portability"]' 1 diff --git a/src/test/rustdoc/doc-cfg-target-feature.rs b/src/test/rustdoc/doc-cfg-target-feature.rs index f1b000dc82362..f65205d5c68a2 100644 --- a/src/test/rustdoc/doc-cfg-target-feature.rs +++ b/src/test/rustdoc/doc-cfg-target-feature.rs @@ -5,8 +5,6 @@ // #49723: rustdoc didn't add target features when extracting or running doctests -#![feature(doc_cfg)] - /// Foo /// /// # Examples diff --git a/src/test/rustdoc/doc-cfg-traits.rs b/src/test/rustdoc/doc-cfg-traits.rs index 13407b2c791fe..2b79c83a667b7 100644 --- a/src/test/rustdoc/doc-cfg-traits.rs +++ b/src/test/rustdoc/doc-cfg-traits.rs @@ -1,5 +1,5 @@ #![crate_name = "myrmecophagous"] -#![feature(doc_cfg, associated_type_defaults)] +#![feature(associated_type_defaults)] // @has 'myrmecophagous/index.html' // @count - '//*[@class="stab portability"]' 2 diff --git a/src/test/rustdoc/doc-cfg.rs b/src/test/rustdoc/doc-cfg.rs index 4cddb0b76d410..6c8dbd305a195 100644 --- a/src/test/rustdoc/doc-cfg.rs +++ b/src/test/rustdoc/doc-cfg.rs @@ -1,4 +1,3 @@ -#![feature(doc_cfg)] #![feature(target_feature, cfg_target_feature)] // @has doc_cfg/struct.Portable.html diff --git a/src/test/rustdoc/duplicate-cfg.rs b/src/test/rustdoc/duplicate-cfg.rs index 18f3900b263b0..b19f712b00aa0 100644 --- a/src/test/rustdoc/duplicate-cfg.rs +++ b/src/test/rustdoc/duplicate-cfg.rs @@ -1,5 +1,4 @@ #![crate_name = "foo"] -#![feature(doc_cfg)] // @has 'foo/index.html' // @matches '-' '//*[@class="item-left module-item"]//*[@class="stab portability"]' '^sync$' diff --git a/src/test/rustdoc/feature-gate-doc_auto_cfg.rs b/src/test/rustdoc/feature-gate-doc_auto_cfg.rs index da76381e48000..dad80088b4ce1 100644 --- a/src/test/rustdoc/feature-gate-doc_auto_cfg.rs +++ b/src/test/rustdoc/feature-gate-doc_auto_cfg.rs @@ -1,5 +1,3 @@ -#![feature(doc_cfg)] - #![crate_name = "foo"] // @has foo/fn.foo.html diff --git a/src/test/rustdoc/issue-79201.rs b/src/test/rustdoc/issue-79201.rs index f95d79cd493ea..0706415303f28 100644 --- a/src/test/rustdoc/issue-79201.rs +++ b/src/test/rustdoc/issue-79201.rs @@ -1,5 +1,3 @@ -#![feature(doc_cfg)] - // @has 'issue_79201/trait.Foo.html' // @count - '//*[@class="stab portability"]' 6 // @matches - '//*[@class="stab portability"]' 'crate feature foo-root' diff --git a/src/test/rustdoc/reexport-stability-tags-deprecated-and-portability.rs b/src/test/rustdoc/reexport-stability-tags-deprecated-and-portability.rs index a79d05904e31c..dc3833ec2f941 100644 --- a/src/test/rustdoc/reexport-stability-tags-deprecated-and-portability.rs +++ b/src/test/rustdoc/reexport-stability-tags-deprecated-and-portability.rs @@ -1,5 +1,4 @@ #![crate_name = "foo"] -#![feature(doc_cfg)] pub mod tag { #[deprecated(since = "0.1.8", note = "Use bar() instead")] diff --git a/src/test/rustdoc/reexport-stability-tags-unstable-and-portability.rs b/src/test/rustdoc/reexport-stability-tags-unstable-and-portability.rs index ff8a910f59f98..fd94ef5dda10c 100644 --- a/src/test/rustdoc/reexport-stability-tags-unstable-and-portability.rs +++ b/src/test/rustdoc/reexport-stability-tags-unstable-and-portability.rs @@ -1,5 +1,4 @@ #![crate_name = "foo"] -#![feature(doc_cfg)] #![feature(staged_api)] #![stable(feature = "rust1", since = "1.0.0")] diff --git a/src/test/ui/feature-gates/feature-gate-doc_cfg.rs b/src/test/ui/feature-gates/feature-gate-doc_cfg.rs deleted file mode 100644 index b12b8a1057182..0000000000000 --- a/src/test/ui/feature-gates/feature-gate-doc_cfg.rs +++ /dev/null @@ -1,2 +0,0 @@ -#[doc(cfg(unix))] //~ ERROR: `#[doc(cfg)]` is experimental -fn main() {} diff --git a/src/test/ui/feature-gates/feature-gate-doc_cfg.stderr b/src/test/ui/feature-gates/feature-gate-doc_cfg.stderr deleted file mode 100644 index fe88e08c12346..0000000000000 --- a/src/test/ui/feature-gates/feature-gate-doc_cfg.stderr +++ /dev/null @@ -1,12 +0,0 @@ -error[E0658]: `#[doc(cfg)]` is experimental - --> $DIR/feature-gate-doc_cfg.rs:1:1 - | -LL | #[doc(cfg(unix))] - | ^^^^^^^^^^^^^^^^^ - | - = note: see issue #43781 for more information - = help: add `#![feature(doc_cfg)]` to the crate attributes to enable - -error: aborting due to previous error - -For more information about this error, try `rustc --explain E0658`. diff --git a/src/tools/rustfmt/tests/source/cfg_if/lib.rs b/src/tools/rustfmt/tests/source/cfg_if/lib.rs index 8b3bb304f1c83..8f9d41ed6e524 100644 --- a/src/tools/rustfmt/tests/source/cfg_if/lib.rs +++ b/src/tools/rustfmt/tests/source/cfg_if/lib.rs @@ -12,7 +12,7 @@ //! * `powerpc64`: [`is_powerpc64_feature_detected`] #![unstable(feature = "stdsimd", issue = "27731")] -#![feature(const_fn, staged_api, stdsimd, doc_cfg, allow_internal_unstable)] +#![feature(const_fn, staged_api, stdsimd, allow_internal_unstable)] #![allow(clippy::shadow_reuse)] #![deny(clippy::missing_inline_in_public_items)] #![cfg_attr(target_os = "linux", feature(linkage))] diff --git a/src/tools/rustfmt/tests/target/cfg_if/lib.rs b/src/tools/rustfmt/tests/target/cfg_if/lib.rs index 8b3bb304f1c83..8f9d41ed6e524 100644 --- a/src/tools/rustfmt/tests/target/cfg_if/lib.rs +++ b/src/tools/rustfmt/tests/target/cfg_if/lib.rs @@ -12,7 +12,7 @@ //! * `powerpc64`: [`is_powerpc64_feature_detected`] #![unstable(feature = "stdsimd", issue = "27731")] -#![feature(const_fn, staged_api, stdsimd, doc_cfg, allow_internal_unstable)] +#![feature(const_fn, staged_api, stdsimd, allow_internal_unstable)] #![allow(clippy::shadow_reuse)] #![deny(clippy::missing_inline_in_public_items)] #![cfg_attr(target_os = "linux", feature(linkage))] From 85795769a3814167e993282b840af9690baec9fb Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Mon, 26 Sep 2022 17:48:42 +0200 Subject: [PATCH 2/7] Add doc(auto_cfg) and doc(no_auto_cfg) attributes --- .../locales/en-US/passes.ftl | 6 +++ compiler/rustc_passes/src/check_attr.rs | 46 +++++++++++++++- compiler/rustc_passes/src/errors.rs | 16 ++++++ compiler/rustc_span/src/symbol.rs | 2 + src/librustdoc/clean/inline.rs | 7 ++- src/librustdoc/clean/mod.rs | 2 +- src/librustdoc/clean/types.rs | 52 ++++++++++++------- src/librustdoc/doctest.rs | 2 +- src/librustdoc/formats/cache.rs | 2 + src/librustdoc/html/render/print_item.rs | 6 ++- src/librustdoc/visit_ast.rs | 17 ++++++ 11 files changed, 134 insertions(+), 24 deletions(-) diff --git a/compiler/rustc_error_messages/locales/en-US/passes.ftl b/compiler/rustc_error_messages/locales/en-US/passes.ftl index 995ad4fe25859..8a5fa8031f4cd 100644 --- a/compiler/rustc_error_messages/locales/en-US/passes.ftl +++ b/compiler/rustc_error_messages/locales/en-US/passes.ftl @@ -75,6 +75,12 @@ passes_doc_alias_not_string_literal = `#[doc(alias("a"))]` expects string litera passes_doc_alias_malformed = doc alias attribute expects a string `#[doc(alias = "a")]` or a list of strings `#[doc(alias("a", "b"))]` +passes_doc_auto_cfg_malformed = `#![doc({$attr_str})]` attribute doesn't expect a value + +passes_doc_no_auto_cfg_enabled_by_default = `doc(no_auto_cfg)` is enabled by default before the 2024 edition + +passes_doc_auto_cfg_enabled_by_default = `doc(auto_cfg)` is enabled by default since the 2024 edition + passes_doc_keyword_empty_mod = `#[doc(keyword = "...")]` should be used on empty modules passes_doc_keyword_not_mod = `#[doc(keyword = "...")]` should be used on modules diff --git a/compiler/rustc_passes/src/check_attr.rs b/compiler/rustc_passes/src/check_attr.rs index a21521ff68b19..1fa6ceff6d91e 100644 --- a/compiler/rustc_passes/src/check_attr.rs +++ b/compiler/rustc_passes/src/check_attr.rs @@ -5,7 +5,7 @@ //! item. use crate::errors; -use rustc_ast::{ast, AttrStyle, Attribute, Lit, LitKind, MetaItemKind, NestedMetaItem}; +use rustc_ast::{ast, AttrStyle, Attribute, Lit, LitKind, MetaItem, MetaItemKind, NestedMetaItem}; use rustc_data_structures::fx::FxHashMap; use rustc_errors::{fluent, struct_span_err, Applicability, MultiSpan}; use rustc_expand::base::resolve_path; @@ -25,6 +25,7 @@ use rustc_session::lint::builtin::{ CONFLICTING_REPR_HINTS, INVALID_DOC_ATTRIBUTES, UNUSED_ATTRIBUTES, }; use rustc_session::parse::feature_err; +use rustc_span::edition::Edition; use rustc_span::symbol::{kw, sym, Symbol}; use rustc_span::{Span, DUMMY_SP}; use rustc_target::spec::abi::Abi; @@ -936,6 +937,40 @@ impl CheckAttrVisitor<'_> { is_valid } + /// Checks that `doc(auto_cfg)` is valid (i.e. no value) and warn if it's used whereas the + /// "equivalent feature" is already enabled. + fn check_auto_cfg(&self, meta: &MetaItem, hir_id: HirId) -> bool { + let name = meta.name_or_empty(); + let mut is_valid = true; + if !meta.is_word() { + self.tcx + .sess + .emit_err(errors::DocAutoCfgMalformed { span: meta.span, attr_str: name.as_str() }); + is_valid = false; + } else if name == sym::no_auto_cfg { + if self.tcx.sess.edition() < Edition::Edition2024 { + self.tcx.emit_spanned_lint( + UNUSED_ATTRIBUTES, + hir_id, + meta.span, + errors::DocNoAutoCfgEnabledByDefault, + ); + is_valid = false; + } + } else { + if self.tcx.sess.edition() > Edition::Edition2021 { + self.tcx.emit_spanned_lint( + UNUSED_ATTRIBUTES, + hir_id, + meta.span, + errors::DocAutoCfgEnabledByDefault, + ); + is_valid = false; + } + } + is_valid + } + /// Runs various checks on `#[doc]` attributes. Returns `true` if valid. /// /// `specified_inline` should be initialized to `None` and kept for the scope @@ -984,6 +1019,8 @@ impl CheckAttrVisitor<'_> { | sym::html_root_url | sym::html_no_source | sym::test + | sym::auto_cfg + | sym::no_auto_cfg if !self.check_attr_crate_level(attr, meta, hir_id) => { is_valid = false; @@ -1001,6 +1038,11 @@ impl CheckAttrVisitor<'_> { is_valid = false; } + sym::auto_cfg | sym::no_auto_cfg + if !self.check_auto_cfg(i_meta, hir_id) => { + is_valid = false; + } + // no_default_passes: deprecated // passes: deprecated // plugins: removed, but rustdoc warns about it itself @@ -1022,6 +1064,8 @@ impl CheckAttrVisitor<'_> { | sym::notable_trait | sym::passes | sym::plugins + | sym::auto_cfg + | sym::no_auto_cfg | sym::fake_variadic => {} sym::test => { diff --git a/compiler/rustc_passes/src/errors.rs b/compiler/rustc_passes/src/errors.rs index cdfa7cf7f93c2..71a5f5ba10490 100644 --- a/compiler/rustc_passes/src/errors.rs +++ b/compiler/rustc_passes/src/errors.rs @@ -189,6 +189,22 @@ pub struct DocAliasMalformed { pub span: Span, } +#[derive(Diagnostic)] +#[diag(passes::doc_auto_cfg_malformed)] +pub struct DocAutoCfgMalformed<'a> { + #[primary_span] + pub span: Span, + pub attr_str: &'a str, +} + +#[derive(LintDiagnostic)] +#[diag(passes::doc_auto_cfg_enabled_by_default)] +pub struct DocAutoCfgEnabledByDefault; + +#[derive(LintDiagnostic)] +#[diag(passes::doc_no_auto_cfg_enabled_by_default)] +pub struct DocNoAutoCfgEnabledByDefault; + #[derive(Diagnostic)] #[diag(passes::doc_keyword_empty_mod)] pub struct DocKeywordEmptyMod { diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index 502ef67fc6767..8adb89ebba02c 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -405,6 +405,7 @@ symbols! { attr_literals, attributes, augmented_assignments, + auto_cfg, auto_traits, automatically_derived, avx, @@ -995,6 +996,7 @@ symbols! { next, nll, no, + no_auto_cfg, no_builtins, no_core, no_coverage, diff --git a/src/librustdoc/clean/inline.rs b/src/librustdoc/clean/inline.rs index c8aa51c3a49a3..416ee661b08c7 100644 --- a/src/librustdoc/clean/inline.rs +++ b/src/librustdoc/clean/inline.rs @@ -318,10 +318,13 @@ pub(crate) fn merge_attrs( } else { Attributes::from_ast(&both) }, - both.cfg(cx.tcx, &cx.cache.hidden_cfg), + both.cfg(cx.tcx, &cx.cache.hidden_cfg, cx.cache.doc_auto_cfg_active), ) } else { - (Attributes::from_ast(&old_attrs), old_attrs.cfg(cx.tcx, &cx.cache.hidden_cfg)) + ( + Attributes::from_ast(&old_attrs), + old_attrs.cfg(cx.tcx, &cx.cache.hidden_cfg, cx.cache.doc_auto_cfg_active), + ) } } diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index bd68dffb823d1..2c96f132229be 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -2076,7 +2076,7 @@ fn clean_extern_crate<'tcx>( item_id: crate_def_id.into(), visibility: clean_visibility(ty_vis), kind: Box::new(ExternCrateItem { src: orig_name }), - cfg: attrs.cfg(cx.tcx, &cx.cache.hidden_cfg), + cfg: attrs.cfg(cx.tcx, &cx.cache.hidden_cfg, cx.cache.doc_auto_cfg_active), }] } diff --git a/src/librustdoc/clean/types.rs b/src/librustdoc/clean/types.rs index 455f013ee5b9b..1753695b50b1a 100644 --- a/src/librustdoc/clean/types.rs +++ b/src/librustdoc/clean/types.rs @@ -470,7 +470,7 @@ impl Item { kind, Box::new(Attributes::from_ast(ast_attrs)), cx, - ast_attrs.cfg(cx.tcx, &cx.cache.hidden_cfg), + ast_attrs.cfg(cx.tcx, &cx.cache.hidden_cfg, cx.cache.doc_auto_cfg_active), ) } @@ -845,7 +845,12 @@ pub(crate) trait AttributesExt { fn inner_docs(&self) -> bool; - fn cfg(&self, tcx: TyCtxt<'_>, hidden_cfg: &FxHashSet) -> Option>; + fn cfg( + &self, + tcx: TyCtxt<'_>, + hidden_cfg: &FxHashSet, + doc_auto_cfg_active: bool, + ) -> Option>; } impl AttributesExt for [ast::Attribute] { @@ -871,7 +876,12 @@ impl AttributesExt for [ast::Attribute] { self.iter().find(|a| a.doc_str().is_some()).map_or(true, |a| a.style == AttrStyle::Inner) } - fn cfg(&self, tcx: TyCtxt<'_>, hidden_cfg: &FxHashSet) -> Option> { + fn cfg( + &self, + tcx: TyCtxt<'_>, + hidden_cfg: &FxHashSet, + doc_auto_cfg_active: bool, + ) -> Option> { let sess = tcx.sess; fn single(it: T) -> Option { @@ -883,22 +893,28 @@ impl AttributesExt for [ast::Attribute] { Some(item) } - let mut doc_cfg = self - .iter() - .filter(|attr| attr.has_name(sym::doc)) - .flat_map(|attr| attr.meta_item_list().unwrap_or_default()) - .filter(|attr| attr.has_name(sym::cfg)) - .peekable(); - let mut cfg = if doc_cfg.peek().is_some() { - doc_cfg - .filter_map(|attr| Cfg::parse(attr.meta_item()?).ok()) - .fold(Cfg::True, |cfg, new_cfg| cfg & new_cfg) - } else { - self.iter() + let mut cfg = if doc_auto_cfg_active { + let mut doc_cfg = self + .iter() + .filter(|attr| attr.has_name(sym::doc)) + .flat_map(|attr| attr.meta_item_list().unwrap_or_default()) .filter(|attr| attr.has_name(sym::cfg)) - .filter_map(|attr| single(attr.meta_item_list()?)) - .filter_map(|attr| Cfg::parse_without(attr.meta_item()?, hidden_cfg).ok().flatten()) - .fold(Cfg::True, |cfg, new_cfg| cfg & new_cfg) + .peekable(); + if doc_cfg.peek().is_some() { + doc_cfg + .filter_map(|attr| Cfg::parse(attr.meta_item()?).ok()) + .fold(Cfg::True, |cfg, new_cfg| cfg & new_cfg) + } else { + self.iter() + .filter(|attr| attr.has_name(sym::cfg)) + .filter_map(|attr| single(attr.meta_item_list()?)) + .filter_map(|attr| { + Cfg::parse_without(attr.meta_item()?, hidden_cfg).ok().flatten() + }) + .fold(Cfg::True, |cfg, new_cfg| cfg & new_cfg) + } + } else { + Cfg::True }; for attr in self.iter() { diff --git a/src/librustdoc/doctest.rs b/src/librustdoc/doctest.rs index 20ae102bc27d3..2cac8dcc93ef1 100644 --- a/src/librustdoc/doctest.rs +++ b/src/librustdoc/doctest.rs @@ -1209,7 +1209,7 @@ impl<'a, 'hir, 'tcx> HirCollector<'a, 'hir, 'tcx> { nested: F, ) { let ast_attrs = self.tcx.hir().attrs(hir_id); - if let Some(ref cfg) = ast_attrs.cfg(self.tcx, &FxHashSet::default()) { + if let Some(ref cfg) = ast_attrs.cfg(self.tcx, &FxHashSet::default(), false) { if !cfg.matches(&self.sess.parse_sess, Some(self.sess.features_untracked())) { return; } diff --git a/src/librustdoc/formats/cache.rs b/src/librustdoc/formats/cache.rs index 86392610d2c28..9cae988509116 100644 --- a/src/librustdoc/formats/cache.rs +++ b/src/librustdoc/formats/cache.rs @@ -121,6 +121,8 @@ pub(crate) struct Cache { pub(crate) intra_doc_links: FxHashMap>, /// Cfg that have been hidden via #![doc(cfg_hide(...))] pub(crate) hidden_cfg: FxHashSet, + /// Whether or not the `#![doc(auto_cfg)]` attribute was used. + pub(crate) doc_auto_cfg_active: bool, } /// This struct is used to wrap the `cache` and `tcx` in order to run `DocFolder`. diff --git a/src/librustdoc/html/render/print_item.rs b/src/librustdoc/html/render/print_item.rs index 3e324bbb069c6..a8fb0a0fbe54a 100644 --- a/src/librustdoc/html/render/print_item.rs +++ b/src/librustdoc/html/render/print_item.rs @@ -351,7 +351,11 @@ fn item_module(w: &mut Buffer, cx: &mut Context<'_>, item: &clean::Item, items: let import_item = clean::Item { item_id: import_def_id.into(), attrs: import_attrs, - cfg: ast_attrs.cfg(cx.tcx(), &cx.cache().hidden_cfg), + cfg: ast_attrs.cfg( + cx.tcx(), + &cx.cache().hidden_cfg, + cx.cache().doc_auto_cfg_active, + ), ..myitem.clone() }; diff --git a/src/librustdoc/visit_ast.rs b/src/librustdoc/visit_ast.rs index e6cef4a326ac0..181fc3422eded 100644 --- a/src/librustdoc/visit_ast.rs +++ b/src/librustdoc/visit_ast.rs @@ -10,6 +10,7 @@ use rustc_hir::CRATE_HIR_ID; use rustc_middle::middle::privacy::AccessLevel; use rustc_middle::ty::TyCtxt; use rustc_span::def_id::{CRATE_DEF_ID, LOCAL_CRATE}; +use rustc_span::edition::Edition; use rustc_span::symbol::{kw, sym, Symbol}; use rustc_span::Span; @@ -146,6 +147,22 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> { .into_iter(), ) .collect(); + // This feature is enabled by default starting the 2024 edition. + self.cx.cache.doc_auto_cfg_active = self.cx.tcx.sess.edition() > Edition::Edition2021; + if let Some(attr) = self + .cx + .tcx + .hir() + .attrs(CRATE_HIR_ID) + .iter() + .filter(|attr| attr.has_name(sym::doc)) + .flat_map(|attr| attr.meta_item_list().into_iter().flatten()) + .find(|attr| attr.has_name(sym::auto_cfg) || attr.has_name(sym::auto_cfg)) + { + // If we find one of the two attributes, we update the default value of + // `doc_auto_cfg_active`. + self.cx.cache.doc_auto_cfg_active = attr.has_name(sym::auto_cfg); + } self.cx.cache.exact_paths = self.exact_paths; top_level_module From 76a96617d996d93b85851f9c8cbe14666acbeb29 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Mon, 26 Sep 2022 17:49:37 +0200 Subject: [PATCH 3/7] Add missing `#![doc(auto_cfg)]` attribute in rustdoc tests --- src/test/rustdoc/doc-auto-cfg.rs | 2 ++ src/test/rustdoc/doc-cfg-hide.rs | 1 + src/test/rustdoc/doc-cfg-implicit-gate.rs | 2 ++ src/test/rustdoc/doc-cfg-implicit.rs | 2 ++ src/test/rustdoc/doc_auto_cfg_nested_impl.rs | 2 ++ 5 files changed, 9 insertions(+) diff --git a/src/test/rustdoc/doc-auto-cfg.rs b/src/test/rustdoc/doc-auto-cfg.rs index a515d337e0796..a00ff002763d6 100644 --- a/src/test/rustdoc/doc-auto-cfg.rs +++ b/src/test/rustdoc/doc-auto-cfg.rs @@ -1,5 +1,7 @@ #![crate_name = "foo"] +#![doc(auto_cfg)] + // @has foo/fn.foo.html // @has - '//*[@class="item-info"]/*[@class="stab portability"]' 'non-meowmeow' #[cfg(not(meowmeow))] diff --git a/src/test/rustdoc/doc-cfg-hide.rs b/src/test/rustdoc/doc-cfg-hide.rs index 24662c0362096..1cd6cf85497d2 100644 --- a/src/test/rustdoc/doc-cfg-hide.rs +++ b/src/test/rustdoc/doc-cfg-hide.rs @@ -1,5 +1,6 @@ #![crate_name = "oud"] +#![doc(auto_cfg)] #![doc(cfg_hide(feature = "solecism"))] // @has 'oud/struct.Solecism.html' diff --git a/src/test/rustdoc/doc-cfg-implicit-gate.rs b/src/test/rustdoc/doc-cfg-implicit-gate.rs index b287bfee5f4fd..481770e098c99 100644 --- a/src/test/rustdoc/doc-cfg-implicit-gate.rs +++ b/src/test/rustdoc/doc-cfg-implicit-gate.rs @@ -1,6 +1,8 @@ // compile-flags:--cfg feature="worricow" #![crate_name = "xenogenous"] +#![doc(auto_cfg)] + // @has 'xenogenous/struct.Worricow.html' // @count - '//*[@class="stab portability"]' 1 #[cfg(feature = "worricow")] diff --git a/src/test/rustdoc/doc-cfg-implicit.rs b/src/test/rustdoc/doc-cfg-implicit.rs index ec6238dbfc305..2e116980e7ab8 100644 --- a/src/test/rustdoc/doc-cfg-implicit.rs +++ b/src/test/rustdoc/doc-cfg-implicit.rs @@ -1,5 +1,7 @@ #![crate_name = "funambulism"] +#![doc(auto_cfg)] + // @has 'funambulism/struct.Disorbed.html' // @count - '//*[@class="stab portability"]' 1 // @matches - '//*[@class="stab portability"]' 'crate feature disorbed' diff --git a/src/test/rustdoc/doc_auto_cfg_nested_impl.rs b/src/test/rustdoc/doc_auto_cfg_nested_impl.rs index 4d73e0d829ad5..0c312ce6cb4b2 100644 --- a/src/test/rustdoc/doc_auto_cfg_nested_impl.rs +++ b/src/test/rustdoc/doc_auto_cfg_nested_impl.rs @@ -4,6 +4,8 @@ #![crate_type = "lib"] #![crate_name = "foo"] +#![doc(auto_cfg)] + pub struct S; pub trait MyTrait1 {} pub trait MyTrait2 {} From 6d9360eb0d2d091fcb990bfa961c84860a87cb75 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Mon, 26 Sep 2022 17:50:28 +0200 Subject: [PATCH 4/7] Add rustdoc-ui test for `doc(auto_cfg)` and `doc(no_auto_cfg)` attributes --- src/librustdoc/visit_ast.rs | 2 +- src/test/rustdoc-ui/doc_no_auto_cfg.rs | 13 +++++ src/test/rustdoc-ui/doc_no_auto_cfg.stderr | 60 ++++++++++++++++++++++ 3 files changed, 74 insertions(+), 1 deletion(-) create mode 100644 src/test/rustdoc-ui/doc_no_auto_cfg.rs create mode 100644 src/test/rustdoc-ui/doc_no_auto_cfg.stderr diff --git a/src/librustdoc/visit_ast.rs b/src/librustdoc/visit_ast.rs index 181fc3422eded..f97812ea76abd 100644 --- a/src/librustdoc/visit_ast.rs +++ b/src/librustdoc/visit_ast.rs @@ -157,7 +157,7 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> { .iter() .filter(|attr| attr.has_name(sym::doc)) .flat_map(|attr| attr.meta_item_list().into_iter().flatten()) - .find(|attr| attr.has_name(sym::auto_cfg) || attr.has_name(sym::auto_cfg)) + .find(|attr| attr.has_name(sym::auto_cfg) || attr.has_name(sym::no_auto_cfg)) { // If we find one of the two attributes, we update the default value of // `doc_auto_cfg_active`. diff --git a/src/test/rustdoc-ui/doc_no_auto_cfg.rs b/src/test/rustdoc-ui/doc_no_auto_cfg.rs new file mode 100644 index 0000000000000..add09802e20b1 --- /dev/null +++ b/src/test/rustdoc-ui/doc_no_auto_cfg.rs @@ -0,0 +1,13 @@ +// edition: 2021 +#![deny(warnings)] +#![doc(no_auto_cfg)] +/*#![doc(no_auto_cfg(1))] //~ ERROR +#![doc(no_auto_cfg = 1)] //~ ERROR +#![doc(auto_cfg(1))] //~ ERROR +#![doc(auto_cfg = 1)] //~ ERROR + +#[doc(auto_cfg)] //~ ERROR +//~^ WARN +#[doc(no_auto_cfg)] //~ ERROR +//~^ WARN +pub struct Bar;*/ diff --git a/src/test/rustdoc-ui/doc_no_auto_cfg.stderr b/src/test/rustdoc-ui/doc_no_auto_cfg.stderr new file mode 100644 index 0000000000000..4e5558d8bd783 --- /dev/null +++ b/src/test/rustdoc-ui/doc_no_auto_cfg.stderr @@ -0,0 +1,60 @@ +error: this attribute can only be applied at the crate level + --> $DIR/doc_no_auto_cfg.rs:9:7 + | +LL | #[doc(auto_cfg)] + | ^^^^^^^^ + | +note: the lint level is defined here + --> $DIR/doc_no_auto_cfg.rs:2:9 + | +LL | #![deny(warnings)] + | ^^^^^^^^ + = note: `#[deny(invalid_doc_attributes)]` implied by `#[deny(warnings)]` + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #82730 + = note: read for more information +help: to apply to the crate, use an inner attribute + | +LL | #![doc(auto_cfg)] + | ~~~~~~~~~~~~~~~~~ + +error: this attribute can only be applied at the crate level + --> $DIR/doc_no_auto_cfg.rs:11:7 + | +LL | #[doc(no_auto_cfg)] + | ^^^^^^^^^^^ + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #82730 + = note: read for more information +help: to apply to the crate, use an inner attribute + | +LL | #![doc(no_auto_cfg)] + | ~~~~~~~~~~~~~~~~~~~~ + +error: `#![doc(no_auto_cfg)]` attribute doesn't expect a value + --> $DIR/doc_no_auto_cfg.rs:4:8 + | +LL | #![doc(no_auto_cfg(1))] + | ^^^^^^^^^^^^^^ + +error: `#![doc(no_auto_cfg)]` attribute doesn't expect a value + --> $DIR/doc_no_auto_cfg.rs:5:8 + | +LL | #![doc(no_auto_cfg = 1)] + | ^^^^^^^^^^^^^^^ + +error: `#![doc(auto_cfg)]` attribute doesn't expect a value + --> $DIR/doc_no_auto_cfg.rs:6:8 + | +LL | #![doc(auto_cfg(1))] + | ^^^^^^^^^^^ + +error: `#![doc(auto_cfg)]` attribute doesn't expect a value + --> $DIR/doc_no_auto_cfg.rs:7:8 + | +LL | #![doc(auto_cfg = 1)] + | ^^^^^^^^^^^^ + +error: aborting due to 6 previous errors + From 6790415be1cb9e41e478308e311b584272011c80 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Mon, 26 Sep 2022 18:14:46 +0200 Subject: [PATCH 5/7] Add documentation for `doc(auto_cfg)` and `doc(no_auto_cfg)` attributes --- .../write-documentation/the-doc-attribute.md | 30 ++++++++++++------- 1 file changed, 20 insertions(+), 10 deletions(-) diff --git a/src/doc/rustdoc/src/write-documentation/the-doc-attribute.md b/src/doc/rustdoc/src/write-documentation/the-doc-attribute.md index e27f909863109..ce404ecf77dce 100644 --- a/src/doc/rustdoc/src/write-documentation/the-doc-attribute.md +++ b/src/doc/rustdoc/src/write-documentation/the-doc-attribute.md @@ -279,16 +279,6 @@ Users can now look for `lib_name_do_something` in our crate directly and find ## `cfg` -By default, if you use `#[cfg(...)]`: - -```rust -#[cfg(any(windows, doc))] -pub struct WindowsToken; -``` - -`rustdoc` will display this information in the rendered documentation. `#[doc(cfg(...))]` is needed -only if you want to override the default behaviour. - `#[doc(cfg)]` is intended to be used alongside `#[cfg(doc)]` (described in [advanced features]). For example, `#[cfg(any(windows, doc))]` will preserve the item either on Windows or during the documentation process. Then, adding a new attribute `#[doc(cfg(windows))]` will tell Rustdoc @@ -316,6 +306,19 @@ in documentation. If you want to hide some `cfg` information in your whole crate at once, take a look at `cfg_hide` just below. +If you want rustdoc to get the `cfg` information directly from the `#[cfg(...)]` attribute, you +need to enable it by using the `#![doc(auto_cfg)]` attribute: + +```rust +#[cfg(any(windows, doc))] +pub struct WindowsToken; +``` + +`rustdoc` will display this information in the rendered documentation. `#[doc(cfg(...))]` is needed +only if you want to override the default behaviour. + +More information about `doc(auto_cfg)` below. + [advanced features]: ../advanced-features.md ## `cfg_hide` @@ -334,3 +337,10 @@ documentation, you can add: ```rust #![doc(cfg_hide(feature = "internal-dev-stuff"))] ``` + +## `auto_cfg`/`no_auto_cfg` + +These two attributes enable/disable the `doc_auto_cfg` feature. You can find more information +about it into the [`cfg`](#cfg) part. + +Please note that this feature is disabled by default before the 2024 edition. From 341b10119e07521a912878b831abab487ec8ce35 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Tue, 27 Sep 2022 19:27:27 +0200 Subject: [PATCH 6/7] Add check for usage of both `doc(auto_cfg)` and `doc(no_auto_cfg)` at the same time --- .../locales/en-US/passes.ftl | 3 ++ compiler/rustc_passes/src/check_attr.rs | 28 +++++++++++++++---- compiler/rustc_passes/src/errors.rs | 9 ++++++ src/librustdoc/core.rs | 1 + 4 files changed, 36 insertions(+), 5 deletions(-) diff --git a/compiler/rustc_error_messages/locales/en-US/passes.ftl b/compiler/rustc_error_messages/locales/en-US/passes.ftl index 8a5fa8031f4cd..cd20d6976aeb2 100644 --- a/compiler/rustc_error_messages/locales/en-US/passes.ftl +++ b/compiler/rustc_error_messages/locales/en-US/passes.ftl @@ -77,6 +77,9 @@ passes_doc_alias_malformed = passes_doc_auto_cfg_malformed = `#![doc({$attr_str})]` attribute doesn't expect a value +passes_doc_both_auto_cfg = please don't specify both `doc(auto_cfg)` and `doc(no_auto_cfg)` + .label = the other is specified here + passes_doc_no_auto_cfg_enabled_by_default = `doc(no_auto_cfg)` is enabled by default before the 2024 edition passes_doc_auto_cfg_enabled_by_default = `doc(auto_cfg)` is enabled by default since the 2024 edition diff --git a/compiler/rustc_passes/src/check_attr.rs b/compiler/rustc_passes/src/check_attr.rs index 1fa6ceff6d91e..cdfb90190c18e 100644 --- a/compiler/rustc_passes/src/check_attr.rs +++ b/compiler/rustc_passes/src/check_attr.rs @@ -98,6 +98,7 @@ impl CheckAttrVisitor<'_> { target, &mut specified_inline, &mut doc_aliases, + &mut seen, ), sym::no_link => self.check_no_link(hir_id, &attr, span, target), sym::export_name => self.check_export_name(hir_id, &attr, span, target), @@ -939,15 +940,16 @@ impl CheckAttrVisitor<'_> { /// Checks that `doc(auto_cfg)` is valid (i.e. no value) and warn if it's used whereas the /// "equivalent feature" is already enabled. - fn check_auto_cfg(&self, meta: &MetaItem, hir_id: HirId) -> bool { + fn check_auto_cfg(&self, meta: &MetaItem, hir_id: HirId, seen: &mut FxHashMap) -> bool { let name = meta.name_or_empty(); - let mut is_valid = true; if !meta.is_word() { self.tcx .sess .emit_err(errors::DocAutoCfgMalformed { span: meta.span, attr_str: name.as_str() }); - is_valid = false; - } else if name == sym::no_auto_cfg { + return false; + } + let mut is_valid = true; + let other = if name == sym::no_auto_cfg { if self.tcx.sess.edition() < Edition::Edition2024 { self.tcx.emit_spanned_lint( UNUSED_ATTRIBUTES, @@ -957,6 +959,7 @@ impl CheckAttrVisitor<'_> { ); is_valid = false; } + sym::auto_cfg } else { if self.tcx.sess.edition() > Edition::Edition2021 { self.tcx.emit_spanned_lint( @@ -967,7 +970,21 @@ impl CheckAttrVisitor<'_> { ); is_valid = false; } + sym::no_auto_cfg + }; + + match seen.entry(other) { + Entry::Occupied(entry) => { + self.tcx + .sess + .emit_err(errors::BothDocAutoCfg { span: *entry.get(), attr_span: meta.span }); + is_valid = false; + } + Entry::Vacant(entry) => { + entry.insert(meta.span); + } } + is_valid } @@ -984,6 +1001,7 @@ impl CheckAttrVisitor<'_> { target: Target, specified_inline: &mut Option<(bool, Span)>, aliases: &mut FxHashMap, + seen: &mut FxHashMap, ) -> bool { let mut is_valid = true; @@ -1039,7 +1057,7 @@ impl CheckAttrVisitor<'_> { } sym::auto_cfg | sym::no_auto_cfg - if !self.check_auto_cfg(i_meta, hir_id) => { + if !self.check_auto_cfg(i_meta, hir_id, seen) => { is_valid = false; } diff --git a/compiler/rustc_passes/src/errors.rs b/compiler/rustc_passes/src/errors.rs index 71a5f5ba10490..ae8194d6ced5b 100644 --- a/compiler/rustc_passes/src/errors.rs +++ b/compiler/rustc_passes/src/errors.rs @@ -197,6 +197,15 @@ pub struct DocAutoCfgMalformed<'a> { pub attr_str: &'a str, } +#[derive(Diagnostic)] +#[diag(passes::doc_both_auto_cfg)] +pub struct BothDocAutoCfg { + #[primary_span] + pub span: Span, + #[label] + pub attr_span: Span, +} + #[derive(LintDiagnostic)] #[diag(passes::doc_auto_cfg_enabled_by_default)] pub struct DocAutoCfgEnabledByDefault; diff --git a/src/librustdoc/core.rs b/src/librustdoc/core.rs index 76562d26a5502..2f3639047f24c 100644 --- a/src/librustdoc/core.rs +++ b/src/librustdoc/core.rs @@ -245,6 +245,7 @@ pub(crate) fn create_config( rustc_lint::builtin::UNEXPECTED_CFGS.name.to_string(), // this lint is needed to support `#[expect]` attributes rustc_lint::builtin::UNFULFILLED_LINT_EXPECTATIONS.name.to_string(), + rustc_lint::builtin::UNUSED_ATTRIBUTES.name.to_string(), ]; lints_to_show.extend(crate::lint::RUSTDOC_LINTS.iter().map(|lint| lint.name.to_string())); From 2d06d6506652c3d0281fccf291c54d22bfe37766 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Tue, 27 Sep 2022 19:27:50 +0200 Subject: [PATCH 7/7] Add tests for duplicated usage of `doc(auto_cfg)` and `doc(no_auto_cfg)` --- src/test/rustdoc-ui/doc_no_auto_cfg.rs | 8 +++-- src/test/rustdoc-ui/doc_no_auto_cfg.stderr | 37 ++++++++++++++++++---- 2 files changed, 35 insertions(+), 10 deletions(-) diff --git a/src/test/rustdoc-ui/doc_no_auto_cfg.rs b/src/test/rustdoc-ui/doc_no_auto_cfg.rs index add09802e20b1..89d9659c76ff4 100644 --- a/src/test/rustdoc-ui/doc_no_auto_cfg.rs +++ b/src/test/rustdoc-ui/doc_no_auto_cfg.rs @@ -1,7 +1,9 @@ // edition: 2021 #![deny(warnings)] -#![doc(no_auto_cfg)] -/*#![doc(no_auto_cfg(1))] //~ ERROR +#![doc(no_auto_cfg)] //~ ERROR +//~^ ERROR +#![doc(auto_cfg, no_auto_cfg)] //~ ERROR +#![doc(no_auto_cfg(1))] //~ ERROR #![doc(no_auto_cfg = 1)] //~ ERROR #![doc(auto_cfg(1))] //~ ERROR #![doc(auto_cfg = 1)] //~ ERROR @@ -10,4 +12,4 @@ //~^ WARN #[doc(no_auto_cfg)] //~ ERROR //~^ WARN -pub struct Bar;*/ +pub struct Bar; diff --git a/src/test/rustdoc-ui/doc_no_auto_cfg.stderr b/src/test/rustdoc-ui/doc_no_auto_cfg.stderr index 4e5558d8bd783..1c3a1d4052923 100644 --- a/src/test/rustdoc-ui/doc_no_auto_cfg.stderr +++ b/src/test/rustdoc-ui/doc_no_auto_cfg.stderr @@ -1,5 +1,5 @@ error: this attribute can only be applied at the crate level - --> $DIR/doc_no_auto_cfg.rs:9:7 + --> $DIR/doc_no_auto_cfg.rs:11:7 | LL | #[doc(auto_cfg)] | ^^^^^^^^ @@ -19,7 +19,7 @@ LL | #![doc(auto_cfg)] | ~~~~~~~~~~~~~~~~~ error: this attribute can only be applied at the crate level - --> $DIR/doc_no_auto_cfg.rs:11:7 + --> $DIR/doc_no_auto_cfg.rs:13:7 | LL | #[doc(no_auto_cfg)] | ^^^^^^^^^^^ @@ -32,29 +32,52 @@ help: to apply to the crate, use an inner attribute LL | #![doc(no_auto_cfg)] | ~~~~~~~~~~~~~~~~~~~~ +error: `doc(no_auto_cfg)` is enabled by default before the 2024 edition + --> $DIR/doc_no_auto_cfg.rs:3:8 + | +LL | #![doc(no_auto_cfg)] + | ^^^^^^^^^^^ + | + = note: `#[deny(unused_attributes)]` implied by `#[deny(warnings)]` + +error: `doc(no_auto_cfg)` is enabled by default before the 2024 edition + --> $DIR/doc_no_auto_cfg.rs:5:18 + | +LL | #![doc(auto_cfg, no_auto_cfg)] + | ^^^^^^^^^^^ + +error: please don't specify both `doc(auto_cfg)` and `doc(no_auto_cfg)` + --> $DIR/doc_no_auto_cfg.rs:3:8 + | +LL | #![doc(no_auto_cfg)] + | ^^^^^^^^^^^ +LL | +LL | #![doc(auto_cfg, no_auto_cfg)] + | ----------- the other is specified here + error: `#![doc(no_auto_cfg)]` attribute doesn't expect a value - --> $DIR/doc_no_auto_cfg.rs:4:8 + --> $DIR/doc_no_auto_cfg.rs:6:8 | LL | #![doc(no_auto_cfg(1))] | ^^^^^^^^^^^^^^ error: `#![doc(no_auto_cfg)]` attribute doesn't expect a value - --> $DIR/doc_no_auto_cfg.rs:5:8 + --> $DIR/doc_no_auto_cfg.rs:7:8 | LL | #![doc(no_auto_cfg = 1)] | ^^^^^^^^^^^^^^^ error: `#![doc(auto_cfg)]` attribute doesn't expect a value - --> $DIR/doc_no_auto_cfg.rs:6:8 + --> $DIR/doc_no_auto_cfg.rs:8:8 | LL | #![doc(auto_cfg(1))] | ^^^^^^^^^^^ error: `#![doc(auto_cfg)]` attribute doesn't expect a value - --> $DIR/doc_no_auto_cfg.rs:7:8 + --> $DIR/doc_no_auto_cfg.rs:9:8 | LL | #![doc(auto_cfg = 1)] | ^^^^^^^^^^^^ -error: aborting due to 6 previous errors +error: aborting due to 9 previous errors