Manually cleanup token stream when macro expansion aborts.

This commit is contained in:
Camille GILLOT 2022-08-08 00:05:20 +02:00
parent 5338f5f1d4
commit 8823634db8
3 changed files with 71 additions and 15 deletions

View file

@ -442,23 +442,38 @@ fn make_token_stream(
}
token_and_spacing = iter.next();
}
let mut final_buf = stack.pop().expect("Missing final buf!");
if break_last_token {
let last_token = final_buf.inner.pop().unwrap();
if let AttrTokenTree::Token(last_token, spacing) = last_token {
let unglued_first = last_token.kind.break_two_token_op().unwrap().0;
// An 'unglued' token is always two ASCII characters
let mut first_span = last_token.span.shrink_to_lo();
first_span = first_span.with_hi(first_span.lo() + rustc_span::BytePos(1));
final_buf
while let Some(FrameData { open_delim_sp, mut inner }) = stack.pop() {
// A former macro expansion could give us malformed tokens.
// In that case, manually close all open delimitors so downstream users
// don't ICE on them.
if let Some((delim, open_sp)) = open_delim_sp {
let dspan = DelimSpan::from_pair(open_sp, rustc_span::DUMMY_SP);
let stream = AttrTokenStream::new(inner);
let delimited = AttrTokenTree::Delimited(dspan, delim, stream);
stack
.last_mut()
.unwrap_or_else(|| panic!("Bottom token frame is missing for recovered token"))
.inner
.push(AttrTokenTree::Token(Token::new(unglued_first, first_span), spacing));
.push(delimited);
} else {
panic!("Unexpected last token {:?}", last_token)
if break_last_token {
let last_token = inner.pop().unwrap();
if let AttrTokenTree::Token(last_token, spacing) = last_token {
let unglued_first = last_token.kind.break_two_token_op().unwrap().0;
// An 'unglued' token is always two ASCII characters
let mut first_span = last_token.span.shrink_to_lo();
first_span = first_span.with_hi(first_span.lo() + rustc_span::BytePos(1));
inner
.push(AttrTokenTree::Token(Token::new(unglued_first, first_span), spacing));
} else {
panic!("Unexpected last token {:?}", last_token)
}
}
assert!(stack.is_empty(), "Stack should be empty: stack={:?}", stack);
return AttrTokenStream::new(inner);
}
}
assert!(stack.is_empty(), "Stack should be empty: final_buf={:?} stack={:?}", final_buf, stack);
AttrTokenStream::new(final_buf.inner)
panic!("Missing final buf!")
}