Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Stabilize doc_cfg, auto_doc_cfg and cfg_hide features #100883

Closed
2 changes: 0 additions & 2 deletions compiler/rustc_ast_passes/src/feature_gate.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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
);
Expand Down
9 changes: 9 additions & 0 deletions compiler/rustc_error_messages/locales/en-US/passes.ftl
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,15 @@ 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_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

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
Expand Down
7 changes: 7 additions & 0 deletions compiler/rustc_feature/src/accepted.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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).
Expand Down
6 changes: 0 additions & 6 deletions compiler/rustc_feature/src/active.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down
64 changes: 63 additions & 1 deletion compiler/rustc_passes/src/check_attr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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;
Expand Down Expand Up @@ -97,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),
Expand Down Expand Up @@ -936,6 +938,56 @@ 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, seen: &mut FxHashMap<Symbol, Span>) -> bool {
let name = meta.name_or_empty();
if !meta.is_word() {
self.tcx
.sess
.emit_err(errors::DocAutoCfgMalformed { span: meta.span, attr_str: name.as_str() });
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,
hir_id,
meta.span,
errors::DocNoAutoCfgEnabledByDefault,
);
is_valid = false;
}
sym::auto_cfg
} else {
if self.tcx.sess.edition() > Edition::Edition2021 {
self.tcx.emit_spanned_lint(
UNUSED_ATTRIBUTES,
hir_id,
meta.span,
errors::DocAutoCfgEnabledByDefault,
);
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
}

/// Runs various checks on `#[doc]` attributes. Returns `true` if valid.
///
/// `specified_inline` should be initialized to `None` and kept for the scope
Expand All @@ -949,6 +1001,7 @@ impl CheckAttrVisitor<'_> {
target: Target,
specified_inline: &mut Option<(bool, Span)>,
aliases: &mut FxHashMap<String, Span>,
seen: &mut FxHashMap<Symbol, Span>,
) -> bool {
let mut is_valid = true;

Expand Down Expand Up @@ -984,6 +1037,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;
Expand All @@ -1001,6 +1056,11 @@ impl CheckAttrVisitor<'_> {
is_valid = false;
}

sym::auto_cfg | sym::no_auto_cfg
if !self.check_auto_cfg(i_meta, hir_id, seen) => {
is_valid = false;
}

// no_default_passes: deprecated
// passes: deprecated
// plugins: removed, but rustdoc warns about it itself
Expand All @@ -1022,6 +1082,8 @@ impl CheckAttrVisitor<'_> {
| sym::notable_trait
| sym::passes
| sym::plugins
| sym::auto_cfg
| sym::no_auto_cfg
| sym::fake_variadic => {}

sym::test => {
Expand Down
25 changes: 25 additions & 0 deletions compiler/rustc_passes/src/errors.rs
Original file line number Diff line number Diff line change
Expand Up @@ -189,6 +189,31 @@ 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(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;

#[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 {
Expand Down
2 changes: 2 additions & 0 deletions compiler/rustc_span/src/symbol.rs
Original file line number Diff line number Diff line change
Expand Up @@ -405,6 +405,7 @@ symbols! {
attr_literals,
attributes,
augmented_assignments,
auto_cfg,
auto_traits,
automatically_derived,
avx,
Expand Down Expand Up @@ -995,6 +996,7 @@ symbols! {
next,
nll,
no,
no_auto_cfg,
no_builtins,
no_core,
no_coverage,
Expand Down
4 changes: 2 additions & 2 deletions library/alloc/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
4 changes: 2 additions & 2 deletions library/core/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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)]
Expand Down
4 changes: 2 additions & 2 deletions library/std/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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)]
Expand Down
82 changes: 0 additions & 82 deletions src/doc/rustdoc/src/unstable-features.md
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
Loading