summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-05-04 05:38:31 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-05-04 05:38:31 +0000
commit017a0f00b2f35e8f0d3c5175d558cd4e706c305d (patch)
tree669ae5e120a957271aafa639969279bac10004e4 /src
parentReleasing progress-linux version 1.0.76-1~progress7.99u1. (diff)
downloadrust-proc-macro2-017a0f00b2f35e8f0d3c5175d558cd4e706c305d.tar.xz
rust-proc-macro2-017a0f00b2f35e8f0d3c5175d558cd4e706c305d.zip
Merging upstream version 1.0.81.
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'src')
-rw-r--r--src/extra.rs75
-rw-r--r--src/fallback.rs207
-rw-r--r--src/lib.rs81
-rw-r--r--src/marker.rs18
-rw-r--r--src/wrapper.rs75
5 files changed, 347 insertions, 109 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,
}
}
diff --git a/src/fallback.rs b/src/fallback.rs
index 7b40427..b42537b 100644
--- a/src/fallback.rs
+++ b/src/fallback.rs
@@ -11,9 +11,13 @@ use core::cell::RefCell;
use core::cmp;
use core::fmt::{self, Debug, Display, Write};
use core::mem::ManuallyDrop;
+#[cfg(span_locations)]
+use core::ops::Range;
use core::ops::RangeBounds;
use core::ptr;
-use core::str::FromStr;
+use core::str::{self, FromStr};
+use std::ffi::CStr;
+#[cfg(procmacro2_semver_exempt)]
use std::path::PathBuf;
/// Force use of proc-macro2's fallback implementation of the API for now, even
@@ -151,9 +155,9 @@ fn get_cursor(src: &str) -> Cursor {
// Create a dummy file & add it to the source map
#[cfg(not(fuzzing))]
- SOURCE_MAP.with(|cm| {
- let mut cm = cm.borrow_mut();
- let span = cm.add_file(src);
+ SOURCE_MAP.with(|sm| {
+ let mut sm = sm.borrow_mut();
+ let span = sm.add_file(src);
Cursor {
rest: src,
off: span.lo,
@@ -295,11 +299,13 @@ impl IntoIterator for TokenStream {
}
}
+#[cfg(procmacro2_semver_exempt)]
#[derive(Clone, PartialEq, Eq)]
pub(crate) struct SourceFile {
path: PathBuf,
}
+#[cfg(procmacro2_semver_exempt)]
impl SourceFile {
/// Get the path to this source file as a string.
pub fn path(&self) -> PathBuf {
@@ -311,6 +317,7 @@ impl SourceFile {
}
}
+#[cfg(procmacro2_semver_exempt)]
impl Debug for SourceFile {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
f.debug_struct("SourceFile")
@@ -334,6 +341,12 @@ thread_local! {
});
}
+#[cfg(span_locations)]
+pub(crate) fn invalidate_current_thread_spans() {
+ #[cfg(not(fuzzing))]
+ SOURCE_MAP.with(|sm| sm.borrow_mut().files.truncate(1));
+}
+
#[cfg(all(span_locations, not(fuzzing)))]
struct FileInfo {
source_text: String,
@@ -366,7 +379,7 @@ impl FileInfo {
span.lo >= self.span.lo && span.hi <= self.span.hi
}
- fn source_text(&mut self, span: Span) -> String {
+ fn byte_range(&mut self, span: Span) -> Range<usize> {
let lo_char = (span.lo - self.span.lo) as usize;
// Look up offset of the largest already-computed char index that is
@@ -395,11 +408,15 @@ impl FileInfo {
let trunc_lo = &self.source_text[lo_byte..];
let char_len = (span.hi - span.lo) as usize;
- let source_text = match trunc_lo.char_indices().nth(char_len) {
- Some((offset, _ch)) => &trunc_lo[..offset],
- None => trunc_lo,
- };
- source_text.to_owned()
+ lo_byte..match trunc_lo.char_indices().nth(char_len) {
+ Some((offset, _ch)) => lo_byte + offset,
+ None => self.source_text.len(),
+ }
+ }
+
+ fn source_text(&mut self, span: Span) -> String {
+ let byte_range = self.byte_range(span);
+ self.source_text[byte_range].to_owned()
}
}
@@ -534,22 +551,37 @@ impl Span {
};
#[cfg(not(fuzzing))]
- SOURCE_MAP.with(|cm| {
- let cm = cm.borrow();
- let path = cm.filepath(*self);
+ SOURCE_MAP.with(|sm| {
+ let sm = sm.borrow();
+ let path = sm.filepath(*self);
SourceFile { path }
})
}
#[cfg(span_locations)]
+ pub fn byte_range(&self) -> Range<usize> {
+ #[cfg(fuzzing)]
+ return 0..0;
+
+ #[cfg(not(fuzzing))]
+ {
+ if self.is_call_site() {
+ 0..0
+ } else {
+ SOURCE_MAP.with(|sm| sm.borrow_mut().fileinfo_mut(*self).byte_range(*self))
+ }
+ }
+ }
+
+ #[cfg(span_locations)]
pub fn start(&self) -> LineColumn {
#[cfg(fuzzing)]
return LineColumn { line: 0, column: 0 };
#[cfg(not(fuzzing))]
- SOURCE_MAP.with(|cm| {
- let cm = cm.borrow();
- let fi = cm.fileinfo(*self);
+ SOURCE_MAP.with(|sm| {
+ let sm = sm.borrow();
+ let fi = sm.fileinfo(*self);
fi.offset_line_column(self.lo as usize)
})
}
@@ -560,9 +592,9 @@ impl Span {
return LineColumn { line: 0, column: 0 };
#[cfg(not(fuzzing))]
- SOURCE_MAP.with(|cm| {
- let cm = cm.borrow();
- let fi = cm.fileinfo(*self);
+ SOURCE_MAP.with(|sm| {
+ let sm = sm.borrow();
+ let fi = sm.fileinfo(*self);
fi.offset_line_column(self.hi as usize)
})
}
@@ -581,10 +613,10 @@ impl Span {
};
#[cfg(not(fuzzing))]
- SOURCE_MAP.with(|cm| {
- let cm = cm.borrow();
+ SOURCE_MAP.with(|sm| {
+ let sm = sm.borrow();
// If `other` is not within the same FileInfo as us, return None.
- if !cm.fileinfo(*self).span_within(other) {
+ if !sm.fileinfo(*self).span_within(other) {
return None;
}
Some(Span {
@@ -609,7 +641,7 @@ impl Span {
if self.is_call_site() {
None
} else {
- Some(SOURCE_MAP.with(|cm| cm.borrow_mut().fileinfo_mut(*self).source_text(*self)))
+ Some(SOURCE_MAP.with(|sm| sm.borrow_mut().fileinfo_mut(*self).source_text(*self)))
}
}
}
@@ -895,7 +927,7 @@ impl Debug for Ident {
#[derive(Clone)]
pub(crate) struct Literal {
- repr: String,
+ pub(crate) repr: String,
span: Span,
}
@@ -976,71 +1008,98 @@ impl Literal {
Literal::_new(s)
}
- pub fn string(t: &str) -> Literal {
- let mut repr = String::with_capacity(t.len() + 2);
+ pub fn string(string: &str) -> Literal {
+ let mut repr = String::with_capacity(string.len() + 2);
repr.push('"');
- let mut chars = t.chars();
- while let Some(ch) = chars.next() {
- if ch == '\0' {
- repr.push_str(
- if chars
- .as_str()
- .starts_with(|next| '0' <= next && next <= '7')
- {
- // circumvent clippy::octal_escapes lint
- "\\x00"
- } else {
- "\\0"
- },
- );
- } else if ch == '\'' {
- // escape_debug turns this into "\'" which is unnecessary.
- repr.push(ch);
- } else {
- repr.extend(ch.escape_debug());
- }
- }
+ escape_utf8(string, &mut repr);
repr.push('"');
Literal::_new(repr)
}
- pub fn character(t: char) -> Literal {
+ pub fn character(ch: char) -> Literal {
let mut repr = String::new();
repr.push('\'');
- if t == '"' {
+ if ch == '"' {
// escape_debug turns this into '\"' which is unnecessary.
- repr.push(t);
+ repr.push(ch);
} else {
- repr.extend(t.escape_debug());
+ repr.extend(ch.escape_debug());
+ }
+ repr.push('\'');
+ Literal::_new(repr)
+ }
+
+ pub fn byte_character(byte: u8) -> Literal {
+ let mut repr = "b'".to_string();
+ #[allow(clippy::match_overlapping_arm)]
+ match byte {
+ b'\0' => repr.push_str(r"\0"),
+ b'\t' => repr.push_str(r"\t"),
+ b'\n' => repr.push_str(r"\n"),
+ b'\r' => repr.push_str(r"\r"),
+ b'\'' => repr.push_str(r"\'"),
+ b'\\' => repr.push_str(r"\\"),
+ b'\x20'..=b'\x7E' => repr.push(byte as char),
+ _ => {
+ let _ = write!(repr, r"\x{:02X}", byte);
+ }
}
repr.push('\'');
Literal::_new(repr)
}
pub fn byte_string(bytes: &[u8]) -> Literal {
- let mut escaped = "b\"".to_string();
+ let mut repr = "b\"".to_string();
let mut bytes = bytes.iter();
while let Some(&b) = bytes.next() {
#[allow(clippy::match_overlapping_arm)]
match b {
- b'\0' => escaped.push_str(match bytes.as_slice().first() {
+ b'\0' => repr.push_str(match bytes.as_slice().first() {
// circumvent clippy::octal_escapes lint
Some(b'0'..=b'7') => r"\x00",
_ => r"\0",
}),
- b'\t' => escaped.push_str(r"\t"),
- b'\n' => escaped.push_str(r"\n"),
- b'\r' => escaped.push_str(r"\r"),
- b'"' => escaped.push_str("\\\""),
- b'\\' => escaped.push_str("\\\\"),
- b'\x20'..=b'\x7E' => escaped.push(b as char),
+ b'\t' => repr.push_str(r"\t"),
+ b'\n' => repr.push_str(r"\n"),
+ b'\r' => repr.push_str(r"\r"),
+ b'"' => repr.push_str("\\\""),
+ b'\\' => repr.push_str(r"\\"),
+ b'\x20'..=b'\x7E' => repr.push(b as char),
_ => {
- let _ = write!(escaped, "\\x{:02X}", b);
+ let _ = write!(repr, r"\x{:02X}", b);
+ }
+ }
+ }
+ repr.push('"');
+ Literal::_new(repr)
+ }
+
+ pub fn c_string(string: &CStr) -> Literal {
+ let mut repr = "c\"".to_string();
+ let mut bytes = string.to_bytes();
+ while !bytes.is_empty() {
+ let (valid, invalid) = match str::from_utf8(bytes) {
+ Ok(all_valid) => {
+ bytes = b"";
+ (all_valid, bytes)
+ }
+ Err(utf8_error) => {
+ let (valid, rest) = bytes.split_at(utf8_error.valid_up_to());
+ let valid = str::from_utf8(valid).unwrap();
+ let invalid = utf8_error
+ .error_len()
+ .map_or(rest, |error_len| &rest[..error_len]);
+ bytes = &bytes[valid.len() + invalid.len()..];
+ (valid, invalid)
}
+ };
+ escape_utf8(valid, &mut repr);
+ for &byte in invalid {
+ let _ = write!(repr, r"\x{:02X}", byte);
}
}
- escaped.push('"');
- Literal::_new(escaped)
+ repr.push('"');
+ Literal::_new(repr)
}
pub fn span(&self) -> Span {
@@ -1141,3 +1200,27 @@ impl Debug for Literal {
debug.finish()
}
}
+
+fn escape_utf8(string: &str, repr: &mut String) {
+ let mut chars = string.chars();
+ while let Some(ch) = chars.next() {
+ if ch == '\0' {
+ repr.push_str(
+ if chars
+ .as_str()
+ .starts_with(|next| '0' <= next && next <= '7')
+ {
+ // circumvent clippy::octal_escapes lint
+ r"\x00"
+ } else {
+ r"\0"
+ },
+ );
+ } else if ch == '\'' {
+ // escape_debug turns this into "\'" which is unnecessary.
+ repr.push(ch);
+ } else {
+ repr.extend(ch.escape_debug());
+ }
+ }
+}
diff --git a/src/lib.rs b/src/lib.rs
index 7e8f543..93d7e5b 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -86,7 +86,7 @@
//! a different thread.
// Proc-macro2 types in rustdoc of other crates get linked to here.
-#![doc(html_root_url = "https://docs.rs/proc-macro2/1.0.76")]
+#![doc(html_root_url = "https://docs.rs/proc-macro2/1.0.81")]
#![cfg_attr(any(proc_macro_span, super_unstable), feature(proc_macro_span))]
#![cfg_attr(super_unstable, feature(proc_macro_def_site))]
#![cfg_attr(doc_cfg, feature(doc_cfg))]
@@ -96,6 +96,7 @@
clippy::cast_possible_truncation,
clippy::checked_conversions,
clippy::doc_markdown,
+ clippy::incompatible_msrv,
clippy::items_after_statements,
clippy::iter_without_into_iter,
clippy::let_underscore_untyped,
@@ -160,13 +161,16 @@ mod imp;
mod location;
use crate::extra::DelimSpan;
-use crate::marker::Marker;
+use crate::marker::{ProcMacroAutoTraits, MARKER};
use core::cmp::Ordering;
use core::fmt::{self, Debug, Display};
use core::hash::{Hash, Hasher};
+#[cfg(span_locations)]
+use core::ops::Range;
use core::ops::RangeBounds;
use core::str::FromStr;
use std::error::Error;
+use std::ffi::CStr;
#[cfg(procmacro2_semver_exempt)]
use std::path::PathBuf;
@@ -184,27 +188,27 @@ pub use crate::location::LineColumn;
#[derive(Clone)]
pub struct TokenStream {
inner: imp::TokenStream,
- _marker: Marker,
+ _marker: ProcMacroAutoTraits,
}
/// Error returned from `TokenStream::from_str`.
pub struct LexError {
inner: imp::LexError,
- _marker: Marker,
+ _marker: ProcMacroAutoTraits,
}
impl TokenStream {
fn _new(inner: imp::TokenStream) -> Self {
TokenStream {
inner,
- _marker: Marker,
+ _marker: MARKER,
}
}
fn _new_fallback(inner: fallback::TokenStream) -> Self {
TokenStream {
inner: inner.into(),
- _marker: Marker,
+ _marker: MARKER,
}
}
@@ -241,7 +245,7 @@ impl FromStr for TokenStream {
fn from_str(src: &str) -> Result<TokenStream, LexError> {
let e = src.parse().map_err(|e| LexError {
inner: e,
- _marker: Marker,
+ _marker: MARKER,
})?;
Ok(TokenStream::_new(e))
}
@@ -339,7 +343,7 @@ impl Error for LexError {}
#[derive(Clone, PartialEq, Eq)]
pub struct SourceFile {
inner: imp::SourceFile,
- _marker: Marker,
+ _marker: ProcMacroAutoTraits,
}
#[cfg(all(procmacro2_semver_exempt, any(not(wrap_proc_macro), super_unstable)))]
@@ -347,7 +351,7 @@ impl SourceFile {
fn _new(inner: imp::SourceFile) -> Self {
SourceFile {
inner,
- _marker: Marker,
+ _marker: MARKER,
}
}
@@ -386,21 +390,21 @@ impl Debug for SourceFile {
#[derive(Copy, Clone)]
pub struct Span {
inner: imp::Span,
- _marker: Marker,
+ _marker: ProcMacroAutoTraits,
}
impl Span {
fn _new(inner: imp::Span) -> Self {
Span {
inner,
- _marker: Marker,
+ _marker: MARKER,
}
}
fn _new_fallback(inner: fallback::Span) -> Self {
Span {
inner: inner.into(),
- _marker: Marker,
+ _marker: MARKER,
}
}
@@ -472,6 +476,21 @@ impl Span {
SourceFile::_new(self.inner.source_file())
}
+ /// Returns the span's byte position range in the source file.
+ ///
+ /// This method requires the `"span-locations"` feature to be enabled.
+ ///
+ /// When executing in a procedural macro context, the returned range is only
+ /// accurate if compiled with a nightly toolchain. The stable toolchain does
+ /// not have this information available. When executing outside of a
+ /// procedural macro, such as main.rs or build.rs, the byte range is always
+ /// accurate regardless of toolchain.
+ #[cfg(span_locations)]
+ #[cfg_attr(doc_cfg, doc(cfg(feature = "span-locations")))]
+ pub fn byte_range(&self) -> Range<usize> {
+ self.inner.byte_range()
+ }
+
/// Get the starting line/column in the source file for this span.
///
/// This method requires the `"span-locations"` feature to be enabled.
@@ -659,12 +678,12 @@ pub enum Delimiter {
Brace,
/// `[ ... ]`
Bracket,
- /// `Ø ... Ø`
+ /// `∅ ... ∅`
///
- /// An implicit delimiter, that may, for example, appear around tokens
+ /// An invisible delimiter, that may, for example, appear around tokens
/// coming from a "macro variable" `$var`. It is important to preserve
/// operator priorities in cases like `$var * 3` where `$var` is `1 + 2`.
- /// Implicit delimiters may not survive roundtrip of a token stream through
+ /// Invisible delimiters may not survive roundtrip of a token stream through
/// a string.
None,
}
@@ -919,14 +938,14 @@ impl Debug for Punct {
#[derive(Clone)]
pub struct Ident {
inner: imp::Ident,
- _marker: Marker,
+ _marker: ProcMacroAutoTraits,
}
impl Ident {
fn _new(inner: imp::Ident) -> Self {
Ident {
inner,
- _marker: Marker,
+ _marker: MARKER,
}
}
@@ -1046,7 +1065,7 @@ impl Debug for Ident {
#[derive(Clone)]
pub struct Literal {
inner: imp::Literal,
- _marker: Marker,
+ _marker: ProcMacroAutoTraits,
}
macro_rules! suffixed_int_literals {
@@ -1093,14 +1112,14 @@ impl Literal {
fn _new(inner: imp::Literal) -> Self {
Literal {
inner,
- _marker: Marker,
+ _marker: MARKER,
}
}
fn _new_fallback(inner: fallback::Literal) -> Self {
Literal {
inner: inner.into(),
- _marker: Marker,
+ _marker: MARKER,
}
}
@@ -1216,9 +1235,19 @@ impl Literal {
Literal::_new(imp::Literal::character(ch))
}
+ /// Byte character literal.
+ pub fn byte_character(byte: u8) -> Literal {
+ Literal::_new(imp::Literal::byte_character(byte))
+ }
+
/// Byte string literal.
- pub fn byte_string(s: &[u8]) -> Literal {
- Literal::_new(imp::Literal::byte_string(s))
+ pub fn byte_string(bytes: &[u8]) -> Literal {
+ Literal::_new(imp::Literal::byte_string(bytes))
+ }
+
+ /// C string literal.
+ pub fn c_string(string: &CStr) -> Literal {
+ Literal::_new(imp::Literal::c_string(string))
}
/// Returns the span encompassing this literal.
@@ -1260,7 +1289,7 @@ impl FromStr for Literal {
fn from_str(repr: &str) -> Result<Self, LexError> {
repr.parse().map(Literal::_new).map_err(|inner| LexError {
inner,
- _marker: Marker,
+ _marker: MARKER,
})
}
}
@@ -1279,7 +1308,7 @@ impl Display for Literal {
/// Public implementation details for the `TokenStream` type, such as iterators.
pub mod token_stream {
- use crate::marker::Marker;
+ use crate::marker::{ProcMacroAutoTraits, MARKER};
use crate::{imp, TokenTree};
use core::fmt::{self, Debug};
@@ -1292,7 +1321,7 @@ pub mod token_stream {
#[derive(Clone)]
pub struct IntoIter {
inner: imp::TokenTreeIter,
- _marker: Marker,
+ _marker: ProcMacroAutoTraits,
}
impl Iterator for IntoIter {
@@ -1321,7 +1350,7 @@ pub mod token_stream {
fn into_iter(self) -> IntoIter {
IntoIter {
inner: self.inner.into_iter(),
- _marker: Marker,
+ _marker: MARKER,
}
}
}
diff --git a/src/marker.rs b/src/marker.rs
index e8874bd..23b94ce 100644
--- a/src/marker.rs
+++ b/src/marker.rs
@@ -4,18 +4,14 @@ use core::panic::{RefUnwindSafe, UnwindSafe};
// Zero sized marker with the correct set of autotrait impls we want all proc
// macro types to have.
-pub(crate) type Marker = PhantomData<ProcMacroAutoTraits>;
+#[derive(Copy, Clone)]
+#[cfg_attr(
+ all(procmacro2_semver_exempt, any(not(wrap_proc_macro), super_unstable)),
+ derive(PartialEq, Eq)
+)]
+pub(crate) struct ProcMacroAutoTraits(PhantomData<Rc<()>>);
-pub(crate) use self::value::*;
-
-mod value {
- pub(crate) use core::marker::PhantomData as Marker;
-}
-
-pub(crate) struct ProcMacroAutoTraits(
- #[allow(dead_code)] // https://github.com/rust-lang/rust/issues/119645
- Rc<()>,
-);
+pub(crate) const MARKER: ProcMacroAutoTraits = ProcMacroAutoTraits(PhantomData);
impl UnwindSafe for ProcMacroAutoTraits {}
impl RefUnwindSafe for ProcMacroAutoTraits {}
diff --git a/src/wrapper.rs b/src/wrapper.rs
index f5eb826..87e348d 100644
--- a/src/wrapper.rs
+++ b/src/wrapper.rs
@@ -3,8 +3,11 @@ use crate::detection::inside_proc_macro;
use crate::location::LineColumn;
use crate::{fallback, Delimiter, Punct, Spacing, TokenTree};
use core::fmt::{self, Debug, Display};
+#[cfg(span_locations)]
+use core::ops::Range;
use core::ops::RangeBounds;
use core::str::FromStr;
+use std::ffi::CStr;
use std::panic;
#[cfg(super_unstable)]
use std::path::PathBuf;
@@ -461,6 +464,17 @@ impl Span {
}
#[cfg(span_locations)]
+ pub fn byte_range(&self) -> Range<usize> {
+ match self {
+ #[cfg(proc_macro_span)]
+ Span::Compiler(s) => s.byte_range(),
+ #[cfg(not(proc_macro_span))]
+ Span::Compiler(_) => 0..0,
+ Span::Fallback(s) => s.byte_range(),
+ }
+ }
+
+ #[cfg(span_locations)]
pub fn start(&self) -> LineColumn {
match self {
Span::Compiler(_) => LineColumn { line: 0, column: 0 },
@@ -833,19 +847,38 @@ impl Literal {
}
}
- pub fn string(t: &str) -> Literal {
+ pub fn string(string: &str) -> Literal {
if inside_proc_macro() {
- Literal::Compiler(proc_macro::Literal::string(t))
+ Literal::Compiler(proc_macro::Literal::string(string))
} else {
- Literal::Fallback(fallback::Literal::string(t))
+ Literal::Fallback(fallback::Literal::string(string))
}
}
- pub fn character(t: char) -> Literal {
+ pub fn character(ch: char) -> Literal {
if inside_proc_macro() {
- Literal::Compiler(proc_macro::Literal::character(t))
+ Literal::Compiler(proc_macro::Literal::character(ch))
+ } else {
+ Literal::Fallback(fallback::Literal::character(ch))
+ }
+ }
+
+ pub fn byte_character(byte: u8) -> Literal {
+ if inside_proc_macro() {
+ Literal::Compiler({
+ #[cfg(not(no_literal_byte_character))]
+ {
+ proc_macro::Literal::byte_character(byte)
+ }
+
+ #[cfg(no_literal_byte_character)]
+ {
+ let fallback = fallback::Literal::byte_character(byte);
+ fallback.repr.parse::<proc_macro::Literal>().unwrap()
+ }
+ })
} else {
- Literal::Fallback(fallback::Literal::character(t))
+ Literal::Fallback(fallback::Literal::byte_character(byte))
}
}
@@ -857,6 +890,25 @@ impl Literal {
}
}
+ pub fn c_string(string: &CStr) -> Literal {
+ if inside_proc_macro() {
+ Literal::Compiler({
+ #[cfg(not(no_literal_c_string))]
+ {
+ proc_macro::Literal::c_string(string)
+ }
+
+ #[cfg(no_literal_c_string)]
+ {
+ let fallback = fallback::Literal::c_string(string);
+ fallback.repr.parse::<proc_macro::Literal>().unwrap()
+ }
+ })
+ } else {
+ Literal::Fallback(fallback::Literal::c_string(string))
+ }
+ }
+
pub fn span(&self) -> Span {
match self {
Literal::Compiler(lit) => Span::Compiler(lit.span()),
@@ -928,3 +980,14 @@ impl Debug for Literal {
}
}
}
+
+#[cfg(span_locations)]
+pub(crate) fn invalidate_current_thread_spans() {
+ if inside_proc_macro() {
+ panic!(
+ "proc_macro2::extra::invalidate_current_thread_spans is not available in procedural macros"
+ );
+ } else {
+ crate::fallback::invalidate_current_thread_spans();
+ }
+}