Skip to content

Instantly share code, notes, and snippets.

@yvt
Created March 22, 2023 14:04
Show Gist options
  • Save yvt/baa2ceb4ef99ee9df582b35dca97df03 to your computer and use it in GitHub Desktop.
Save yvt/baa2ceb4ef99ee9df582b35dca97df03 to your computer and use it in GitHub Desktop.
Attach backtrace to "unexpected token" errors in `syn`
diff --git a/src/discouraged.rs b/src/discouraged.rs
index fb98d633..059b7351 100644
--- a/src/discouraged.rs
+++ b/src/discouraged.rs
@@ -170,7 +170,7 @@ impl<'a> Speculative for ParseBuffer<'a> {
match (fork_sp, self_sp) {
// Unexpected set on the fork, but not on `self`, copy it over.
(Some(span), None) => {
- self_unexp.set(Unexpected::Some(span));
+ self_unexp.set(Unexpected::Some(span.0, span.1));
}
// Unexpected unset. Use chain to propagate errors from fork.
(None, None) => {
diff --git a/src/parse.rs b/src/parse.rs
index 61a10d2b..d0ef2169 100644
--- a/src/parse.rs
+++ b/src/parse.rs
@@ -268,7 +268,10 @@ impl<'a> Drop for ParseBuffer<'a> {
if let Some(unexpected_span) = span_of_unexpected_ignoring_nones(self.cursor()) {
let (inner, old_span) = inner_unexpected(self);
if old_span.is_none() {
- inner.set(Unexpected::Some(unexpected_span));
+ inner.set(Unexpected::Some(
+ unexpected_span,
+ Rc::new(std::backtrace::Backtrace::capture()),
+ ));
}
}
}
@@ -396,7 +399,7 @@ pub(crate) fn new_parse_buffer(
pub(crate) enum Unexpected {
None,
- Some(Span),
+ Some(Span, Rc<std::backtrace::Backtrace>),
Chain(Rc<Cell<Unexpected>>),
}
@@ -410,7 +413,7 @@ impl Clone for Unexpected {
fn clone(&self) -> Self {
match self {
Unexpected::None => Unexpected::None,
- Unexpected::Some(span) => Unexpected::Some(*span),
+ Unexpected::Some(span, bt) => Unexpected::Some(*span, bt.clone()),
Unexpected::Chain(next) => Unexpected::Chain(next.clone()),
}
}
@@ -425,12 +428,17 @@ fn cell_clone<T: Default + Clone>(cell: &Cell<T>) -> T {
ret
}
-fn inner_unexpected(buffer: &ParseBuffer) -> (Rc<Cell<Unexpected>>, Option<Span>) {
+fn inner_unexpected(
+ buffer: &ParseBuffer,
+) -> (
+ Rc<Cell<Unexpected>>,
+ Option<(Span, Rc<std::backtrace::Backtrace>)>,
+) {
let mut unexpected = get_unexpected(buffer);
loop {
match cell_clone(&unexpected) {
Unexpected::None => return (unexpected, None),
- Unexpected::Some(span) => return (unexpected, Some(span)),
+ Unexpected::Some(span, bt) => return (unexpected, Some((span, bt))),
Unexpected::Chain(next) => unexpected = next,
}
}
@@ -1105,7 +1113,7 @@ impl<'a> ParseBuffer<'a> {
fn check_unexpected(&self) -> Result<()> {
match inner_unexpected(self).1 {
- Some(span) => Err(Error::new(span, "unexpected token")),
+ Some((span, bt)) => Err(Error::new(span, format_args!("unexpected token: {bt}"))),
None => Ok(()),
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment