Skip to content

Commit 5b75a44

Browse files
Improve code and better check doc(cfg(...)) attributes
1 parent d6a138c commit 5b75a44

File tree

13 files changed

+209
-75
lines changed

13 files changed

+209
-75
lines changed

compiler/rustc_ast_passes/src/feature_gate.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -183,6 +183,7 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> {
183183
gate_doc!(
184184
"experimental" {
185185
cfg => doc_cfg
186+
auto_cfg => doc_cfg
186187
masked => doc_masked
187188
notable_trait => doc_notable_trait
188189
}

compiler/rustc_passes/messages.ftl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -159,7 +159,7 @@ passes_doc_auto_cfg_hide_show_expects_list =
159159
`#![doc(auto_cfg({$attr_name}(...)))]` expects a list of items
160160
161161
passes_doc_auto_cfg_hide_show_unexpected_item =
162-
`#![doc(auto_cfg({$attr_name}(...)))]` only accepts identifiers or key/values items
162+
`#![doc(auto_cfg({$attr_name}(...)))]` only accepts identifiers or key/value items
163163
164164
passes_doc_auto_cfg_wrong_literal =
165165
`expected boolean for #[doc(auto_cfg = ...)]`

compiler/rustc_passes/src/check_attr.rs

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1165,7 +1165,15 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
11651165
}
11661166
MetaItemKind::List(list) => {
11671167
for item in list {
1168-
let Some(attr_name) = item.name() else { continue };
1168+
let Some(attr_name) = item.name() else {
1169+
self.tcx.emit_node_span_lint(
1170+
INVALID_DOC_ATTRIBUTES,
1171+
hir_id,
1172+
meta.span,
1173+
errors::DocAutoCfgExpectsHideOrShow,
1174+
);
1175+
continue;
1176+
};
11691177
if attr_name != sym::hide && attr_name != sym::show {
11701178
self.tcx.emit_node_span_lint(
11711179
INVALID_DOC_ATTRIBUTES,
@@ -1184,6 +1192,19 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
11841192
attr_name: attr_name.as_str(),
11851193
},
11861194
);
1195+
} else if match item {
1196+
MetaItemInner::Lit(_) => true,
1197+
// We already checked above that it's not a list.
1198+
MetaItemInner::MetaItem(meta) => meta.path.segments.len() != 1,
1199+
} {
1200+
self.tcx.emit_node_span_lint(
1201+
INVALID_DOC_ATTRIBUTES,
1202+
hir_id,
1203+
item.span(),
1204+
errors::DocAutoCfgHideShowUnexpectedItem {
1205+
attr_name: attr_name.as_str(),
1206+
},
1207+
);
11871208
}
11881209
}
11891210
} else {

compiler/rustc_span/src/symbol.rs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1149,7 +1149,6 @@ symbols! {
11491149
hashset_iter_ty,
11501150
hexagon_target_feature,
11511151
hidden,
1152-
hidden_cfg,
11531152
hide,
11541153
hint,
11551154
homogeneous_aggregate,

src/librustdoc/clean/inline.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -605,6 +605,10 @@ pub(crate) fn build_impl(
605605
});
606606
}
607607

608+
// In here, we pass an empty `CfgInfo` because the computation of `cfg` happens later, so it
609+
// doesn't matter at this point.
610+
//
611+
// We need to pass this empty `CfgInfo` because `merge_attrs` is used when computing the `cfg`.
608612
let (merged_attrs, cfg) = merge_attrs(cx, load_attrs(cx, did), attrs, &mut CfgInfo::default());
609613
trace!("merged_attrs={merged_attrs:?}");
610614

src/librustdoc/clean/types.rs

Lines changed: 53 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -1089,8 +1089,10 @@ fn show_hide_show_conflict_error(
10891089
diag.emit();
10901090
}
10911091

1092-
/// This function checks if a same `cfg` is present in both `auto_cfg(hide(...))` and
1093-
/// `auto_cfg(show(...))` on the same item. If so, it emits an error.
1092+
/// This functions updates the `hidden_cfg` field of the provided `cfg_info` argument.
1093+
///
1094+
/// It also checks if a same `cfg` is present in both `auto_cfg(hide(...))` and
1095+
/// `auto_cfg(show(...))` on the same item and emits an error if it's the case.
10941096
///
10951097
/// Because we go through a list of `cfg`s, we keep track of the `cfg`s we saw in `new_show_attrs`
10961098
/// and in `new_hide_attrs` arguments.
@@ -1142,6 +1144,31 @@ pub(crate) fn extract_cfg_from_attrs<'a, I: Iterator<Item = &'a hir::Attribute>
11421144
Some(item)
11431145
}
11441146

1147+
fn check_changed_auto_active_status(
1148+
changed_auto_active_status: &mut Option<rustc_span::Span>,
1149+
attr: &ast::MetaItem,
1150+
cfg_info: &mut CfgInfo,
1151+
tcx: TyCtxt<'_>,
1152+
new_value: bool,
1153+
) -> bool {
1154+
if let Some(first_change) = changed_auto_active_status {
1155+
if cfg_info.auto_cfg_active != new_value {
1156+
tcx.sess
1157+
.dcx()
1158+
.struct_span_err(
1159+
vec![*first_change, attr.span],
1160+
"`auto_cfg` was disabled and enabled more than once on the same item",
1161+
)
1162+
.emit();
1163+
return true;
1164+
}
1165+
} else {
1166+
*changed_auto_active_status = Some(attr.span);
1167+
}
1168+
cfg_info.auto_cfg_active = new_value;
1169+
false
1170+
}
1171+
11451172
let mut new_show_attrs = FxHashMap::default();
11461173
let mut new_hide_attrs = FxHashMap::default();
11471174

@@ -1189,49 +1216,39 @@ pub(crate) fn extract_cfg_from_attrs<'a, I: Iterator<Item = &'a hir::Attribute>
11891216
};
11901217
match &attr.kind {
11911218
MetaItemKind::Word => {
1192-
if let Some(first_change) = changed_auto_active_status {
1193-
if !cfg_info.auto_cfg_active {
1194-
tcx.sess.dcx().struct_span_err(
1195-
vec![first_change, attr.span],
1196-
"`auto_cfg` was disabled and enabled more than once on the same item",
1197-
).emit();
1198-
return None;
1199-
}
1200-
} else {
1201-
changed_auto_active_status = Some(attr.span);
1219+
if check_changed_auto_active_status(
1220+
&mut changed_auto_active_status,
1221+
attr,
1222+
cfg_info,
1223+
tcx,
1224+
true,
1225+
) {
1226+
return None;
12021227
}
1203-
cfg_info.auto_cfg_active = true;
12041228
}
12051229
MetaItemKind::NameValue(lit) => {
12061230
if let LitKind::Bool(value) = lit.kind {
1207-
if let Some(first_change) = changed_auto_active_status {
1208-
if cfg_info.auto_cfg_active != value {
1209-
tcx.sess.dcx().struct_span_err(
1210-
vec![first_change, attr.span],
1211-
"`auto_cfg` was disabled and enabled more than once on the same item",
1212-
).emit();
1213-
return None;
1214-
}
1215-
} else {
1216-
changed_auto_active_status = Some(attr.span);
1231+
if check_changed_auto_active_status(
1232+
&mut changed_auto_active_status,
1233+
attr,
1234+
cfg_info,
1235+
tcx,
1236+
value,
1237+
) {
1238+
return None;
12171239
}
1218-
cfg_info.auto_cfg_active = value;
12191240
}
12201241
}
12211242
MetaItemKind::List(sub_attrs) => {
1222-
if let Some(first_change) = changed_auto_active_status {
1223-
if !cfg_info.auto_cfg_active {
1224-
tcx.sess.dcx().struct_span_err(
1225-
vec![first_change, attr.span],
1226-
"`auto_cfg` was disabled and enabled more than once on the same item",
1227-
).emit();
1228-
return None;
1229-
}
1230-
} else {
1231-
changed_auto_active_status = Some(attr.span);
1243+
if check_changed_auto_active_status(
1244+
&mut changed_auto_active_status,
1245+
attr,
1246+
cfg_info,
1247+
tcx,
1248+
true,
1249+
) {
1250+
return None;
12321251
}
1233-
// Whatever happens next, the feature is enabled again.
1234-
cfg_info.auto_cfg_active = true;
12351252
for sub_attr in sub_attrs.iter() {
12361253
if let Some(ident) = sub_attr.ident()
12371254
&& (ident.name == sym::show || ident.name == sym::hide)

tests/rustdoc-ui/doc-cfg.rs

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,4 +8,13 @@
88
//~^^ WARN unexpected `cfg` condition name: `bar`
99
#[doc(cfg())] //~ ERROR
1010
#[doc(cfg(foo, bar))] //~ ERROR
11+
#[doc(auto_cfg(42))] //~ ERROR
12+
#[doc(auto_cfg(hide(true)))] //~ ERROR
13+
#[doc(auto_cfg(hide(42)))] //~ ERROR
14+
#[doc(auto_cfg(hide("a")))] //~ ERROR
15+
#[doc(auto_cfg(hide(foo::bar)))] //~ ERROR
16+
// Shouldn't lint
17+
#[doc(auto_cfg(hide(windows)))]
18+
#[doc(auto_cfg(hide(feature = "windows")))]
19+
#[doc(auto_cfg(hide(foo)))]
1120
pub fn foo() {}

tests/rustdoc-ui/doc-cfg.stderr

Lines changed: 49 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,26 +1,34 @@
1-
error: `cfg` predicate is not specified
2-
--> $DIR/doc-cfg.rs:3:7
1+
error: `only "hide" or "show" are allowed in "#[doc(auto_cfg(...))]"`
2+
--> $DIR/doc-cfg.rs:11:7
33
|
4-
LL | #[doc(cfg(), cfg(foo, bar))]
5-
| ^^^^^ help: expected syntax is: `cfg(/* predicate */)`
4+
LL | #[doc(auto_cfg(42))]
5+
| ^^^^^^^^^^^^
6+
|
7+
= note: `#[deny(invalid_doc_attributes)]` on by default
68

7-
error: multiple `cfg` predicates are specified
8-
--> $DIR/doc-cfg.rs:3:23
9+
error: `#![doc(auto_cfg(hide(...)))]` only accepts identifiers or key/value items
10+
--> $DIR/doc-cfg.rs:12:21
911
|
10-
LL | #[doc(cfg(), cfg(foo, bar))]
11-
| ^^^
12+
LL | #[doc(auto_cfg(hide(true)))]
13+
| ^^^^
1214

13-
error: `cfg` predicate is not specified
14-
--> $DIR/doc-cfg.rs:9:7
15+
error: `#![doc(auto_cfg(hide(...)))]` only accepts identifiers or key/value items
16+
--> $DIR/doc-cfg.rs:13:21
1517
|
16-
LL | #[doc(cfg())]
17-
| ^^^^^ help: expected syntax is: `cfg(/* predicate */)`
18+
LL | #[doc(auto_cfg(hide(42)))]
19+
| ^^
1820

19-
error: multiple `cfg` predicates are specified
20-
--> $DIR/doc-cfg.rs:10:16
21+
error: `#![doc(auto_cfg(hide(...)))]` only accepts identifiers or key/value items
22+
--> $DIR/doc-cfg.rs:14:21
2123
|
22-
LL | #[doc(cfg(foo, bar))]
23-
| ^^^
24+
LL | #[doc(auto_cfg(hide("a")))]
25+
| ^^^
26+
27+
error: `#![doc(auto_cfg(hide(...)))]` only accepts identifiers or key/value items
28+
--> $DIR/doc-cfg.rs:15:21
29+
|
30+
LL | #[doc(auto_cfg(hide(foo::bar)))]
31+
| ^^^^^^^^
2432

2533
warning: unexpected `cfg` condition name: `foo`
2634
--> $DIR/doc-cfg.rs:6:11
@@ -42,5 +50,29 @@ LL | #[doc(cfg(foo), cfg(bar))]
4250
= help: to expect this configuration use `--check-cfg=cfg(bar)`
4351
= note: see <https://doc.rust-lang.org/nightly/rustc/check-cfg.html> for more information about checking conditional configuration
4452

45-
error: aborting due to 4 previous errors; 2 warnings emitted
53+
error: `cfg` predicate is not specified
54+
--> $DIR/doc-cfg.rs:3:7
55+
|
56+
LL | #[doc(cfg(), cfg(foo, bar))]
57+
| ^^^^^ help: expected syntax is: `cfg(/* predicate */)`
58+
59+
error: multiple `cfg` predicates are specified
60+
--> $DIR/doc-cfg.rs:3:23
61+
|
62+
LL | #[doc(cfg(), cfg(foo, bar))]
63+
| ^^^
64+
65+
error: `cfg` predicate is not specified
66+
--> $DIR/doc-cfg.rs:9:7
67+
|
68+
LL | #[doc(cfg())]
69+
| ^^^^^ help: expected syntax is: `cfg(/* predicate */)`
70+
71+
error: multiple `cfg` predicates are specified
72+
--> $DIR/doc-cfg.rs:10:16
73+
|
74+
LL | #[doc(cfg(foo, bar))]
75+
| ^^^
76+
77+
error: aborting due to 9 previous errors; 2 warnings emitted
4678

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
#![doc(auto_cfg)] //~ ERROR
2+
#![doc(auto_cfg(false))] //~ ERROR
3+
#![doc(auto_cfg(true))] //~ ERROR
4+
#![doc(auto_cfg(hide(feature = "solecism")))] //~ ERROR
5+
#![doc(auto_cfg(show(feature = "bla")))] //~ ERROR
6+
#![doc(cfg(feature = "solecism"))] //~ ERROR
Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
error[E0658]: `#[doc(auto_cfg)]` is experimental
2+
--> $DIR/feature-gate-doc_cfg.rs:1:1
3+
|
4+
LL | #![doc(auto_cfg)]
5+
| ^^^^^^^^^^^^^^^^^
6+
|
7+
= note: see issue #43781 <https://github.com/rust-lang/rust/issues/43781> for more information
8+
= help: add `#![feature(doc_cfg)]` to the crate attributes to enable
9+
= note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
10+
11+
error[E0658]: `#[doc(auto_cfg)]` is experimental
12+
--> $DIR/feature-gate-doc_cfg.rs:2:1
13+
|
14+
LL | #![doc(auto_cfg(false))]
15+
| ^^^^^^^^^^^^^^^^^^^^^^^^
16+
|
17+
= note: see issue #43781 <https://github.com/rust-lang/rust/issues/43781> for more information
18+
= help: add `#![feature(doc_cfg)]` to the crate attributes to enable
19+
= note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
20+
21+
error[E0658]: `#[doc(auto_cfg)]` is experimental
22+
--> $DIR/feature-gate-doc_cfg.rs:3:1
23+
|
24+
LL | #![doc(auto_cfg(true))]
25+
| ^^^^^^^^^^^^^^^^^^^^^^^
26+
|
27+
= note: see issue #43781 <https://github.com/rust-lang/rust/issues/43781> for more information
28+
= help: add `#![feature(doc_cfg)]` to the crate attributes to enable
29+
= note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
30+
31+
error[E0658]: `#[doc(auto_cfg)]` is experimental
32+
--> $DIR/feature-gate-doc_cfg.rs:4:1
33+
|
34+
LL | #![doc(auto_cfg(hide(feature = "solecism")))]
35+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
36+
|
37+
= note: see issue #43781 <https://github.com/rust-lang/rust/issues/43781> for more information
38+
= help: add `#![feature(doc_cfg)]` to the crate attributes to enable
39+
= note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
40+
41+
error[E0658]: `#[doc(auto_cfg)]` is experimental
42+
--> $DIR/feature-gate-doc_cfg.rs:5:1
43+
|
44+
LL | #![doc(auto_cfg(show(feature = "bla")))]
45+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
46+
|
47+
= note: see issue #43781 <https://github.com/rust-lang/rust/issues/43781> for more information
48+
= help: add `#![feature(doc_cfg)]` to the crate attributes to enable
49+
= note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
50+
51+
error[E0658]: `#[doc(cfg)]` is experimental
52+
--> $DIR/feature-gate-doc_cfg.rs:6:1
53+
|
54+
LL | #![doc(cfg(feature = "solecism"))]
55+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
56+
|
57+
= note: see issue #43781 <https://github.com/rust-lang/rust/issues/43781> for more information
58+
= help: add `#![feature(doc_cfg)]` to the crate attributes to enable
59+
= note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
60+
61+
error: aborting due to 6 previous errors
62+
63+
For more information about this error, try `rustc --explain E0658`.

0 commit comments

Comments
 (0)