Skip to content

Commit 771318c

Browse files
Remove doc_cfg show/hide conflict error and correctly handle values(any())
1 parent d38a2c9 commit 771318c

7 files changed

Lines changed: 228 additions & 241 deletions

File tree

compiler/rustc_attr_parsing/src/attributes/doc.rs

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -329,17 +329,17 @@ impl DocParser {
329329
kind: LitKind::Str(symbol, _),
330330
span,
331331
..
332-
}) => match &mut cfg_values.values {
333-
DocCfgHideShowValue::Any(any_span) => {
332+
}) => match &mut cfg_values {
333+
DocCfgHideShow::Any(any_span) => {
334334
cx.emit_lint(
335335
rustc_session::lint::builtin::INVALID_DOC_ATTRIBUTES,
336336
DocAutoCfgHideShowValuesMix { value_span: *span },
337337
*any_span,
338338
);
339339
}
340-
DocCfgHideShowValue::List(symbols) => {
340+
DocCfgHideShow::List(symbols) => {
341341
if values_set.insert(symbol) {
342-
symbols.push((*symbol, *span));
342+
symbols.push(DocCfgHideShowValue::new(*symbol, *span));
343343
}
344344
}
345345
},
@@ -358,19 +358,19 @@ impl DocParser {
358358
&& list.mixed().count() == 0
359359
{
360360
if ident.name == sym::any {
361-
if let DocCfgHideShowValue::List(values) = &cfg_values.values
362-
&& let Some((_, span)) = values.first()
361+
if let DocCfgHideShow::List(values) = &cfg_values
362+
&& let Some(value) = values.first()
363363
{
364364
cx.emit_lint(
365365
rustc_session::lint::builtin::INVALID_DOC_ATTRIBUTES,
366-
DocAutoCfgHideShowValuesMix { value_span: *span },
366+
DocAutoCfgHideShowValuesMix { value_span: value.span },
367367
sub_item.span(),
368368
);
369369
} else {
370-
cfg_values.values = DocCfgHideShowValue::Any(sub_item.span());
370+
cfg_values.merge_with(&DocCfgHideShow::Any(sub_item.span()));
371371
}
372372
} else {
373-
cfg_values.only_key = Some(sub_item.span());
373+
cfg_values.push_none(sub_item.span());
374374
}
375375
} else {
376376
cx.emit_lint(

compiler/rustc_hir/src/attrs/data_structures.rs

Lines changed: 38 additions & 68 deletions
Original file line numberDiff line numberDiff line change
@@ -515,98 +515,68 @@ pub enum HideOrShow {
515515
Show,
516516
}
517517

518-
#[derive(Clone, Debug, StableHash, Encodable, Decodable, PrintAttribute, PartialEq)]
519-
pub enum DocCfgHideShowValue {
520-
Any(Span),
521-
List(ThinVec<(Symbol, Span)>),
518+
#[derive(Clone, Copy, Debug, StableHash, Encodable, Decodable, PrintAttribute, PartialEq)]
519+
pub struct DocCfgHideShowValue {
520+
pub span: Span,
521+
/// If `value` is `None`, then it's a `none()` value.
522+
pub value: Option<Symbol>,
522523
}
523524

524-
#[derive(Clone, Debug, StableHash, Encodable, Decodable, PrintAttribute)]
525-
pub struct DocCfgHideShow {
526-
/// If `Some`, then `cfg` without values (like `cfg(windows)`) will be shown/hidden.
527-
/// The `Span` comes from where this value was set.
528-
pub only_key: Option<Span>,
529-
/// The values of this `cfg` to shown/hidden.
530-
pub values: DocCfgHideShowValue,
525+
impl DocCfgHideShowValue {
526+
pub fn new(value: Symbol, span: Span) -> Self {
527+
Self { span, value: Some(value) }
528+
}
529+
530+
pub fn new_none(span: Span) -> Self {
531+
Self { span, value: None }
532+
}
533+
}
534+
535+
#[derive(Clone, Debug, StableHash, Encodable, Decodable, PrintAttribute, PartialEq)]
536+
pub enum DocCfgHideShow {
537+
Any(Span),
538+
List(ThinVec<DocCfgHideShowValue>),
531539
}
532540

533541
impl DocCfgHideShow {
534542
pub fn new() -> Self {
535-
Self { only_key: None, values: DocCfgHideShowValue::List(ThinVec::new()) }
543+
Self::List(ThinVec::new())
536544
}
537545

538546
pub fn new_with_only_key(span: Span) -> Self {
539-
Self { only_key: Some(span), values: DocCfgHideShowValue::List(ThinVec::new()) }
547+
let mut values = ThinVec::with_capacity(1);
548+
values.push(DocCfgHideShowValue { span, value: None });
549+
Self::List(values)
540550
}
541551

542-
pub fn merge_with(&mut self, other: &Self) {
543-
if self.only_key.is_none()
544-
&& let Some(span) = other.only_key
552+
pub fn push_none(&mut self, span: Span) {
553+
if let Self::List(values) = self
554+
&& !values.iter().any(|v| v.value.is_none())
545555
{
546-
self.only_key = Some(span);
556+
values.push(DocCfgHideShowValue { span, value: None });
547557
}
548-
match (&mut self.values, &other.values) {
549-
(DocCfgHideShowValue::Any(_), DocCfgHideShowValue::Any(_)) => {
558+
}
559+
560+
pub fn merge_with(&mut self, other: &Self) {
561+
match (self, other) {
562+
(Self::Any(_), Self::Any(_) | Self::List(_)) => {
550563
// Nothing to do.
551564
}
552-
(_, DocCfgHideShowValue::Any(span)) => {
565+
(s, Self::Any(span)) => {
553566
// We "upgrade" the list values to "all".
554-
self.values = DocCfgHideShowValue::Any(*span);
555-
}
556-
(DocCfgHideShowValue::List(values), DocCfgHideShowValue::List(other_values)) => {
557-
// Having duplicates is not an issue, we simply ignore them. Would be more
558-
// convenient to have a `set` type though. T_T
559-
for (other_symbol, other_span) in other_values {
560-
if !values.iter().any(|(symbol, _)| symbol == other_symbol) {
561-
values.push((*other_symbol, *other_span));
562-
}
563-
}
567+
*s = Self::Any(*span);
564568
}
565-
(DocCfgHideShowValue::Any(_), DocCfgHideShowValue::List(_)) => {
566-
// Nothing to do here either, we already accept all values.
567-
}
568-
}
569-
}
570-
571-
pub fn update_with(&mut self, other: &Self) {
572-
if self.only_key.is_none()
573-
&& let Some(span) = other.only_key
574-
{
575-
self.only_key = Some(span);
576-
}
577-
match (&mut self.values, &other.values) {
578-
(DocCfgHideShowValue::Any(_), _) => {}
579-
(DocCfgHideShowValue::List(_), DocCfgHideShowValue::Any(span)) => {
580-
self.values = DocCfgHideShowValue::Any(*span);
581-
}
582-
(DocCfgHideShowValue::List(values), DocCfgHideShowValue::List(other_values)) => {
569+
(Self::List(values), Self::List(other_values)) => {
583570
// Having duplicates is not an issue, we simply ignore them. Would be more
584571
// convenient to have a `set` type though. T_T
585-
for (other_symbol, other_span) in other_values {
586-
if !values.iter().any(|(symbol, _)| symbol == other_symbol) {
587-
values.push((*other_symbol, *other_span));
572+
for other in other_values {
573+
if !values.iter().any(|value| value.value == other.value) {
574+
values.push(*other);
588575
}
589576
}
590577
}
591578
}
592579
}
593-
594-
pub fn remove_overlap(&mut self, other: &Self) {
595-
if other.only_key.is_some() {
596-
self.only_key = None;
597-
}
598-
match (&mut self.values, &other.values) {
599-
(_, DocCfgHideShowValue::Any(_)) => {
600-
self.values = DocCfgHideShowValue::List(ThinVec::new());
601-
}
602-
(DocCfgHideShowValue::Any(_), DocCfgHideShowValue::List(values)) => {
603-
self.values = DocCfgHideShowValue::List(values.clone());
604-
}
605-
(DocCfgHideShowValue::List(current), DocCfgHideShowValue::List(values)) => {
606-
current.retain(|(name, _)| !values.iter().any(|(other, _)| other == name));
607-
}
608-
}
609-
}
610580
}
611581

612582
#[derive(Clone, Debug, StableHash, Encodable, Decodable, PrintAttribute)]

src/doc/rustdoc/src/unstable-features.md

Lines changed: 20 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -867,26 +867,40 @@ In this case, `#[cfg(feature = "linux")]`, `#[cfg(feature = "something")]`, `#[c
867867
```rust,ignore (nightly)
868868
#[doc(auto_cfg(
869869
hide(feature, values("something")),
870-
hide(target_os, values("linux"))))]
870+
hide(target_os, values("linux")),
871+
))]
872+
```
873+
874+
Now, only `#[cfg(feature = "something")]` and `#[cfg(target_os = "linux")]` will be hidden. If you want to hide a key and all its values, you can use `any()`:
875+
876+
```rust,ignore (nightly)
877+
#[doc(auto_cfg(
878+
hide(feature, values(any())),
879+
))]
871880
```
872881

873-
Now, only `#[cfg(feature = "something")]` and `#[cfg(target_os = "linux")]` will be hidden. If you want to hide all values of a key, you can use `any()`:
882+
If you want to hide only when there is no value you can use `none()`:
874883

875884
```rust,ignore (nightly)
876-
#[doc(auto_cfg(hide(feature, values(any()))))]
885+
#[doc(auto_cfg(
886+
hide(feature, values("something", none())),
887+
))]
877888
```
878889

879-
If you want to hide when there is no value you can use `none()`:
890+
So now, if you want to forbid all values for a key, but allow the key itself, you can do:
880891

881892
```rust,ignore (nightly)
882-
#[doc(auto_cfg(hide(feature, values("something", none()))))]
893+
#[doc(auto_cfg(
894+
hide(feature, values(any())), // We completely hide "feature".
895+
show(feature), // We show again "feature" (but not any value).
896+
))]
883897
```
884898

885899
If the previous example, both `#[cfg(feature)]` and `#[cfg(feature = "something")]` will be hidden.
886900

887901
Rustdoc currently hides `test`, `doc` and `doctest` attributes by default and reserves the right to change the list of "hidden by default" attributes.
888902

889-
The attribute accepts only a list of identifiers or key/value items. So you can write:
903+
The attribute accepts only a list of identifiers and `values()`. So you can write:
890904

891905
```rust,ignore (nightly)
892906
#[doc(auto_cfg(
@@ -916,14 +930,6 @@ However, it only impacts the `unix` cfg, not the feature:
916930
#[cfg(feature = "unix")] // `feature = "unix"` is displayed
917931
```
918932

919-
If `cfg_auto(show(...))` and `cfg_auto(hide(...))` are used to show/hide a same `cfg` on a same item, it'll emit an error. Example:
920-
921-
```rust,ignore (nightly)
922-
#[doc(auto_cfg(hide(unix)))]
923-
#[doc(auto_cfg(show(unix)))] // Error!
924-
pub fn foo() {}
925-
```
926-
927933
Using this attribute will re-enable `auto_cfg` if it was disabled at this location:
928934

929935
```rust,ignore (nightly)
@@ -941,14 +947,6 @@ pub mod module {
941947
}
942948
```
943949

944-
However, using `doc(auto_cfg = ...)` and `doc(auto_cfg(...))` on the same item will emit an error:
945-
946-
```rust,ignore (nightly)
947-
#[doc(auto_cfg = false)]
948-
#[doc(auto_cfg(hide(unix)))] // error
949-
pub fn foo() {}
950-
```
951-
952950
The reason behind this is that `doc(auto_cfg = ...)` enables or disables the feature, whereas `doc(auto_cfg(...))` enables it unconditionally, making the first attribute to appear useless as it will be overidden by the next `doc(auto_cfg)` attribute.
953951

954952
### `#[doc(auto_cfg(show(...)))]`

0 commit comments

Comments
 (0)