Skip to content

Commit cb5ea8d

Browse files
committed
Emit an error instead of reconstructing token stream.
1 parent 8823634 commit cb5ea8d

File tree

4 files changed

+58
-59
lines changed

4 files changed

+58
-59
lines changed

compiler/rustc_builtin_macros/src/cfg_eval.rs

+36-28
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ use rustc_ast::visit::Visitor;
77
use rustc_ast::NodeId;
88
use rustc_ast::{mut_visit, visit};
99
use rustc_ast::{Attribute, HasAttrs, HasTokens};
10+
use rustc_errors::PResult;
1011
use rustc_expand::base::{Annotatable, ExtCtxt};
1112
use rustc_expand::config::StripUnconfigured;
1213
use rustc_expand::configure;
@@ -144,33 +145,34 @@ impl CfgEval<'_, '_> {
144145
// the location of `#[cfg]` and `#[cfg_attr]` in the token stream. The tokenization
145146
// process is lossless, so this process is invisible to proc-macros.
146147

147-
let parse_annotatable_with: fn(&mut Parser<'_>) -> _ = match annotatable {
148-
Annotatable::Item(_) => {
149-
|parser| Annotatable::Item(parser.parse_item(ForceCollect::Yes).unwrap().unwrap())
150-
}
151-
Annotatable::TraitItem(_) => |parser| {
152-
Annotatable::TraitItem(
153-
parser.parse_trait_item(ForceCollect::Yes).unwrap().unwrap().unwrap(),
154-
)
155-
},
156-
Annotatable::ImplItem(_) => |parser| {
157-
Annotatable::ImplItem(
158-
parser.parse_impl_item(ForceCollect::Yes).unwrap().unwrap().unwrap(),
159-
)
160-
},
161-
Annotatable::ForeignItem(_) => |parser| {
162-
Annotatable::ForeignItem(
163-
parser.parse_foreign_item(ForceCollect::Yes).unwrap().unwrap().unwrap(),
164-
)
165-
},
166-
Annotatable::Stmt(_) => |parser| {
167-
Annotatable::Stmt(P(parser.parse_stmt(ForceCollect::Yes).unwrap().unwrap()))
168-
},
169-
Annotatable::Expr(_) => {
170-
|parser| Annotatable::Expr(parser.parse_expr_force_collect().unwrap())
171-
}
172-
_ => unreachable!(),
173-
};
148+
let parse_annotatable_with: for<'a> fn(&mut Parser<'a>) -> PResult<'a, _> =
149+
match annotatable {
150+
Annotatable::Item(_) => {
151+
|parser| Ok(Annotatable::Item(parser.parse_item(ForceCollect::Yes)?.unwrap()))
152+
}
153+
Annotatable::TraitItem(_) => |parser| {
154+
Ok(Annotatable::TraitItem(
155+
parser.parse_trait_item(ForceCollect::Yes)?.unwrap().unwrap(),
156+
))
157+
},
158+
Annotatable::ImplItem(_) => |parser| {
159+
Ok(Annotatable::ImplItem(
160+
parser.parse_impl_item(ForceCollect::Yes)?.unwrap().unwrap(),
161+
))
162+
},
163+
Annotatable::ForeignItem(_) => |parser| {
164+
Ok(Annotatable::ForeignItem(
165+
parser.parse_foreign_item(ForceCollect::Yes)?.unwrap().unwrap(),
166+
))
167+
},
168+
Annotatable::Stmt(_) => |parser| {
169+
Ok(Annotatable::Stmt(P(parser.parse_stmt(ForceCollect::Yes)?.unwrap())))
170+
},
171+
Annotatable::Expr(_) => {
172+
|parser| Ok(Annotatable::Expr(parser.parse_expr_force_collect()?))
173+
}
174+
_ => unreachable!(),
175+
};
174176

175177
// 'Flatten' all nonterminals (i.e. `TokenKind::Interpolated`)
176178
// to `None`-delimited groups containing the corresponding tokens. This
@@ -193,7 +195,13 @@ impl CfgEval<'_, '_> {
193195
let mut parser =
194196
rustc_parse::stream_to_parser(&self.cfg.sess.parse_sess, orig_tokens, None);
195197
parser.capture_cfg = true;
196-
annotatable = parse_annotatable_with(&mut parser);
198+
match parse_annotatable_with(&mut parser) {
199+
Ok(a) => annotatable = a,
200+
Err(mut err) => {
201+
err.emit();
202+
return Some(annotatable);
203+
}
204+
}
197205

198206
// Now that we have our re-parsed `AttrTokenStream`, recursively configuring
199207
// our attribute target will correctly the tokens as well.

compiler/rustc_parse/src/parser/attr_wrapper.rs

+14-30
Original file line numberDiff line numberDiff line change
@@ -442,38 +442,22 @@ fn make_token_stream(
442442
}
443443
token_and_spacing = iter.next();
444444
}
445-
while let Some(FrameData { open_delim_sp, mut inner }) = stack.pop() {
446-
// A former macro expansion could give us malformed tokens.
447-
// In that case, manually close all open delimitors so downstream users
448-
// don't ICE on them.
449-
if let Some((delim, open_sp)) = open_delim_sp {
450-
let dspan = DelimSpan::from_pair(open_sp, rustc_span::DUMMY_SP);
451-
let stream = AttrTokenStream::new(inner);
452-
let delimited = AttrTokenTree::Delimited(dspan, delim, stream);
453-
stack
454-
.last_mut()
455-
.unwrap_or_else(|| panic!("Bottom token frame is missing for recovered token"))
445+
let mut final_buf = stack.pop().expect("Missing final buf!");
446+
if break_last_token {
447+
let last_token = final_buf.inner.pop().unwrap();
448+
if let AttrTokenTree::Token(last_token, spacing) = last_token {
449+
let unglued_first = last_token.kind.break_two_token_op().unwrap().0;
450+
451+
// An 'unglued' token is always two ASCII characters
452+
let mut first_span = last_token.span.shrink_to_lo();
453+
first_span = first_span.with_hi(first_span.lo() + rustc_span::BytePos(1));
454+
455+
final_buf
456456
.inner
457-
.push(delimited);
457+
.push(AttrTokenTree::Token(Token::new(unglued_first, first_span), spacing));
458458
} else {
459-
if break_last_token {
460-
let last_token = inner.pop().unwrap();
461-
if let AttrTokenTree::Token(last_token, spacing) = last_token {
462-
let unglued_first = last_token.kind.break_two_token_op().unwrap().0;
463-
464-
// An 'unglued' token is always two ASCII characters
465-
let mut first_span = last_token.span.shrink_to_lo();
466-
first_span = first_span.with_hi(first_span.lo() + rustc_span::BytePos(1));
467-
468-
inner
469-
.push(AttrTokenTree::Token(Token::new(unglued_first, first_span), spacing));
470-
} else {
471-
panic!("Unexpected last token {:?}", last_token)
472-
}
473-
}
474-
assert!(stack.is_empty(), "Stack should be empty: stack={:?}", stack);
475-
return AttrTokenStream::new(inner);
459+
panic!("Unexpected last token {:?}", last_token)
476460
}
477461
}
478-
panic!("Missing final buf!")
462+
AttrTokenStream::new(final_buf.inner)
479463
}

src/test/ui/macros/syntax-error-recovery.rs

+1
Original file line numberDiff line numberDiff line change
@@ -13,5 +13,6 @@ macro_rules! values {
1313
//~| ERROR macro expansion ignores token `(String)` and any following
1414

1515
values!(STRING(1) as (String) => cfg(test),);
16+
//~^ ERROR expected one of `!` or `::`, found `<eof>`
1617

1718
fn main() {}

src/test/ui/macros/syntax-error-recovery.stderr

+7-1
Original file line numberDiff line numberDiff line change
@@ -20,5 +20,11 @@ LL | values!(STRING(1) as (String) => cfg(test),);
2020
|
2121
= note: the usage of `values!` is likely invalid in item context
2222

23-
error: aborting due to 2 previous errors
23+
error: expected one of `!` or `::`, found `<eof>`
24+
--> $DIR/syntax-error-recovery.rs:15:9
25+
|
26+
LL | values!(STRING(1) as (String) => cfg(test),);
27+
| ^^^^^^ expected one of `!` or `::`
28+
29+
error: aborting due to 3 previous errors
2430

0 commit comments

Comments
 (0)