extra.rs 5.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153
  1. // SPDX-License-Identifier: Apache-2.0 OR MIT
  2. //! Items which do not have a correspondence to any API in the proc_macro crate,
  3. //! but are necessary to include in proc-macro2.
  4. use crate::fallback;
  5. use crate::imp;
  6. use crate::marker::{ProcMacroAutoTraits, MARKER};
  7. use crate::Span;
  8. use core::fmt::{self, Debug};
  9. /// Invalidate any `proc_macro2::Span` that exist on the current thread.
  10. ///
  11. /// The implementation of `Span` uses thread-local data structures and this
  12. /// function clears them. Calling any method on a `Span` on the current thread
  13. /// created prior to the invalidation will return incorrect values or crash.
  14. ///
  15. /// This function is useful for programs that process more than 2<sup>32</sup>
  16. /// bytes of Rust source code on the same thread. Just like rustc, proc-macro2
  17. /// uses 32-bit source locations, and these wrap around when the total source
  18. /// code processed by the same thread exceeds 2<sup>32</sup> bytes (4
  19. /// gigabytes). After a wraparound, `Span` methods such as `source_text()` can
  20. /// return wrong data.
  21. ///
  22. /// # Example
  23. ///
  24. /// As of late 2023, there is 200 GB of Rust code published on crates.io.
  25. /// Looking at just the newest version of every crate, it is 16 GB of code. So a
  26. /// workload that involves parsing it all would overflow a 32-bit source
  27. /// location unless spans are being invalidated.
  28. ///
  29. /// ```
  30. /// use flate2::read::GzDecoder;
  31. /// use std::ffi::OsStr;
  32. /// use std::io::{BufReader, Read};
  33. /// use std::str::FromStr;
  34. /// use tar::Archive;
  35. ///
  36. /// rayon::scope(|s| {
  37. /// for krate in every_version_of_every_crate() {
  38. /// s.spawn(move |_| {
  39. /// proc_macro2::extra::invalidate_current_thread_spans();
  40. ///
  41. /// let reader = BufReader::new(krate);
  42. /// let tar = GzDecoder::new(reader);
  43. /// let mut archive = Archive::new(tar);
  44. /// for entry in archive.entries().unwrap() {
  45. /// let mut entry = entry.unwrap();
  46. /// let path = entry.path().unwrap();
  47. /// if path.extension() != Some(OsStr::new("rs")) {
  48. /// continue;
  49. /// }
  50. /// let mut content = String::new();
  51. /// entry.read_to_string(&mut content).unwrap();
  52. /// match proc_macro2::TokenStream::from_str(&content) {
  53. /// Ok(tokens) => {/* ... */},
  54. /// Err(_) => continue,
  55. /// }
  56. /// }
  57. /// });
  58. /// }
  59. /// });
  60. /// #
  61. /// # fn every_version_of_every_crate() -> Vec<std::fs::File> {
  62. /// # Vec::new()
  63. /// # }
  64. /// ```
  65. ///
  66. /// # Panics
  67. ///
  68. /// This function is not applicable to and will panic if called from a
  69. /// procedural macro.
  70. #[cfg(span_locations)]
  71. #[cfg_attr(docsrs, doc(cfg(feature = "span-locations")))]
  72. pub fn invalidate_current_thread_spans() {
  73. crate::imp::invalidate_current_thread_spans();
  74. }
  75. /// An object that holds a [`Group`]'s `span_open()` and `span_close()` together
  76. /// in a more compact representation than holding those 2 spans individually.
  77. ///
  78. /// [`Group`]: crate::Group
  79. #[derive(Copy, Clone)]
  80. pub struct DelimSpan {
  81. inner: DelimSpanEnum,
  82. _marker: ProcMacroAutoTraits,
  83. }
  84. #[derive(Copy, Clone)]
  85. enum DelimSpanEnum {
  86. #[cfg(wrap_proc_macro)]
  87. Compiler {
  88. join: proc_macro::Span,
  89. open: proc_macro::Span,
  90. close: proc_macro::Span,
  91. },
  92. Fallback(fallback::Span),
  93. }
  94. impl DelimSpan {
  95. pub(crate) fn new(group: &imp::Group) -> Self {
  96. #[cfg(wrap_proc_macro)]
  97. let inner = match group {
  98. imp::Group::Compiler(group) => DelimSpanEnum::Compiler {
  99. join: group.span(),
  100. open: group.span_open(),
  101. close: group.span_close(),
  102. },
  103. imp::Group::Fallback(group) => DelimSpanEnum::Fallback(group.span()),
  104. };
  105. #[cfg(not(wrap_proc_macro))]
  106. let inner = DelimSpanEnum::Fallback(group.span());
  107. DelimSpan {
  108. inner,
  109. _marker: MARKER,
  110. }
  111. }
  112. /// Returns a span covering the entire delimited group.
  113. pub fn join(&self) -> Span {
  114. match &self.inner {
  115. #[cfg(wrap_proc_macro)]
  116. DelimSpanEnum::Compiler { join, .. } => Span::_new(imp::Span::Compiler(*join)),
  117. DelimSpanEnum::Fallback(span) => Span::_new_fallback(*span),
  118. }
  119. }
  120. /// Returns a span for the opening punctuation of the group only.
  121. pub fn open(&self) -> Span {
  122. match &self.inner {
  123. #[cfg(wrap_proc_macro)]
  124. DelimSpanEnum::Compiler { open, .. } => Span::_new(imp::Span::Compiler(*open)),
  125. DelimSpanEnum::Fallback(span) => Span::_new_fallback(span.first_byte()),
  126. }
  127. }
  128. /// Returns a span for the closing punctuation of the group only.
  129. pub fn close(&self) -> Span {
  130. match &self.inner {
  131. #[cfg(wrap_proc_macro)]
  132. DelimSpanEnum::Compiler { close, .. } => Span::_new(imp::Span::Compiler(*close)),
  133. DelimSpanEnum::Fallback(span) => Span::_new_fallback(span.last_byte()),
  134. }
  135. }
  136. }
  137. impl Debug for DelimSpan {
  138. fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
  139. Debug::fmt(&self.join(), f)
  140. }
  141. }