Improve code and better check doc(cfg(...)) attributes
This commit is contained in:
@@ -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
|
||||
}
|
||||
|
||||
@@ -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 = ...)]`
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -1150,7 +1150,6 @@ symbols! {
|
||||
hashset_iter_ty,
|
||||
hexagon_target_feature,
|
||||
hidden,
|
||||
hidden_cfg,
|
||||
hide,
|
||||
hint,
|
||||
homogeneous_aggregate,
|
||||
|
||||
@@ -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:?}");
|
||||
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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() {}
|
||||
|
||||
@@ -1,3 +1,55 @@
|
||||
error: `only "hide" or "show" are allowed in "#[doc(auto_cfg(...))]"`
|
||||
--> $DIR/doc-cfg.rs:11:7
|
||||
|
|
||||
LL | #[doc(auto_cfg(42))]
|
||||
| ^^^^^^^^^^^^
|
||||
|
|
||||
= note: `#[deny(invalid_doc_attributes)]` on by default
|
||||
|
||||
error: `#![doc(auto_cfg(hide(...)))]` only accepts identifiers or key/value items
|
||||
--> $DIR/doc-cfg.rs:12:21
|
||||
|
|
||||
LL | #[doc(auto_cfg(hide(true)))]
|
||||
| ^^^^
|
||||
|
||||
error: `#![doc(auto_cfg(hide(...)))]` only accepts identifiers or key/value items
|
||||
--> $DIR/doc-cfg.rs:13:21
|
||||
|
|
||||
LL | #[doc(auto_cfg(hide(42)))]
|
||||
| ^^
|
||||
|
||||
error: `#![doc(auto_cfg(hide(...)))]` only accepts identifiers or key/value items
|
||||
--> $DIR/doc-cfg.rs:14:21
|
||||
|
|
||||
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
|
||||
|
|
||||
LL | #[doc(cfg(foo), cfg(bar))]
|
||||
| ^^^
|
||||
|
|
||||
= help: expected names are: `FALSE` and `test` and 31 more
|
||||
= help: to expect this configuration use `--check-cfg=cfg(foo)`
|
||||
= note: see <https://doc.rust-lang.org/nightly/rustc/check-cfg.html> for more information about checking conditional configuration
|
||||
= note: `#[warn(unexpected_cfgs)]` on by default
|
||||
|
||||
warning: unexpected `cfg` condition name: `bar`
|
||||
--> $DIR/doc-cfg.rs:6:21
|
||||
|
|
||||
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: `cfg` predicate is not specified
|
||||
--> $DIR/doc-cfg.rs:3:7
|
||||
|
|
||||
@@ -22,25 +74,5 @@ error: multiple `cfg` predicates are specified
|
||||
LL | #[doc(cfg(foo, bar))]
|
||||
| ^^^
|
||||
|
||||
warning: unexpected `cfg` condition name: `foo`
|
||||
--> $DIR/doc-cfg.rs:6:11
|
||||
|
|
||||
LL | #[doc(cfg(foo), cfg(bar))]
|
||||
| ^^^
|
||||
|
|
||||
= help: expected names are: `FALSE` and `test` and 31 more
|
||||
= help: to expect this configuration use `--check-cfg=cfg(foo)`
|
||||
= note: see <https://doc.rust-lang.org/nightly/rustc/check-cfg.html> for more information about checking conditional configuration
|
||||
= note: `#[warn(unexpected_cfgs)]` on by default
|
||||
|
||||
warning: unexpected `cfg` condition name: `bar`
|
||||
--> $DIR/doc-cfg.rs:6:21
|
||||
|
|
||||
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: aborting due to 9 previous errors; 2 warnings emitted
|
||||
|
||||
|
||||
6
tests/rustdoc-ui/feature-gate-doc_cfg.rs
Normal file
6
tests/rustdoc-ui/feature-gate-doc_cfg.rs
Normal file
@@ -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
|
||||
63
tests/rustdoc-ui/feature-gate-doc_cfg.stderr
Normal file
63
tests/rustdoc-ui/feature-gate-doc_cfg.stderr
Normal file
@@ -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`.
|
||||
@@ -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() {}
|
||||
@@ -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
|
||||
|
||||
@@ -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))))]
|
||||
|
||||
Reference in New Issue
Block a user