1 #[cfg(feature = "parsing")] 2 use crate::buffer::Cursor; 3 use crate::thread::ThreadBound; 4 use proc_macro2::{ 5 Delimiter, Group, Ident, LexError, Literal, Punct, Spacing, Span, TokenStream, TokenTree, 6 }; 7 #[cfg(feature = "printing")] 8 use quote::ToTokens; 9 use std::fmt::{self, Debug, Display}; 10 use std::slice; 11 use std::vec; 12 13 /// The result of a Syn parser. 14 pub type Result<T> = std::result::Result<T, Error>; 15 16 /// Error returned when a Syn parser cannot parse the input tokens. 17 /// 18 /// # Error reporting in proc macros 19 /// 20 /// The correct way to report errors back to the compiler from a procedural 21 /// macro is by emitting an appropriately spanned invocation of 22 /// [`compile_error!`] in the generated code. This produces a better diagnostic 23 /// message than simply panicking the macro. 24 /// 25 /// [`compile_error!`]: std::compile_error! 26 /// 27 /// When parsing macro input, the [`parse_macro_input!`] macro handles the 28 /// conversion to `compile_error!` automatically. 29 /// 30 /// [`parse_macro_input!`]: crate::parse_macro_input! 31 /// 32 /// ``` 33 /// # extern crate proc_macro; 34 /// # 35 /// use proc_macro::TokenStream; 36 /// use syn::parse::{Parse, ParseStream, Result}; 37 /// use syn::{parse_macro_input, ItemFn}; 38 /// 39 /// # const IGNORE: &str = stringify! { 40 /// #[proc_macro_attribute] 41 /// # }; 42 /// pub fn my_attr(args: TokenStream, input: TokenStream) -> TokenStream { 43 /// let args = parse_macro_input!(args as MyAttrArgs); 44 /// let input = parse_macro_input!(input as ItemFn); 45 /// 46 /// /* ... */ 47 /// # TokenStream::new() 48 /// } 49 /// 50 /// struct MyAttrArgs { 51 /// # _k: [(); { stringify! { 52 /// ... 53 /// # }; 0 }] 54 /// } 55 /// 56 /// impl Parse for MyAttrArgs { 57 /// fn parse(input: ParseStream) -> Result<Self> { 58 /// # stringify! { 59 /// ... 60 /// # }; 61 /// # unimplemented!() 62 /// } 63 /// } 64 /// ``` 65 /// 66 /// For errors that arise later than the initial parsing stage, the 67 /// [`.to_compile_error()`] or [`.into_compile_error()`] methods can be used to 68 /// perform an explicit conversion to `compile_error!`. 69 /// 70 /// [`.to_compile_error()`]: Error::to_compile_error 71 /// [`.into_compile_error()`]: Error::into_compile_error 72 /// 73 /// ``` 74 /// # extern crate proc_macro; 75 /// # 76 /// # use proc_macro::TokenStream; 77 /// # use syn::{parse_macro_input, DeriveInput}; 78 /// # 79 /// # const IGNORE: &str = stringify! { 80 /// #[proc_macro_derive(MyDerive)] 81 /// # }; 82 /// pub fn my_derive(input: TokenStream) -> TokenStream { 83 /// let input = parse_macro_input!(input as DeriveInput); 84 /// 85 /// // fn(DeriveInput) -> syn::Result<proc_macro2::TokenStream> 86 /// expand::my_derive(input) 87 /// .unwrap_or_else(syn::Error::into_compile_error) 88 /// .into() 89 /// } 90 /// # 91 /// # mod expand { 92 /// # use proc_macro2::TokenStream; 93 /// # use syn::{DeriveInput, Result}; 94 /// # 95 /// # pub fn my_derive(input: DeriveInput) -> Result<TokenStream> { 96 /// # unimplemented!() 97 /// # } 98 /// # } 99 /// ``` 100 pub struct Error { 101 messages: Vec<ErrorMessage>, 102 } 103 104 struct ErrorMessage { 105 // Span is implemented as an index into a thread-local interner to keep the 106 // size small. It is not safe to access from a different thread. We want 107 // errors to be Send and Sync to play nicely with ecosystem crates for error 108 // handling, so pin the span we're given to its original thread and assume 109 // it is Span::call_site if accessed from any other thread. 110 span: ThreadBound<SpanRange>, 111 message: String, 112 } 113 114 // Cannot use std::ops::Range<Span> because that does not implement Copy, 115 // whereas ThreadBound<T> requires a Copy impl as a way to ensure no Drop impls 116 // are involved. 117 struct SpanRange { 118 start: Span, 119 end: Span, 120 } 121 122 #[cfg(test)] 123 struct _Test 124 where 125 Error: Send + Sync; 126 127 impl Error { 128 /// Usually the [`ParseStream::error`] method will be used instead, which 129 /// automatically uses the correct span from the current position of the 130 /// parse stream. 131 /// 132 /// Use `Error::new` when the error needs to be triggered on some span other 133 /// than where the parse stream is currently positioned. 134 /// 135 /// [`ParseStream::error`]: crate::parse::ParseBuffer::error 136 /// 137 /// # Example 138 /// 139 /// ``` 140 /// use syn::{Error, Ident, LitStr, Result, Token}; 141 /// use syn::parse::ParseStream; 142 /// 143 /// // Parses input that looks like `name = "string"` where the key must be 144 /// // the identifier `name` and the value may be any string literal. 145 /// // Returns the string literal. 146 /// fn parse_name(input: ParseStream) -> Result<LitStr> { 147 /// let name_token: Ident = input.parse()?; 148 /// if name_token != "name" { 149 /// // Trigger an error not on the current position of the stream, 150 /// // but on the position of the unexpected identifier. 151 /// return Err(Error::new(name_token.span(), "expected `name`")); 152 /// } 153 /// input.parse::<Token![=]>()?; 154 /// let s: LitStr = input.parse()?; 155 /// Ok(s) 156 /// } 157 /// ``` newnull158 pub fn new<T: Display>(span: Span, message: T) -> Self { 159 return new(span, message.to_string()); 160 161 fn new(span: Span, message: String) -> Error { 162 Error { 163 messages: vec![ErrorMessage { 164 span: ThreadBound::new(SpanRange { 165 start: span, 166 end: span, 167 }), 168 message, 169 }], 170 } 171 } 172 } 173 174 /// Creates an error with the specified message spanning the given syntax 175 /// tree node. 176 /// 177 /// Unlike the `Error::new` constructor, this constructor takes an argument 178 /// `tokens` which is a syntax tree node. This allows the resulting `Error` 179 /// to attempt to span all tokens inside of `tokens`. While you would 180 /// typically be able to use the `Spanned` trait with the above `Error::new` 181 /// constructor, implementation limitations today mean that 182 /// `Error::new_spanned` may provide a higher-quality error message on 183 /// stable Rust. 184 /// 185 /// When in doubt it's recommended to stick to `Error::new` (or 186 /// `ParseStream::error`)! 187 #[cfg(feature = "printing")] 188 #[cfg_attr(doc_cfg, doc(cfg(feature = "printing")))] new_spannednull189 pub fn new_spanned<T: ToTokens, U: Display>(tokens: T, message: U) -> Self { 190 return new_spanned(tokens.into_token_stream(), message.to_string()); 191 192 fn new_spanned(tokens: TokenStream, message: String) -> Error { 193 let mut iter = tokens.into_iter(); 194 let start = iter.next().map_or_else(Span::call_site, |t| t.span()); 195 let end = iter.last().map_or(start, |t| t.span()); 196 Error { 197 messages: vec![ErrorMessage { 198 span: ThreadBound::new(SpanRange { start, end }), 199 message, 200 }], 201 } 202 } 203 } 204 205 /// The source location of the error. 206 /// 207 /// Spans are not thread-safe so this function returns `Span::call_site()` 208 /// if called from a different thread than the one on which the `Error` was 209 /// originally created. spannull210 pub fn span(&self) -> Span { 211 let SpanRange { start, end } = match self.messages[0].span.get() { 212 Some(span) => *span, 213 None => return Span::call_site(), 214 }; 215 start.join(end).unwrap_or(start) 216 } 217 218 /// Render the error as an invocation of [`compile_error!`]. 219 /// 220 /// The [`parse_macro_input!`] macro provides a convenient way to invoke 221 /// this method correctly in a procedural macro. 222 /// 223 /// [`compile_error!`]: std::compile_error! 224 /// [`parse_macro_input!`]: crate::parse_macro_input! to_compile_errornull225 pub fn to_compile_error(&self) -> TokenStream { 226 self.messages 227 .iter() 228 .map(ErrorMessage::to_compile_error) 229 .collect() 230 } 231 232 /// Render the error as an invocation of [`compile_error!`]. 233 /// 234 /// [`compile_error!`]: std::compile_error! 235 /// 236 /// # Example 237 /// 238 /// ``` 239 /// # extern crate proc_macro; 240 /// # 241 /// use proc_macro::TokenStream; 242 /// use syn::{parse_macro_input, DeriveInput, Error}; 243 /// 244 /// # const _: &str = stringify! { 245 /// #[proc_macro_derive(MyTrait)] 246 /// # }; 247 /// pub fn derive_my_trait(input: TokenStream) -> TokenStream { 248 /// let input = parse_macro_input!(input as DeriveInput); 249 /// my_trait::expand(input) 250 /// .unwrap_or_else(Error::into_compile_error) 251 /// .into() 252 /// } 253 /// 254 /// mod my_trait { 255 /// use proc_macro2::TokenStream; 256 /// use syn::{DeriveInput, Result}; 257 /// 258 /// pub(crate) fn expand(input: DeriveInput) -> Result<TokenStream> { 259 /// /* ... */ 260 /// # unimplemented!() 261 /// } 262 /// } 263 /// ``` into_compile_errornull264 pub fn into_compile_error(self) -> TokenStream { 265 self.to_compile_error() 266 } 267 268 /// Add another error message to self such that when `to_compile_error()` is 269 /// called, both errors will be emitted together. combinenull270 pub fn combine(&mut self, another: Error) { 271 self.messages.extend(another.messages); 272 } 273 } 274 275 impl ErrorMessage { to_compile_errornull276 fn to_compile_error(&self) -> TokenStream { 277 let (start, end) = match self.span.get() { 278 Some(range) => (range.start, range.end), 279 None => (Span::call_site(), Span::call_site()), 280 }; 281 282 // ::core::compile_error!($message) 283 TokenStream::from_iter(vec![ 284 TokenTree::Punct({ 285 let mut punct = Punct::new(':', Spacing::Joint); 286 punct.set_span(start); 287 punct 288 }), 289 TokenTree::Punct({ 290 let mut punct = Punct::new(':', Spacing::Alone); 291 punct.set_span(start); 292 punct 293 }), 294 TokenTree::Ident(Ident::new("core", start)), 295 TokenTree::Punct({ 296 let mut punct = Punct::new(':', Spacing::Joint); 297 punct.set_span(start); 298 punct 299 }), 300 TokenTree::Punct({ 301 let mut punct = Punct::new(':', Spacing::Alone); 302 punct.set_span(start); 303 punct 304 }), 305 TokenTree::Ident(Ident::new("compile_error", start)), 306 TokenTree::Punct({ 307 let mut punct = Punct::new('!', Spacing::Alone); 308 punct.set_span(start); 309 punct 310 }), 311 TokenTree::Group({ 312 let mut group = Group::new(Delimiter::Brace, { 313 TokenStream::from_iter(vec![TokenTree::Literal({ 314 let mut string = Literal::string(&self.message); 315 string.set_span(end); 316 string 317 })]) 318 }); 319 group.set_span(end); 320 group 321 }), 322 ]) 323 } 324 } 325 326 #[cfg(feature = "parsing")] 327 pub(crate) fn new_at<T: Display>(scope: Span, cursor: Cursor, message: T) -> Error { 328 if cursor.eof() { 329 Error::new(scope, format!("unexpected end of input, {}", message)) 330 } else { 331 let span = crate::buffer::open_span_of_group(cursor); 332 Error::new(span, message) 333 } 334 } 335 336 #[cfg(all(feature = "parsing", any(feature = "full", feature = "derive")))] 337 pub(crate) fn new2<T: Display>(start: Span, end: Span, message: T) -> Error { 338 return new2(start, end, message.to_string()); 339 new2null340 fn new2(start: Span, end: Span, message: String) -> Error { 341 Error { 342 messages: vec![ErrorMessage { 343 span: ThreadBound::new(SpanRange { start, end }), 344 message, 345 }], 346 } 347 } 348 } 349 350 impl Debug for Error { fmtnull351 fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { 352 if self.messages.len() == 1 { 353 formatter 354 .debug_tuple("Error") 355 .field(&self.messages[0]) 356 .finish() 357 } else { 358 formatter 359 .debug_tuple("Error") 360 .field(&self.messages) 361 .finish() 362 } 363 } 364 } 365 366 impl Debug for ErrorMessage { fmtnull367 fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { 368 Debug::fmt(&self.message, formatter) 369 } 370 } 371 372 impl Display for Error { fmtnull373 fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { 374 formatter.write_str(&self.messages[0].message) 375 } 376 } 377 378 impl Clone for Error { clonenull379 fn clone(&self) -> Self { 380 Error { 381 messages: self.messages.clone(), 382 } 383 } 384 } 385 386 impl Clone for ErrorMessage { clonenull387 fn clone(&self) -> Self { 388 ErrorMessage { 389 span: self.span, 390 message: self.message.clone(), 391 } 392 } 393 } 394 395 impl Clone for SpanRange { clonenull396 fn clone(&self) -> Self { 397 *self 398 } 399 } 400 401 impl Copy for SpanRange {} 402 403 impl std::error::Error for Error {} 404 405 impl From<LexError> for Error { fromnull406 fn from(err: LexError) -> Self { 407 Error::new(err.span(), err) 408 } 409 } 410 411 impl IntoIterator for Error { 412 type Item = Error; 413 type IntoIter = IntoIter; 414 into_iternull415 fn into_iter(self) -> Self::IntoIter { 416 IntoIter { 417 messages: self.messages.into_iter(), 418 } 419 } 420 } 421 422 pub struct IntoIter { 423 messages: vec::IntoIter<ErrorMessage>, 424 } 425 426 impl Iterator for IntoIter { 427 type Item = Error; 428 nextnull429 fn next(&mut self) -> Option<Self::Item> { 430 Some(Error { 431 messages: vec![self.messages.next()?], 432 }) 433 } 434 } 435 436 impl<'a> IntoIterator for &'a Error { 437 type Item = Error; 438 type IntoIter = Iter<'a>; 439 into_iternull440 fn into_iter(self) -> Self::IntoIter { 441 Iter { 442 messages: self.messages.iter(), 443 } 444 } 445 } 446 447 pub struct Iter<'a> { 448 messages: slice::Iter<'a, ErrorMessage>, 449 } 450 451 impl<'a> Iterator for Iter<'a> { 452 type Item = Error; 453 nextnull454 fn next(&mut self) -> Option<Self::Item> { 455 Some(Error { 456 messages: vec![self.messages.next()?.clone()], 457 }) 458 } 459 } 460 461 impl Extend<Error> for Error { extendnull462 fn extend<T: IntoIterator<Item = Error>>(&mut self, iter: T) { 463 for err in iter { 464 self.combine(err); 465 } 466 } 467 } 468