summaryrefslogtreecommitdiffstats
path: root/src/extra.rs
diff options
context:
space:
mode:
Diffstat (limited to 'src/extra.rs')
-rw-r--r--src/extra.rs75
1 files changed, 71 insertions, 4 deletions
diff --git a/src/extra.rs b/src/extra.rs
index 4a69d46..543ec1d 100644
--- a/src/extra.rs
+++ b/src/extra.rs
@@ -3,18 +3,85 @@
use crate::fallback;
use crate::imp;
-use crate::marker::Marker;
+use crate::marker::{ProcMacroAutoTraits, MARKER};
use crate::Span;
use core::fmt::{self, Debug};
+/// Invalidate any `proc_macro2::Span` that exist on the current thread.
+///
+/// The implementation of `Span` uses thread-local data structures and this
+/// function clears them. Calling any method on a `Span` on the current thread
+/// created prior to the invalidation will return incorrect values or crash.
+///
+/// This function is useful for programs that process more than 2<sup>32</sup>
+/// bytes of Rust source code on the same thread. Just like rustc, proc-macro2
+/// uses 32-bit source locations, and these wrap around when the total source
+/// code processed by the same thread exceeds 2<sup>32</sup> bytes (4
+/// gigabytes). After a wraparound, `Span` methods such as `source_text()` can
+/// return wrong data.
+///
+/// # Example
+///
+/// As of late 2023, there is 200 GB of Rust code published on crates.io.
+/// Looking at just the newest version of every crate, it is 16 GB of code. So a
+/// workload that involves parsing it all would overflow a 32-bit source
+/// location unless spans are being invalidated.
+///
+/// ```
+/// use flate2::read::GzDecoder;
+/// use std::ffi::OsStr;
+/// use std::io::{BufReader, Read};
+/// use std::str::FromStr;
+/// use tar::Archive;
+///
+/// rayon::scope(|s| {
+/// for krate in every_version_of_every_crate() {
+/// s.spawn(move |_| {
+/// proc_macro2::extra::invalidate_current_thread_spans();
+///
+/// let reader = BufReader::new(krate);
+/// let tar = GzDecoder::new(reader);
+/// let mut archive = Archive::new(tar);
+/// for entry in archive.entries().unwrap() {
+/// let mut entry = entry.unwrap();
+/// let path = entry.path().unwrap();
+/// if path.extension() != Some(OsStr::new("rs")) {
+/// continue;
+/// }
+/// let mut content = String::new();
+/// entry.read_to_string(&mut content).unwrap();
+/// match proc_macro2::TokenStream::from_str(&content) {
+/// Ok(tokens) => {/* ... */},
+/// Err(_) => continue,
+/// }
+/// }
+/// });
+/// }
+/// });
+/// #
+/// # fn every_version_of_every_crate() -> Vec<std::fs::File> {
+/// # Vec::new()
+/// # }
+/// ```
+///
+/// # Panics
+///
+/// This function is not applicable to and will panic if called from a
+/// procedural macro.
+#[cfg(span_locations)]
+#[cfg_attr(doc_cfg, doc(cfg(feature = "span-locations")))]
+pub fn invalidate_current_thread_spans() {
+ crate::imp::invalidate_current_thread_spans();
+}
+
/// An object that holds a [`Group`]'s `span_open()` and `span_close()` together
-/// (in a more compact representation than holding those 2 spans individually.
+/// in a more compact representation than holding those 2 spans individually.
///
/// [`Group`]: crate::Group
#[derive(Copy, Clone)]
pub struct DelimSpan {
inner: DelimSpanEnum,
- _marker: Marker,
+ _marker: ProcMacroAutoTraits,
}
#[derive(Copy, Clone)]
@@ -45,7 +112,7 @@ impl DelimSpan {
DelimSpan {
inner,
- _marker: Marker,
+ _marker: MARKER,
}
}