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