diff options
| author | Guillaume Gomez <guillaume1.gomez@gmail.com> | 2025-05-29 18:39:08 +0200 |
|---|---|---|
| committer | Guillaume Gomez <guillaume1.gomez@gmail.com> | 2025-09-27 11:29:49 +0200 |
| commit | 553308b11503eafac6341b82f345bd62b09ba317 (patch) | |
| tree | 0149dbb52ae9088cde28314584b7556227ae58aa | |
| parent | 1561efe41afe40c1afaf3d11316ef754d9a8f9a9 (diff) | |
| download | rust-553308b11503eafac6341b82f345bd62b09ba317.tar.gz rust-553308b11503eafac6341b82f345bd62b09ba317.zip | |
Improve code and better check `doc(cfg(...))` attributes
| -rw-r--r-- | compiler/rustc_ast_passes/src/feature_gate.rs | 1 | ||||
| -rw-r--r-- | compiler/rustc_passes/messages.ftl | 2 | ||||
| -rw-r--r-- | compiler/rustc_passes/src/check_attr.rs | 23 | ||||
| -rw-r--r-- | compiler/rustc_span/src/symbol.rs | 1 | ||||
| -rw-r--r-- | src/librustdoc/clean/inline.rs | 4 | ||||
| -rw-r--r-- | src/librustdoc/clean/types.rs | 89 | ||||
| -rw-r--r-- | tests/rustdoc-ui/doc-cfg.rs | 9 | ||||
| -rw-r--r-- | tests/rustdoc-ui/doc-cfg.stderr | 66 | ||||
| -rw-r--r-- | tests/rustdoc-ui/feature-gate-doc_cfg.rs | 6 | ||||
| -rw-r--r-- | tests/rustdoc-ui/feature-gate-doc_cfg.stderr | 63 | ||||
| -rw-r--r-- | tests/rustdoc-ui/feature-gate-doc_cfg_hide.rs | 8 | ||||
| -rw-r--r-- | tests/rustdoc-ui/feature-gate-doc_cfg_hide.stderr | 10 | ||||
| -rw-r--r-- | tests/rustdoc-ui/lints/doc_cfg_hide.stderr | 2 |
13 files changed, 209 insertions, 75 deletions
diff --git a/compiler/rustc_ast_passes/src/feature_gate.rs b/compiler/rustc_ast_passes/src/feature_gate.rs index 35531378784..608ccfefeb6 100644 --- a/compiler/rustc_ast_passes/src/feature_gate.rs +++ b/compiler/rustc_ast_passes/src/feature_gate.rs @@ -183,6 +183,7 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> { gate_doc!( "experimental" { cfg => doc_cfg + auto_cfg => doc_cfg masked => doc_masked notable_trait => doc_notable_trait } diff --git a/compiler/rustc_passes/messages.ftl b/compiler/rustc_passes/messages.ftl index a9a0f6d8b51..a5ff169e638 100644 --- a/compiler/rustc_passes/messages.ftl +++ b/compiler/rustc_passes/messages.ftl @@ -150,7 +150,7 @@ 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/values items + `#![doc(auto_cfg({$attr_name}(...)))]` only accepts identifiers or key/value items passes_doc_auto_cfg_wrong_literal = `expected boolean for #[doc(auto_cfg = ...)]` diff --git a/compiler/rustc_passes/src/check_attr.rs b/compiler/rustc_passes/src/check_attr.rs index c521467b556..88b49c781e7 100644 --- a/compiler/rustc_passes/src/check_attr.rs +++ b/compiler/rustc_passes/src/check_attr.rs @@ -1176,7 +1176,15 @@ impl<'tcx> CheckAttrVisitor<'tcx> { } MetaItemKind::List(list) => { for item in list { - let Some(attr_name) = item.name() else { continue }; + 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, @@ -1195,6 +1203,19 @@ impl<'tcx> CheckAttrVisitor<'tcx> { 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 { diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index e80a98994db..18c3faed932 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -1150,7 +1150,6 @@ symbols! { hashset_iter_ty, hexagon_target_feature, hidden, - hidden_cfg, hide, hint, homogeneous_aggregate, diff --git a/src/librustdoc/clean/inline.rs b/src/librustdoc/clean/inline.rs index 8ffa6033c9b..8beea0580de 100644 --- a/src/librustdoc/clean/inline.rs +++ b/src/librustdoc/clean/inline.rs @@ -605,6 +605,10 @@ pub(crate) fn build_impl( }); } + // In here, we pass an empty `CfgInfo` because the computation of `cfg` happens later, so it + // doesn't matter at this point. + // + // We need to pass this empty `CfgInfo` because `merge_attrs` is used when computing the `cfg`. let (merged_attrs, cfg) = merge_attrs(cx, load_attrs(cx, did), attrs, &mut CfgInfo::default()); trace!("merged_attrs={merged_attrs:?}"); diff --git a/src/librustdoc/clean/types.rs b/src/librustdoc/clean/types.rs index 545f1ef6da4..605b77109a0 100644 --- a/src/librustdoc/clean/types.rs +++ b/src/librustdoc/clean/types.rs @@ -970,8 +970,10 @@ fn show_hide_show_conflict_error( diag.emit(); } -/// This function checks if a same `cfg` is present in both `auto_cfg(hide(...))` and -/// `auto_cfg(show(...))` on the same item. If so, it emits an error. +/// This functions updates the `hidden_cfg` field of the provided `cfg_info` argument. +/// +/// It also checks if a same `cfg` is present in both `auto_cfg(hide(...))` and +/// `auto_cfg(show(...))` on the same item and emits an error if it's the case. /// /// Because we go through a list of `cfg`s, we keep track of the `cfg`s we saw in `new_show_attrs` /// and in `new_hide_attrs` arguments. @@ -1023,6 +1025,31 @@ pub(crate) fn extract_cfg_from_attrs<'a, I: Iterator<Item = &'a hir::Attribute> Some(item) } + fn check_changed_auto_active_status( + changed_auto_active_status: &mut Option<rustc_span::Span>, + attr: &ast::MetaItem, + cfg_info: &mut CfgInfo, + tcx: TyCtxt<'_>, + new_value: bool, + ) -> bool { + if let Some(first_change) = changed_auto_active_status { + if cfg_info.auto_cfg_active != new_value { + tcx.sess + .dcx() + .struct_span_err( + vec![*first_change, attr.span], + "`auto_cfg` was disabled and enabled more than once on the same item", + ) + .emit(); + return true; + } + } else { + *changed_auto_active_status = Some(attr.span); + } + cfg_info.auto_cfg_active = new_value; + false + } + let mut new_show_attrs = FxHashMap::default(); let mut new_hide_attrs = FxHashMap::default(); @@ -1070,49 +1097,39 @@ pub(crate) fn extract_cfg_from_attrs<'a, I: Iterator<Item = &'a hir::Attribute> }; match &attr.kind { MetaItemKind::Word => { - if let Some(first_change) = changed_auto_active_status { - if !cfg_info.auto_cfg_active { - tcx.sess.dcx().struct_span_err( - vec![first_change, attr.span], - "`auto_cfg` was disabled and enabled more than once on the same item", - ).emit(); - return None; - } - } else { - changed_auto_active_status = Some(attr.span); + if check_changed_auto_active_status( + &mut changed_auto_active_status, + attr, + cfg_info, + tcx, + true, + ) { + return None; } - cfg_info.auto_cfg_active = true; } MetaItemKind::NameValue(lit) => { if let LitKind::Bool(value) = lit.kind { - if let Some(first_change) = changed_auto_active_status { - if cfg_info.auto_cfg_active != value { - tcx.sess.dcx().struct_span_err( - vec![first_change, attr.span], - "`auto_cfg` was disabled and enabled more than once on the same item", - ).emit(); - return None; - } - } else { - changed_auto_active_status = Some(attr.span); + if check_changed_auto_active_status( + &mut changed_auto_active_status, + attr, + cfg_info, + tcx, + value, + ) { + return None; } - cfg_info.auto_cfg_active = value; } } MetaItemKind::List(sub_attrs) => { - if let Some(first_change) = changed_auto_active_status { - if !cfg_info.auto_cfg_active { - tcx.sess.dcx().struct_span_err( - vec![first_change, attr.span], - "`auto_cfg` was disabled and enabled more than once on the same item", - ).emit(); - return None; - } - } else { - changed_auto_active_status = Some(attr.span); + if check_changed_auto_active_status( + &mut changed_auto_active_status, + attr, + cfg_info, + tcx, + true, + ) { + return None; } - // Whatever happens next, the feature is enabled again. - cfg_info.auto_cfg_active = true; for sub_attr in sub_attrs.iter() { if let Some(ident) = sub_attr.ident() && (ident.name == sym::show || ident.name == sym::hide) diff --git a/tests/rustdoc-ui/doc-cfg.rs b/tests/rustdoc-ui/doc-cfg.rs index 14943bbc341..9840c305290 100644 --- a/tests/rustdoc-ui/doc-cfg.rs +++ b/tests/rustdoc-ui/doc-cfg.rs @@ -8,4 +8,13 @@ //~^^ WARN unexpected `cfg` condition name: `bar` #[doc(cfg())] //~ ERROR #[doc(cfg(foo, bar))] //~ ERROR +#[doc(auto_cfg(42))] //~ ERROR +#[doc(auto_cfg(hide(true)))] //~ ERROR +#[doc(auto_cfg(hide(42)))] //~ ERROR +#[doc(auto_cfg(hide("a")))] //~ ERROR +#[doc(auto_cfg(hide(foo::bar)))] //~ ERROR +// Shouldn't lint +#[doc(auto_cfg(hide(windows)))] +#[doc(auto_cfg(hide(feature = "windows")))] +#[doc(auto_cfg(hide(foo)))] pub fn foo() {} diff --git a/tests/rustdoc-ui/doc-cfg.stderr b/tests/rustdoc-ui/doc-cfg.stderr index 1233ee010de..36ca18eed8f 100644 --- a/tests/rustdoc-ui/doc-cfg.stderr +++ b/tests/rustdoc-ui/doc-cfg.stderr @@ -1,26 +1,34 @@ -error: `cfg` predicate is not specified - --> $DIR/doc-cfg.rs:3:7 +error: `only "hide" or "show" are allowed in "#[doc(auto_cfg(...))]"` + --> $DIR/doc-cfg.rs:11:7 | -LL | #[doc(cfg(), cfg(foo, bar))] - | ^^^^^ help: expected syntax is: `cfg(/* predicate */)` +LL | #[doc(auto_cfg(42))] + | ^^^^^^^^^^^^ + | + = note: `#[deny(invalid_doc_attributes)]` on by default -error: multiple `cfg` predicates are specified - --> $DIR/doc-cfg.rs:3:23 +error: `#![doc(auto_cfg(hide(...)))]` only accepts identifiers or key/value items + --> $DIR/doc-cfg.rs:12:21 | -LL | #[doc(cfg(), cfg(foo, bar))] - | ^^^ +LL | #[doc(auto_cfg(hide(true)))] + | ^^^^ -error: `cfg` predicate is not specified - --> $DIR/doc-cfg.rs:9:7 +error: `#![doc(auto_cfg(hide(...)))]` only accepts identifiers or key/value items + --> $DIR/doc-cfg.rs:13:21 | -LL | #[doc(cfg())] - | ^^^^^ help: expected syntax is: `cfg(/* predicate */)` +LL | #[doc(auto_cfg(hide(42)))] + | ^^ -error: multiple `cfg` predicates are specified - --> $DIR/doc-cfg.rs:10:16 +error: `#![doc(auto_cfg(hide(...)))]` only accepts identifiers or key/value items + --> $DIR/doc-cfg.rs:14:21 | -LL | #[doc(cfg(foo, bar))] - | ^^^ +LL | #[doc(auto_cfg(hide("a")))] + | ^^^ + +error: `#![doc(auto_cfg(hide(...)))]` only accepts identifiers or key/value items + --> $DIR/doc-cfg.rs:15:21 + | +LL | #[doc(auto_cfg(hide(foo::bar)))] + | ^^^^^^^^ warning: unexpected `cfg` condition name: `foo` --> $DIR/doc-cfg.rs:6:11 @@ -42,5 +50,29 @@ LL | #[doc(cfg(foo), cfg(bar))] = help: to expect this configuration use `--check-cfg=cfg(bar)` = note: see <https://doc.rust-lang.org/nightly/rustc/check-cfg.html> for more information about checking conditional configuration -error: aborting due to 4 previous errors; 2 warnings emitted +error: `cfg` predicate is not specified + --> $DIR/doc-cfg.rs:3:7 + | +LL | #[doc(cfg(), cfg(foo, bar))] + | ^^^^^ help: expected syntax is: `cfg(/* predicate */)` + +error: multiple `cfg` predicates are specified + --> $DIR/doc-cfg.rs:3:23 + | +LL | #[doc(cfg(), cfg(foo, bar))] + | ^^^ + +error: `cfg` predicate is not specified + --> $DIR/doc-cfg.rs:9:7 + | +LL | #[doc(cfg())] + | ^^^^^ help: expected syntax is: `cfg(/* predicate */)` + +error: multiple `cfg` predicates are specified + --> $DIR/doc-cfg.rs:10:16 + | +LL | #[doc(cfg(foo, bar))] + | ^^^ + +error: aborting due to 9 previous errors; 2 warnings emitted diff --git a/tests/rustdoc-ui/feature-gate-doc_cfg.rs b/tests/rustdoc-ui/feature-gate-doc_cfg.rs new file mode 100644 index 00000000000..b474a1524bc --- /dev/null +++ b/tests/rustdoc-ui/feature-gate-doc_cfg.rs @@ -0,0 +1,6 @@ +#![doc(auto_cfg)] //~ ERROR +#![doc(auto_cfg(false))] //~ ERROR +#![doc(auto_cfg(true))] //~ ERROR +#![doc(auto_cfg(hide(feature = "solecism")))] //~ ERROR +#![doc(auto_cfg(show(feature = "bla")))] //~ ERROR +#![doc(cfg(feature = "solecism"))] //~ ERROR diff --git a/tests/rustdoc-ui/feature-gate-doc_cfg.stderr b/tests/rustdoc-ui/feature-gate-doc_cfg.stderr new file mode 100644 index 00000000000..68a86c1abb7 --- /dev/null +++ b/tests/rustdoc-ui/feature-gate-doc_cfg.stderr @@ -0,0 +1,63 @@ +error[E0658]: `#[doc(auto_cfg)]` is experimental + --> $DIR/feature-gate-doc_cfg.rs:1:1 + | +LL | #![doc(auto_cfg)] + | ^^^^^^^^^^^^^^^^^ + | + = note: see issue #43781 <https://github.com/rust-lang/rust/issues/43781> for more information + = help: add `#![feature(doc_cfg)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + +error[E0658]: `#[doc(auto_cfg)]` is experimental + --> $DIR/feature-gate-doc_cfg.rs:2:1 + | +LL | #![doc(auto_cfg(false))] + | ^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: see issue #43781 <https://github.com/rust-lang/rust/issues/43781> for more information + = help: add `#![feature(doc_cfg)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + +error[E0658]: `#[doc(auto_cfg)]` is experimental + --> $DIR/feature-gate-doc_cfg.rs:3:1 + | +LL | #![doc(auto_cfg(true))] + | ^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: see issue #43781 <https://github.com/rust-lang/rust/issues/43781> for more information + = help: add `#![feature(doc_cfg)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + +error[E0658]: `#[doc(auto_cfg)]` is experimental + --> $DIR/feature-gate-doc_cfg.rs:4:1 + | +LL | #![doc(auto_cfg(hide(feature = "solecism")))] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: see issue #43781 <https://github.com/rust-lang/rust/issues/43781> for more information + = help: add `#![feature(doc_cfg)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + +error[E0658]: `#[doc(auto_cfg)]` is experimental + --> $DIR/feature-gate-doc_cfg.rs:5:1 + | +LL | #![doc(auto_cfg(show(feature = "bla")))] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: see issue #43781 <https://github.com/rust-lang/rust/issues/43781> for more information + = help: add `#![feature(doc_cfg)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + +error[E0658]: `#[doc(cfg)]` is experimental + --> $DIR/feature-gate-doc_cfg.rs:6:1 + | +LL | #![doc(cfg(feature = "solecism"))] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: see issue #43781 <https://github.com/rust-lang/rust/issues/43781> for more information + = help: add `#![feature(doc_cfg)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + +error: aborting due to 6 previous errors + +For more information about this error, try `rustc --explain E0658`. diff --git a/tests/rustdoc-ui/feature-gate-doc_cfg_hide.rs b/tests/rustdoc-ui/feature-gate-doc_cfg_hide.rs deleted file mode 100644 index e49285a01b8..00000000000 --- a/tests/rustdoc-ui/feature-gate-doc_cfg_hide.rs +++ /dev/null @@ -1,8 +0,0 @@ -// FIXME: Remove this file once feature is removed - -#![doc(cfg_hide(test))] //~ ERROR - -#[cfg(not(test))] -pub fn public_fn() {} -#[cfg(test)] -pub fn internal_use_only() {} diff --git a/tests/rustdoc-ui/feature-gate-doc_cfg_hide.stderr b/tests/rustdoc-ui/feature-gate-doc_cfg_hide.stderr deleted file mode 100644 index b3eee2af7f7..00000000000 --- a/tests/rustdoc-ui/feature-gate-doc_cfg_hide.stderr +++ /dev/null @@ -1,10 +0,0 @@ -error: unknown `doc` attribute `cfg_hide` - --> $DIR/feature-gate-doc_cfg_hide.rs:3:8 - | -LL | #![doc(cfg_hide(test))] - | ^^^^^^^^^^^^^^ - | - = note: `#[deny(invalid_doc_attributes)]` on by default - -error: aborting due to 1 previous error - diff --git a/tests/rustdoc-ui/lints/doc_cfg_hide.stderr b/tests/rustdoc-ui/lints/doc_cfg_hide.stderr index 9e820a77b5e..c63c8d607fa 100644 --- a/tests/rustdoc-ui/lints/doc_cfg_hide.stderr +++ b/tests/rustdoc-ui/lints/doc_cfg_hide.stderr @@ -12,7 +12,7 @@ error: `#![doc(auto_cfg(hide(...)))]` expects a list of items LL | #![doc(auto_cfg(hide))] | ^^^^^^^^^^^^^^ -error: `#![doc(auto_cfg(hide(...)))]` only accepts identifiers or key/values items +error: `#![doc(auto_cfg(hide(...)))]` only accepts identifiers or key/value items --> $DIR/doc_cfg_hide.rs:4:22 | LL | #![doc(auto_cfg(hide(not(windows))))] |
