Skip to content
/ rust Public
forked from rust-lang/rust

Commit 230848d

Browse files
authored
Rollup merge of rust-lang#158417 - TaKO8Ki:fix-cfg-eval-derive-reparse-ice, r=petrochenkov
Avoid ICE when cfg_eval recovers no item from derive input Fixes rust-lang#148891 `cfg_eval` reparses derive input when it contains `#[cfg]` or `#[cfg_attr]` so it can capture cfg positions in the token stream. That reparse can emit syntax errors and return `Ok(None)` when parser recovery cannot reconstruct an item. This pr changes the reparse path to return `Option<Annotatable>` and fall back to the original annotatable when recovery produces no node.
2 parents 4c2b08f + 14e5371 commit 230848d

3 files changed

Lines changed: 68 additions & 22 deletions

File tree

compiler/rustc_builtin_macros/src/cfg_eval.rs

Lines changed: 23 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -107,41 +107,42 @@ impl CfgEval<'_> {
107107
// our attribute target will correctly configure the tokens as well.
108108
let mut parser = Parser::new(&self.0.sess.psess, orig_tokens, None);
109109
parser.capture_cfg = true;
110-
let res: PResult<'_, Annotatable> = try {
111-
match annotatable {
112-
Annotatable::Item(_) => {
113-
let item =
114-
parser.parse_item(ForceCollect::Yes, AllowConstBlockItems::Yes)?.unwrap();
115-
Annotatable::Item(self.flat_map_item(item).pop().unwrap())
116-
}
110+
let res: PResult<'_, Option<Annotatable>> = try {
111+
match &annotatable {
112+
Annotatable::Item(_) => parser
113+
.parse_item(ForceCollect::Yes, AllowConstBlockItems::Yes)?
114+
.and_then(|item| self.flat_map_item(item).pop().map(Annotatable::Item)),
117115
Annotatable::AssocItem(_, ctxt) => {
118-
let item = parser.parse_trait_item(ForceCollect::Yes)?.unwrap().unwrap();
119-
Annotatable::AssocItem(
120-
self.flat_map_assoc_item(item, ctxt).pop().unwrap(),
121-
ctxt,
122-
)
116+
parser.parse_trait_item(ForceCollect::Yes)?.flatten().and_then(|item| {
117+
self.flat_map_assoc_item(item, *ctxt)
118+
.pop()
119+
.map(|item| Annotatable::AssocItem(item, *ctxt))
120+
})
123121
}
124122
Annotatable::ForeignItem(_) => {
125-
let item = parser.parse_foreign_item(ForceCollect::Yes)?.unwrap().unwrap();
126-
Annotatable::ForeignItem(self.flat_map_foreign_item(item).pop().unwrap())
127-
}
128-
Annotatable::Stmt(_) => {
129-
let stmt = parser
130-
.parse_stmt_without_recovery(false, ForceCollect::Yes, false)?
131-
.unwrap();
132-
Annotatable::Stmt(Box::new(self.flat_map_stmt(stmt).pop().unwrap()))
123+
parser.parse_foreign_item(ForceCollect::Yes)?.flatten().and_then(|item| {
124+
self.flat_map_foreign_item(item).pop().map(Annotatable::ForeignItem)
125+
})
133126
}
127+
Annotatable::Stmt(_) => parser
128+
.parse_stmt_without_recovery(false, ForceCollect::Yes, false)?
129+
.and_then(|stmt| {
130+
self.flat_map_stmt(stmt).pop().map(|stmt| Annotatable::Stmt(Box::new(stmt)))
131+
}),
134132
Annotatable::Expr(_) => {
135133
let mut expr = parser.parse_expr_force_collect()?;
136134
self.visit_expr(&mut expr);
137-
Annotatable::Expr(expr)
135+
Some(Annotatable::Expr(expr))
138136
}
139137
_ => unreachable!(),
140138
}
141139
};
142140

143141
match res {
144-
Ok(ann) => ann,
142+
Ok(Some(ann)) => ann,
143+
// Parser recovery may emit errors without reconstructing an annotatable.
144+
// Keep the original node so cfg-eval stays best-effort instead of ICEing.
145+
Ok(None) => annotatable,
145146
Err(err) => {
146147
err.emit();
147148
annotatable
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
// Regression test for https://github.com/rust-lang/rust/issues/148891.
2+
3+
macro_rules! values {
4+
($inner:ty) => {
5+
#[derive(Debug)]
6+
pub enum TokenKind {
7+
#[cfg(test)]
8+
STRING([u8; $inner]),
9+
//~^ ERROR expected expression, found `ty` metavariable
10+
//~| ERROR macro expansion ignores `)` and any tokens following
11+
}
12+
};
13+
}
14+
15+
values!(String);
16+
17+
fn main() {}
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
error: expected expression, found `ty` metavariable
2+
--> $DIR/cfg-eval-derive-invalid-reparse-no-ice.rs:8:25
3+
|
4+
LL | pub enum TokenKind {
5+
| --------- while parsing this enum
6+
LL | #[cfg(test)]
7+
LL | STRING([u8; $inner]),
8+
| ^^^^^^ expected expression
9+
...
10+
LL | values!(String);
11+
| --------------- in this macro invocation
12+
|
13+
= help: enum variants can be `Variant`, `Variant = <integer>`, `Variant(Type, ..., TypeN)` or `Variant { fields: Types }`
14+
= note: this error originates in the macro `values` (in Nightly builds, run with -Z macro-backtrace for more info)
15+
16+
error: macro expansion ignores `)` and any tokens following
17+
--> $DIR/cfg-eval-derive-invalid-reparse-no-ice.rs:8:32
18+
|
19+
LL | STRING([u8; $inner]),
20+
| ^
21+
...
22+
LL | values!(String);
23+
| --------------- caused by the macro expansion here
24+
|
25+
= note: the usage of `values!` is likely invalid in item context
26+
27+
error: aborting due to 2 previous errors
28+

0 commit comments

Comments
 (0)