Skip to content

Commit 6133b7e

Browse files
Rollup merge of #155734 - qaijuang:cfg-select-doc-comment, r=JonathanBrouwer
Reject outer attributes on `cfg_select` branches Fixes #155701.
2 parents c6fbd9f + d42a92b commit 6133b7e

4 files changed

Lines changed: 185 additions & 4 deletions

File tree

compiler/rustc_attr_parsing/src/attributes/cfg_select.rs

Lines changed: 29 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ use rustc_ast::token::Token;
22
use rustc_ast::tokenstream::TokenStream;
33
use rustc_ast::{AttrStyle, NodeId, token};
44
use rustc_data_structures::fx::FxHashMap;
5-
use rustc_errors::Diagnostic;
5+
use rustc_errors::{Diagnostic, MultiSpan};
66
use rustc_feature::{AttributeTemplate, Features};
77
use rustc_hir::attrs::CfgEntry;
88
use rustc_hir::{AttrPath, Target};
@@ -76,8 +76,11 @@ pub fn parse_cfg_select(
7676
lint_node_id: NodeId,
7777
) -> Result<CfgSelectBranches, ErrorGuaranteed> {
7878
let mut branches = CfgSelectBranches::default();
79+
let mut branch_attr_error: Option<ErrorGuaranteed> = None;
7980

8081
while p.token != token::Eof {
82+
reject_branch_outer_attrs(p, &mut branch_attr_error)?;
83+
8184
if p.eat_keyword(exp!(Underscore)) {
8285
let underscore = p.prev_token;
8386
p.expect(exp!(FatArrow)).map_err(|e| e.emit())?;
@@ -131,6 +134,10 @@ pub fn parse_cfg_select(
131134
}
132135
}
133136

137+
if let Some(guar) = branch_attr_error {
138+
return Err(guar);
139+
}
140+
134141
let it = branches
135142
.reachable
136143
.iter()
@@ -143,6 +150,27 @@ pub fn parse_cfg_select(
143150
Ok(branches)
144151
}
145152

153+
fn reject_branch_outer_attrs(
154+
p: &mut Parser<'_>,
155+
branch_attr_error: &mut Option<ErrorGuaranteed>,
156+
) -> Result<(), ErrorGuaranteed> {
157+
let Some(spans) = p.parse_cfg_select_branch_outer_attrs().map_err(|e| e.emit())? else {
158+
return Ok(());
159+
};
160+
161+
for (spans, msg) in [
162+
(spans.doc_comments, "doc comments are not allowed on `cfg_select` branches"),
163+
(spans.attrs, "attributes are not allowed on `cfg_select` branches"),
164+
] {
165+
if !spans.is_empty() {
166+
branch_attr_error
167+
.get_or_insert(p.dcx().struct_span_err(MultiSpan::from_spans(spans), msg).emit());
168+
}
169+
}
170+
171+
Ok(())
172+
}
173+
146174
fn lint_unreachable(
147175
p: &mut Parser<'_>,
148176
predicates: impl Iterator<Item = CfgSelectPredicate>,

compiler/rustc_parse/src/parser/cfg_select.rs

Lines changed: 37 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,18 @@
1-
use rustc_ast::token;
21
use rustc_ast::tokenstream::{TokenStream, TokenTree};
32
use rustc_ast::util::classify;
3+
use rustc_ast::{AttrKind, token};
44
use rustc_errors::PResult;
5+
use rustc_span::Span;
56

67
use crate::exp;
78
use crate::parser::{AttrWrapper, ForceCollect, Parser, Restrictions, Trailing, UsePreAttrPos};
89

10+
#[derive(Default)]
11+
pub struct CfgSelectBranchAttrSpans {
12+
pub attrs: Vec<Span>,
13+
pub doc_comments: Vec<Span>,
14+
}
15+
916
impl<'a> Parser<'a> {
1017
/// Parses a `TokenTree` consisting either of `{ /* ... */ }` optionally followed by a comma
1118
/// (and strip the braces and the optional comma) or an expression followed by a comma
@@ -36,4 +43,33 @@ impl<'a> Parser<'a> {
3643
}
3744
Ok(TokenStream::from_ast(&expr))
3845
}
46+
47+
/// Parses outer attributes before a `cfg_select!` branch for recovery.
48+
pub fn parse_cfg_select_branch_outer_attrs(
49+
&mut self,
50+
) -> PResult<'a, Option<CfgSelectBranchAttrSpans>> {
51+
let attrs = self.parse_outer_attributes()?;
52+
if attrs.is_empty() {
53+
return Ok(None);
54+
}
55+
56+
let mut spans = CfgSelectBranchAttrSpans::default();
57+
for attr in attrs.take_for_recovery(self.psess) {
58+
match attr.kind {
59+
AttrKind::Normal(..) => spans.attrs.push(attr.span),
60+
// `parse_outer_attributes` already emitted E0753 for inner doc comments before
61+
// recovering them as outer doc-comment attributes.
62+
AttrKind::DocComment(comment_kind, _)
63+
if self.span_to_snippet(attr.span).ok().is_some_and(
64+
|snippet| match comment_kind {
65+
token::CommentKind::Line => snippet.starts_with("//!"),
66+
token::CommentKind::Block => snippet.starts_with("/*!"),
67+
},
68+
) => {}
69+
AttrKind::DocComment(..) => spans.doc_comments.push(attr.span),
70+
}
71+
}
72+
73+
Ok(Some(spans))
74+
}
3975
}

tests/ui/macros/cfg_select.rs

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -202,3 +202,52 @@ cfg_select! {
202202
//~^ ERROR expected one of `(`, `::`, `=>`, or `=`, found `!`
203203
//~| WARN unexpected `cfg` condition name
204204
}
205+
206+
// Regression test for https://github.com/rust-lang/rust/issues/155701.
207+
cfg_select! {
208+
/// doc comment
209+
//~^ ERROR doc comments are not allowed on `cfg_select` branches
210+
debug_assertions => {}
211+
/// doc comment
212+
//~^ ERROR doc comments are not allowed on `cfg_select` branches
213+
_ => {}
214+
}
215+
216+
cfg_select! {
217+
#[cfg(false)]
218+
//~^ ERROR attributes are not allowed on `cfg_select` branches
219+
debug_assertions => {}
220+
_ => {}
221+
}
222+
223+
cfg_select! {
224+
#![cfg(false)]
225+
//~^ ERROR an inner attribute is not permitted in this context
226+
debug_assertions => {}
227+
_ => {}
228+
}
229+
230+
cfg_select! {
231+
//! inner doc comment
232+
//~^ ERROR expected outer doc comment
233+
debug_assertions => {}
234+
_ => {}
235+
}
236+
237+
cfg_select! {
238+
debug_assertions => {}
239+
/// line1
240+
//~^ ERROR doc comments are not allowed on `cfg_select` branches
241+
// line2
242+
/// line3
243+
_ => {}
244+
}
245+
246+
cfg_select! {
247+
/// outer doc comment
248+
//~^ ERROR doc comments are not allowed on `cfg_select` branches
249+
//! inner doc comment
250+
//~^ ERROR expected outer doc comment
251+
debug_assertions => {}
252+
_ => {}
253+
}

tests/ui/macros/cfg_select.stderr

Lines changed: 70 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,74 @@ error: expected one of `(`, `::`, `=>`, or `=`, found `!`
5555
LL | cfg!() => {}
5656
| ^ expected one of `(`, `::`, `=>`, or `=`
5757

58+
error: doc comments are not allowed on `cfg_select` branches
59+
--> $DIR/cfg_select.rs:208:5
60+
|
61+
LL | /// doc comment
62+
| ^^^^^^^^^^^^^^^
63+
64+
error: doc comments are not allowed on `cfg_select` branches
65+
--> $DIR/cfg_select.rs:211:5
66+
|
67+
LL | /// doc comment
68+
| ^^^^^^^^^^^^^^^
69+
70+
error: attributes are not allowed on `cfg_select` branches
71+
--> $DIR/cfg_select.rs:217:5
72+
|
73+
LL | #[cfg(false)]
74+
| ^^^^^^^^^^^^^
75+
76+
error: an inner attribute is not permitted in this context
77+
--> $DIR/cfg_select.rs:224:5
78+
|
79+
LL | #![cfg(false)]
80+
| ^^^^^^^^^^^^^^
81+
|
82+
= note: inner attributes, like `#![no_std]`, annotate the item enclosing them, and are usually found at the beginning of source files
83+
= note: outer attributes, like `#[test]`, annotate the item following them
84+
85+
error[E0753]: expected outer doc comment
86+
--> $DIR/cfg_select.rs:231:5
87+
|
88+
LL | //! inner doc comment
89+
| ^^^^^^^^^^^^^^^^^^^^^
90+
|
91+
= note: inner doc comments like this (starting with `//!` or `/*!`) can only appear before items
92+
help: you might have meant to write a regular comment
93+
|
94+
LL - //! inner doc comment
95+
LL + // inner doc comment
96+
|
97+
98+
error: doc comments are not allowed on `cfg_select` branches
99+
--> $DIR/cfg_select.rs:239:5
100+
|
101+
LL | /// line1
102+
| ^^^^^^^^^
103+
...
104+
LL | /// line3
105+
| ^^^^^^^^^
106+
107+
error[E0753]: expected outer doc comment
108+
--> $DIR/cfg_select.rs:249:5
109+
|
110+
LL | //! inner doc comment
111+
| ^^^^^^^^^^^^^^^^^^^^^
112+
|
113+
= note: inner doc comments like this (starting with `//!` or `/*!`) can only appear before items
114+
help: you might have meant to write a regular comment
115+
|
116+
LL - //! inner doc comment
117+
LL + // inner doc comment
118+
|
119+
120+
error: doc comments are not allowed on `cfg_select` branches
121+
--> $DIR/cfg_select.rs:247:5
122+
|
123+
LL | /// outer doc comment
124+
| ^^^^^^^^^^^^^^^^^^^^^
125+
58126
warning: unreachable configuration predicate
59127
--> $DIR/cfg_select.rs:136:5
60128
|
@@ -115,7 +183,7 @@ LL | cfg!() => {}
115183
= help: to expect this configuration use `--check-cfg=cfg(cfg)`
116184
= note: see <https://doc.rust-lang.org/nightly/rustc/check-cfg.html> for more information about checking conditional configuration
117185

118-
error: aborting due to 9 previous errors; 7 warnings emitted
186+
error: aborting due to 17 previous errors; 7 warnings emitted
119187

120-
Some errors have detailed explanations: E0537, E0539.
188+
Some errors have detailed explanations: E0537, E0539, E0753.
121189
For more information about an error, try `rustc --explain E0537`.

0 commit comments

Comments
 (0)