Skip to content

Implement RFC 3631: add rustdoc doc_cfg features #138907

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

Open
wants to merge 16 commits into
base: master
Choose a base branch
from
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion compiler/rustc_ast_passes/src/feature_gate.rs
Original file line number Diff line number Diff line change
@@ -173,7 +173,7 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> {
gate_doc!(
"experimental" {
cfg => doc_cfg
cfg_hide => doc_cfg_hide
auto_cfg => doc_cfg
masked => doc_masked
notable_trait => doc_notable_trait
}
2 changes: 0 additions & 2 deletions compiler/rustc_feature/src/unstable.rs
Original file line number Diff line number Diff line change
@@ -473,8 +473,6 @@ declare_features! (
(unstable, doc_auto_cfg, "1.58.0", Some(43781)),
/// Allows `#[doc(cfg(...))]`.
(unstable, doc_cfg, "1.21.0", Some(43781)),
/// Allows `#[doc(cfg_hide(...))]`.
(unstable, doc_cfg_hide, "1.57.0", Some(43781)),
/// Allows `#[doc(masked)]`.
(unstable, doc_masked, "1.21.0", Some(44027)),
/// Allows `dyn* Trait` objects.
13 changes: 11 additions & 2 deletions compiler/rustc_passes/messages.ftl
Original file line number Diff line number Diff line change
@@ -182,8 +182,17 @@ passes_doc_alias_start_end =
passes_doc_attr_not_crate_level =
`#![doc({$attr_name} = "...")]` isn't allowed as a crate-level attribute

passes_doc_cfg_hide_takes_list =
`#[doc(cfg_hide(...))]` takes a list of attributes
passes_doc_auto_cfg_expects_hide_or_show =
`only "hide" or "show" are allowed in "#[doc(auto_cfg(...))]"`

passes_doc_auto_cfg_hide_show_expects_list =
`#![doc(auto_cfg({$attr_name}(...)))]` expects a list of items

passes_doc_auto_cfg_hide_show_unexpected_item =
`#![doc(auto_cfg({$attr_name}(...)))]` only accepts identifiers or key/value items

passes_doc_auto_cfg_wrong_literal =
`expected boolean for #[doc(auto_cfg = ...)]`

passes_doc_expect_str =
doc {$attr_name} attribute expects a string: #[doc({$attr_name} = "a")]
86 changes: 71 additions & 15 deletions compiler/rustc_passes/src/check_attr.rs
Original file line number Diff line number Diff line change
@@ -9,7 +9,7 @@ use std::cell::Cell;
use std::collections::hash_map::Entry;

use rustc_abi::{Align, ExternAbi, Size};
use rustc_ast::{AttrStyle, LitKind, MetaItemInner, MetaItemKind, MetaItemLit, ast};
use rustc_ast::{AttrStyle, LitKind, MetaItem, MetaItemInner, MetaItemKind, MetaItemLit, ast};
use rustc_attr_data_structures::{AttributeKind, ReprAttr, find_attr};
use rustc_data_structures::fx::FxHashMap;
use rustc_errors::{Applicability, DiagCtxtHandle, IntoDiagArg, MultiSpan, StashKey};
@@ -1307,16 +1307,74 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
}
}

/// Check that the `#![doc(cfg_hide(...))]` attribute only contains a list of attributes.
///
fn check_doc_cfg_hide(&self, meta: &MetaItemInner, hir_id: HirId) {
if meta.meta_item_list().is_none() {
self.tcx.emit_node_span_lint(
INVALID_DOC_ATTRIBUTES,
hir_id,
meta.span(),
errors::DocCfgHideTakesList,
);
/// Check that the `#![doc(auto_cfg(..))]` attribute has expected input.
fn check_doc_auto_cfg(&self, meta: &MetaItem, hir_id: HirId) {
match &meta.kind {
MetaItemKind::Word => {}
MetaItemKind::NameValue(lit) => {
if !matches!(lit.kind, LitKind::Bool(_)) {
self.tcx.emit_node_span_lint(
INVALID_DOC_ATTRIBUTES,
hir_id,
meta.span,
errors::DocAutoCfgWrongLiteral,
);
}
}
MetaItemKind::List(list) => {
for item in list {
let Some(attr_name) = item.name() else {
self.tcx.emit_node_span_lint(
INVALID_DOC_ATTRIBUTES,
hir_id,
meta.span,
errors::DocAutoCfgExpectsHideOrShow,
);
continue;
};
if attr_name != sym::hide && attr_name != sym::show {
self.tcx.emit_node_span_lint(
INVALID_DOC_ATTRIBUTES,
hir_id,
meta.span,
errors::DocAutoCfgExpectsHideOrShow,
);
} else if let Some(list) = item.meta_item_list() {
for item in list {
if item.meta_item_list().is_some() {
self.tcx.emit_node_span_lint(
INVALID_DOC_ATTRIBUTES,
hir_id,
item.span(),
errors::DocAutoCfgHideShowUnexpectedItem {
attr_name: attr_name.as_str(),
},
);
} else if match item {
MetaItemInner::Lit(_) => true,
// We already checked above that it's not a list.
MetaItemInner::MetaItem(meta) => meta.path.segments.len() != 1,
} {
self.tcx.emit_node_span_lint(
INVALID_DOC_ATTRIBUTES,
hir_id,
item.span(),
errors::DocAutoCfgHideShowUnexpectedItem {
attr_name: attr_name.as_str(),
},
);
}
}
} else {
self.tcx.emit_node_span_lint(
INVALID_DOC_ATTRIBUTES,
hir_id,
meta.span,
errors::DocAutoCfgHideShowExpectsList { attr_name: attr_name.as_str() },
);
}
}
}
}
}

@@ -1377,10 +1435,8 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
self.check_attr_crate_level(attr, meta, hir_id);
}

Some(sym::cfg_hide) => {
if self.check_attr_crate_level(attr, meta, hir_id) {
self.check_doc_cfg_hide(meta, hir_id);
}
Some(sym::auto_cfg) => {
self.check_doc_auto_cfg(i_meta, hir_id);
}

Some(sym::inline | sym::no_inline) => {
20 changes: 18 additions & 2 deletions compiler/rustc_passes/src/errors.rs
Original file line number Diff line number Diff line change
@@ -333,8 +333,24 @@ pub(crate) struct DocTestLiteral;
pub(crate) struct DocTestTakesList;

#[derive(LintDiagnostic)]
#[diag(passes_doc_cfg_hide_takes_list)]
pub(crate) struct DocCfgHideTakesList;
#[diag(passes_doc_auto_cfg_wrong_literal)]
pub(crate) struct DocAutoCfgWrongLiteral;

#[derive(LintDiagnostic)]
#[diag(passes_doc_auto_cfg_expects_hide_or_show)]
pub(crate) struct DocAutoCfgExpectsHideOrShow;

#[derive(LintDiagnostic)]
#[diag(passes_doc_auto_cfg_hide_show_expects_list)]
pub(crate) struct DocAutoCfgHideShowExpectsList<'a> {
pub attr_name: &'a str,
}

#[derive(LintDiagnostic)]
#[diag(passes_doc_auto_cfg_hide_show_unexpected_item)]
pub(crate) struct DocAutoCfgHideShowUnexpectedItem<'a> {
pub attr_name: &'a str,
}

#[derive(LintDiagnostic)]
#[diag(passes_doc_test_unknown_any)]
4 changes: 3 additions & 1 deletion compiler/rustc_span/src/symbol.rs
Original file line number Diff line number Diff line change
@@ -540,6 +540,7 @@ symbols! {
attributes,
audit_that,
augmented_assignments,
auto_cfg,
auto_traits,
autodiff_forward,
autodiff_reverse,
@@ -856,7 +857,6 @@ symbols! {
doc_alias,
doc_auto_cfg,
doc_cfg,
doc_cfg_hide,
doc_keyword,
doc_masked,
doc_notable_trait,
@@ -1124,6 +1124,7 @@ symbols! {
hashset_iter_ty,
hexagon_target_feature,
hidden,
hide,
hint,
homogeneous_aggregate,
host,
@@ -1928,6 +1929,7 @@ symbols! {
shl_assign,
shorter_tail_lifetimes,
should_panic,
show,
shr,
shr_assign,
sig_dfl,
10 changes: 1 addition & 9 deletions library/alloc/src/lib.rs
Original file line number Diff line number Diff line change
@@ -64,14 +64,7 @@
issue_tracker_base_url = "https://github.com/rust-lang/rust/issues/",
test(no_crate_inject, attr(allow(unused_variables), deny(warnings)))
)]
#![doc(cfg_hide(
not(test),
no_global_oom_handling,
not(no_global_oom_handling),
not(no_rc),
not(no_sync),
target_has_atomic = "ptr"
))]
#![doc(auto_cfg(hide(no_global_oom_handling, no_rc, no_sync, target_has_atomic = "ptr")))]
#![doc(rust_logo)]
#![feature(rustdoc_internals)]
#![no_std]
@@ -191,7 +184,6 @@
//
// Rustdoc features:
#![feature(doc_cfg)]
#![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
5 changes: 2 additions & 3 deletions library/core/src/lib.rs
Original file line number Diff line number Diff line change
@@ -51,7 +51,7 @@
test(attr(allow(dead_code, deprecated, unused_variables, unused_mut)))
)]
#![doc(rust_logo)]
#![doc(cfg_hide(
#![doc(auto_cfg(hide(
no_fp_fmt_parse,
target_pointer_width = "16",
target_pointer_width = "32",
@@ -71,7 +71,7 @@
target_has_atomic_load_store = "32",
target_has_atomic_load_store = "64",
target_has_atomic_load_store = "ptr",
))]
)))]
#![no_core]
#![rustc_coherence_is_core]
#![rustc_preserve_ub_checks]
@@ -146,7 +146,6 @@
#![feature(decl_macro)]
#![feature(deprecated_suggestion)]
#![feature(doc_cfg)]
#![feature(doc_cfg_hide)]
#![feature(doc_notable_trait)]
#![feature(extern_types)]
#![feature(f128)]
3 changes: 1 addition & 2 deletions library/std/src/lib.rs
Original file line number Diff line number Diff line change
@@ -235,7 +235,7 @@
test(attr(allow(dead_code, deprecated, unused_variables, unused_mut)))
)]
#![doc(rust_logo)]
#![doc(cfg_hide(not(test), no_global_oom_handling, not(no_global_oom_handling)))]
#![doc(auto_cfg(hide(no_global_oom_handling)))]
// Don't link to std. We are std.
#![no_std]
// Tell the compiler to link to either panic_abort or panic_unwind
@@ -286,7 +286,6 @@
#![feature(decl_macro)]
#![feature(deprecated_suggestion)]
#![feature(doc_cfg)]
#![feature(doc_cfg_hide)]
#![feature(doc_masked)]
#![feature(doc_notable_trait)]
#![feature(dropck_eyepatch)]
Loading