diff --git a/src/discouraged.rs b/src/discouraged.rs index 9e26bd9ac0..2f929f1a3b 100644 --- a/src/discouraged.rs +++ b/src/discouraged.rs @@ -167,7 +167,7 @@ pub trait Speculative { impl<'a> Speculative for ParseBuffer<'a> { fn advance_to(&self, fork: &Self) { if !crate::buffer::same_scope(self.cursor(), fork.cursor()) { - panic!("fork was not derived from the advancing parse stream"); + crate::panic_with_location!("fork was not derived from the advancing parse stream"); } let (self_unexp, self_sp) = inner_unexpected(self); diff --git a/src/lib.rs b/src/lib.rs index 28a6dd6d79..9000b678f1 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1013,3 +1013,25 @@ pub fn parse_file(mut content: &str) -> Result { file.shebang = shebang; Ok(file) } + +/// `panic!` macro that includes location information [file:line:column] +/// when inside of a proc-macro, because otherwise you don't get this information without +/// -Zmacro-backtrace, and enabling it is an extra step which makes debugging proc macros harder +macro_rules! panic_with_location { + ($message:literal $($tt:tt)*) => {{ + #[cfg(feature = "proc-macro")] + let is_available = proc_macro::is_available(); + #[cfg(not(feature = "proc-macro"))] + let is_available = false; + if is_available { + let location = core::panic::Location::caller(); + let file = location.file(); + let line = location.line(); + let column = location.column(); + ::core::panic!(concat!("[{}:{}:{}] ", $message), file, line, column $($tt)*) + } else { + ::core::panic!($message $($tt)*) + } + }}; +} +pub(crate) use panic_with_location; diff --git a/src/lifetime.rs b/src/lifetime.rs index eeaa398354..5d30ff4e24 100644 --- a/src/lifetime.rs +++ b/src/lifetime.rs @@ -37,18 +37,18 @@ impl Lifetime { /// ``` pub fn new(symbol: &str, span: Span) -> Self { if !symbol.starts_with('\'') { - panic!( + crate::panic_with_location!( "lifetime name must start with apostrophe as in \"'a\", got {:?}", symbol ); } if symbol == "'" { - panic!("lifetime name must not be empty"); + crate::panic_with_location!("lifetime name must not be empty"); } if !crate::ident::xid_ok(&symbol[1..]) { - panic!("{:?} is not a valid lifetime name", symbol); + crate::panic_with_location!("{:?} is not a valid lifetime name", symbol); } Lifetime { diff --git a/src/lit.rs b/src/lit.rs index a77b3cd3e8..7e020d26c6 100644 --- a/src/lit.rs +++ b/src/lit.rs @@ -424,7 +424,7 @@ impl LitInt { pub fn new(repr: &str, span: Span) -> Self { let (digits, suffix) = match value::parse_lit_int(repr) { Some(parse) => parse, - None => panic!("not an integer literal: `{}`", repr), + None => crate::panic_with_location!("not an integer literal: `{}`", repr), }; let mut token: Literal = repr.parse().unwrap(); @@ -504,7 +504,7 @@ impl From for LitInt { }), } } else { - panic!("not an integer literal: `{}`", repr); + crate::panic_with_location!("not an integer literal: `{}`", repr); } } } @@ -520,7 +520,7 @@ impl LitFloat { pub fn new(repr: &str, span: Span) -> Self { let (digits, suffix) = match value::parse_lit_float(repr) { Some(parse) => parse, - None => panic!("not a float literal: `{}`", repr), + None => crate::panic_with_location!("not a float literal: `{}`", repr), }; let mut token: Literal = repr.parse().unwrap(); @@ -578,7 +578,7 @@ impl From for LitFloat { }), } } else { - panic!("not a float literal: `{}`", repr); + crate::panic_with_location!("not a float literal: `{}`", repr); } } } diff --git a/src/parse_quote.rs b/src/parse_quote.rs index 3e96b2ed94..af7049a57a 100644 --- a/src/parse_quote.rs +++ b/src/parse_quote.rs @@ -133,7 +133,7 @@ pub fn parse(token_stream: TokenStream) -> T { let parser = T::parse; match parser.parse2(token_stream) { Ok(t) => t, - Err(err) => panic!("{}", err), + Err(err) => crate::panic_with_location!("{}", err), } } diff --git a/src/punctuated.rs b/src/punctuated.rs index 7545c66926..ead09b9ad2 100644 --- a/src/punctuated.rs +++ b/src/punctuated.rs @@ -504,7 +504,7 @@ where let mut nomore = false; for pair in i { if nomore { - panic!("punctuated extended with items after a Pair::End"); + crate::panic_with_location!("punctuated extended with items after a Pair::End"); } match pair { Pair::Punctuated(a, b) => punctuated.inner.push((a, b)), diff --git a/src/verbatim.rs b/src/verbatim.rs index c05a0c61d1..a0463c1b21 100644 --- a/src/verbatim.rs +++ b/src/verbatim.rs @@ -22,7 +22,7 @@ pub(crate) fn between<'a>(begin: ParseStream<'a>, end: ParseStream<'a>) -> Token cursor = inside; continue; } else { - panic!("verbatim end must not be inside a delimited group"); + crate::panic_with_location!("verbatim end must not be inside a delimited group"); } }