From nobody Tue Dec 2 01:06:14 2025 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-1.web.codeaurora.org [10.30.226.201]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 4A10F314D1A; Mon, 24 Nov 2025 15:19:25 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=10.30.226.201 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1763997566; cv=none; b=YsWsitNgOtnSaMX0PSiMiGKbJvXa/JWvz02vVS3bMgngaHIn0Hzbyh6lVXrGYBEbpzw3cXf6dAebxkn4CGUjX9smdsWhpQBWh3P4JBAkc04ahLSfwPk+aRTMcfiXbJ+FCiRXhBEiTAeUgV3fCqzDZSd+ArdJ1HNlkuMoja7okN0= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1763997566; c=relaxed/simple; bh=/55FuWUTmaU2nJynd4JhaRBaiA6IgejrAOGDmO6T4Mk=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=iIz0B2LmAkj+eTQCRiJSSZpBKtAowGDdCE0+Gdc23vtUbhwHTtkECPNKd278Gje/m2hCQYG2QoiIsvCdjIlFAeTo1Q4CmK205NoLLUMAtPy1WA7zTpFn1/Qnz5j4W46vT11Jv0fX6qdxuqeo/sJ3lPY6Whs4eKc8lTmct4noW2o= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=Qb/a/qMf; arc=none smtp.client-ip=10.30.226.201 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="Qb/a/qMf" Received: by smtp.kernel.org (Postfix) with ESMTPSA id A935CC19423; Mon, 24 Nov 2025 15:19:21 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1763997565; bh=/55FuWUTmaU2nJynd4JhaRBaiA6IgejrAOGDmO6T4Mk=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=Qb/a/qMfI5AzQsXIlqK4qGQAeKX0mCeqmAO1LYdBBL0Cuvenqf8BeI2MNI+q6tp40 h75vRLyZidptFuHfJQGIKnz4u9LE9c0NyrHRwQHKT3FP24Mgj1zUD0QiV0bhrfI52x U2AVexkhnSyubRQLw0od+CyKjoBDXos7Q8Eimjo2fKoMEMkqTPi/1HfSC55kQkiA/a KRRO/x3ar/A2NagE6nRtqEpwbj98wULc5UgUljreMWJ1A2/wJIkoor1aHYkTYBfaoV emnicbk6SestlrnVql6HE6nl222Zm4nX1u/IGUmr7VHO05aeVfBCjQcfAstAiJHTHd Q/f1W+IBWbH0g== From: Miguel Ojeda To: Miguel Ojeda , Alex Gaynor , Nathan Chancellor , Nicolas Schier Cc: Boqun Feng , Gary Guo , =?UTF-8?q?Bj=C3=B6rn=20Roy=20Baron?= , Benno Lossin , Andreas Hindborg , Alice Ryhl , Trevor Gross , Danilo Krummrich , rust-for-linux@vger.kernel.org, linux-kbuild@vger.kernel.org, linux-kernel@vger.kernel.org, patches@lists.linux.dev, Jesung Yang Subject: [PATCH v2 06/20] rust: proc-macro2: import crate Date: Mon, 24 Nov 2025 16:18:18 +0100 Message-ID: <20251124151837.2184382-7-ojeda@kernel.org> In-Reply-To: <20251124151837.2184382-1-ojeda@kernel.org> References: <20251124151837.2184382-1-ojeda@kernel.org> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable This is a subset of the Rust `proc-macro2` crate, version 1.0.101 (released 2025-08-16), licensed under "Apache-2.0 OR MIT", from: https://github.com/dtolnay/proc-macro2/raw/1.0.101/src The files are copied as-is, with no modifications whatsoever (not even adding the SPDX identifiers). For copyright details, please see: https://github.com/dtolnay/proc-macro2/blob/1.0.101/README.md#license https://github.com/dtolnay/proc-macro2/blob/1.0.101/LICENSE-APACHE https://github.com/dtolnay/proc-macro2/blob/1.0.101/LICENSE-MIT The next two patches modify these files as needed for use within the kernel. This patch split allows reviewers to double-check the import and to clearly see the differences introduced. The following script may be used to verify the contents: for path in $(cd rust/proc-macro2/ && find . -type f -name '*.rs'); do curl --silent --show-error --location \ https://github.com/dtolnay/proc-macro2/raw/1.0.101/src/$path \ | diff --unified rust/proc-macro2/$path - && echo $path: OK done Reviewed-by: Gary Guo Tested-by: Gary Guo Tested-by: Jesung Yang Signed-off-by: Miguel Ojeda --- rust/proc-macro2/detection.rs | 75 + rust/proc-macro2/extra.rs | 151 ++ rust/proc-macro2/fallback.rs | 1256 +++++++++++++++ rust/proc-macro2/lib.rs | 1349 +++++++++++++++++ rust/proc-macro2/location.rs | 29 + rust/proc-macro2/marker.rs | 17 + rust/proc-macro2/parse.rs | 995 ++++++++++++ rust/proc-macro2/probe.rs | 10 + rust/proc-macro2/probe/proc_macro_span.rs | 51 + .../proc-macro2/probe/proc_macro_span_file.rs | 14 + .../probe/proc_macro_span_location.rs | 21 + rust/proc-macro2/rcvec.rs | 146 ++ rust/proc-macro2/wrapper.rs | 984 ++++++++++++ 13 files changed, 5098 insertions(+) create mode 100644 rust/proc-macro2/detection.rs create mode 100644 rust/proc-macro2/extra.rs create mode 100644 rust/proc-macro2/fallback.rs create mode 100644 rust/proc-macro2/lib.rs create mode 100644 rust/proc-macro2/location.rs create mode 100644 rust/proc-macro2/marker.rs create mode 100644 rust/proc-macro2/parse.rs create mode 100644 rust/proc-macro2/probe.rs create mode 100644 rust/proc-macro2/probe/proc_macro_span.rs create mode 100644 rust/proc-macro2/probe/proc_macro_span_file.rs create mode 100644 rust/proc-macro2/probe/proc_macro_span_location.rs create mode 100644 rust/proc-macro2/rcvec.rs create mode 100644 rust/proc-macro2/wrapper.rs diff --git a/rust/proc-macro2/detection.rs b/rust/proc-macro2/detection.rs new file mode 100644 index 000000000000..beba7b237395 --- /dev/null +++ b/rust/proc-macro2/detection.rs @@ -0,0 +1,75 @@ +use core::sync::atomic::{AtomicUsize, Ordering}; +use std::sync::Once; + +static WORKS: AtomicUsize =3D AtomicUsize::new(0); +static INIT: Once =3D Once::new(); + +pub(crate) fn inside_proc_macro() -> bool { + match WORKS.load(Ordering::Relaxed) { + 1 =3D> return false, + 2 =3D> return true, + _ =3D> {} + } + + INIT.call_once(initialize); + inside_proc_macro() +} + +pub(crate) fn force_fallback() { + WORKS.store(1, Ordering::Relaxed); +} + +pub(crate) fn unforce_fallback() { + initialize(); +} + +#[cfg(not(no_is_available))] +fn initialize() { + let available =3D proc_macro::is_available(); + WORKS.store(available as usize + 1, Ordering::Relaxed); +} + +// Swap in a null panic hook to avoid printing "thread panicked" to stderr, +// then use catch_unwind to determine whether the compiler's proc_macro is +// working. When proc-macro2 is used from outside of a procedural macro all +// of the proc_macro crate's APIs currently panic. +// +// The Once is to prevent the possibility of this ordering: +// +// thread 1 calls take_hook, gets the user's original hook +// thread 1 calls set_hook with the null hook +// thread 2 calls take_hook, thinks null hook is the original hook +// thread 2 calls set_hook with the null hook +// thread 1 calls set_hook with the actual original hook +// thread 2 calls set_hook with what it thinks is the original hook +// +// in which the user's hook has been lost. +// +// There is still a race condition where a panic in a different thread can +// happen during the interval that the user's original panic hook is +// unregistered such that their hook is incorrectly not called. This is +// sufficiently unlikely and less bad than printing panic messages to stde= rr +// on correct use of this crate. Maybe there is a libstd feature request +// here. For now, if a user needs to guarantee that this failure mode does +// not occur, they need to call e.g. `proc_macro2::Span::call_site()` from +// the main thread before launching any other threads. +#[cfg(no_is_available)] +fn initialize() { + use std::panic::{self, PanicInfo}; + + type PanicHook =3D dyn Fn(&PanicInfo) + Sync + Send + 'static; + + let null_hook: Box =3D Box::new(|_panic_info| { /* ignore *= / }); + let sanity_check =3D &*null_hook as *const PanicHook; + let original_hook =3D panic::take_hook(); + panic::set_hook(null_hook); + + let works =3D panic::catch_unwind(proc_macro::Span::call_site).is_ok(); + WORKS.store(works as usize + 1, Ordering::Relaxed); + + let hopefully_null_hook =3D panic::take_hook(); + panic::set_hook(original_hook); + if sanity_check !=3D &*hopefully_null_hook { + panic!("observed race condition in proc_macro2::inside_proc_macro"= ); + } +} diff --git a/rust/proc-macro2/extra.rs b/rust/proc-macro2/extra.rs new file mode 100644 index 000000000000..522a90e136be --- /dev/null +++ b/rust/proc-macro2/extra.rs @@ -0,0 +1,151 @@ +//! Items which do not have a correspondence to any API in the proc_macro = crate, +//! but are necessary to include in proc-macro2. + +use crate::fallback; +use crate::imp; +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 th= read +/// created prior to the invalidation will return incorrect values or cras= h. +/// +/// This function is useful for programs that process more than 232 +/// bytes of Rust source code on the same thread. Just like rustc, proc-ma= cro2 +/// uses 32-bit source locations, and these wrap around when the total sou= rce +/// code processed by the same thread exceeds 232 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 =3D BufReader::new(krate); +/// let tar =3D GzDecoder::new(reader); +/// let mut archive =3D Archive::new(tar); +/// for entry in archive.entries().unwrap() { +/// let mut entry =3D entry.unwrap(); +/// let path =3D entry.path().unwrap(); +/// if path.extension() !=3D Some(OsStr::new("rs")) { +/// continue; +/// } +/// let mut content =3D String::new(); +/// entry.read_to_string(&mut content).unwrap(); +/// match proc_macro2::TokenStream::from_str(&content) { +/// Ok(tokens) =3D> {/* ... */}, +/// Err(_) =3D> continue, +/// } +/// } +/// }); +/// } +/// }); +/// # +/// # fn every_version_of_every_crate() -> Vec { +/// # Vec::new() +/// # } +/// ``` +/// +/// # Panics +/// +/// This function is not applicable to and will panic if called from a +/// procedural macro. +#[cfg(span_locations)] +#[cfg_attr(docsrs, doc(cfg(feature =3D "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()` to= gether +/// in a more compact representation than holding those 2 spans individual= ly. +/// +/// [`Group`]: crate::Group +#[derive(Copy, Clone)] +pub struct DelimSpan { + inner: DelimSpanEnum, + _marker: ProcMacroAutoTraits, +} + +#[derive(Copy, Clone)] +enum DelimSpanEnum { + #[cfg(wrap_proc_macro)] + Compiler { + join: proc_macro::Span, + open: proc_macro::Span, + close: proc_macro::Span, + }, + Fallback(fallback::Span), +} + +impl DelimSpan { + pub(crate) fn new(group: &imp::Group) -> Self { + #[cfg(wrap_proc_macro)] + let inner =3D match group { + imp::Group::Compiler(group) =3D> DelimSpanEnum::Compiler { + join: group.span(), + open: group.span_open(), + close: group.span_close(), + }, + imp::Group::Fallback(group) =3D> DelimSpanEnum::Fallback(group= .span()), + }; + + #[cfg(not(wrap_proc_macro))] + let inner =3D DelimSpanEnum::Fallback(group.span()); + + DelimSpan { + inner, + _marker: MARKER, + } + } + + /// Returns a span covering the entire delimited group. + pub fn join(&self) -> Span { + match &self.inner { + #[cfg(wrap_proc_macro)] + DelimSpanEnum::Compiler { join, .. } =3D> Span::_new(imp::Span= ::Compiler(*join)), + DelimSpanEnum::Fallback(span) =3D> Span::_new_fallback(*span), + } + } + + /// Returns a span for the opening punctuation of the group only. + pub fn open(&self) -> Span { + match &self.inner { + #[cfg(wrap_proc_macro)] + DelimSpanEnum::Compiler { open, .. } =3D> Span::_new(imp::Span= ::Compiler(*open)), + DelimSpanEnum::Fallback(span) =3D> Span::_new_fallback(span.fi= rst_byte()), + } + } + + /// Returns a span for the closing punctuation of the group only. + pub fn close(&self) -> Span { + match &self.inner { + #[cfg(wrap_proc_macro)] + DelimSpanEnum::Compiler { close, .. } =3D> Span::_new(imp::Spa= n::Compiler(*close)), + DelimSpanEnum::Fallback(span) =3D> Span::_new_fallback(span.la= st_byte()), + } + } +} + +impl Debug for DelimSpan { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + Debug::fmt(&self.join(), f) + } +} diff --git a/rust/proc-macro2/fallback.rs b/rust/proc-macro2/fallback.rs new file mode 100644 index 000000000000..1560105cfd25 --- /dev/null +++ b/rust/proc-macro2/fallback.rs @@ -0,0 +1,1256 @@ +#[cfg(wrap_proc_macro)] +use crate::imp; +#[cfg(span_locations)] +use crate::location::LineColumn; +use crate::parse::{self, Cursor}; +use crate::rcvec::{RcVec, RcVecBuilder, RcVecIntoIter, RcVecMut}; +use crate::{Delimiter, Spacing, TokenTree}; +#[cfg(all(span_locations, not(fuzzing)))] +use alloc::collections::BTreeMap; +#[cfg(all(span_locations, not(fuzzing)))] +use core::cell::RefCell; +#[cfg(span_locations)] +use core::cmp; +#[cfg(all(span_locations, not(fuzzing)))] +use core::cmp::Ordering; +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; +#[cfg(feature =3D "proc-macro")] +use core::str::FromStr; +use std::ffi::CStr; +#[cfg(wrap_proc_macro)] +use std::panic; +#[cfg(span_locations)] +use std::path::PathBuf; + +/// Force use of proc-macro2's fallback implementation of the API for now,= even +/// if the compiler's implementation is available. +pub fn force() { + #[cfg(wrap_proc_macro)] + crate::detection::force_fallback(); +} + +/// Resume using the compiler's implementation of the proc macro API if it= is +/// available. +pub fn unforce() { + #[cfg(wrap_proc_macro)] + crate::detection::unforce_fallback(); +} + +#[derive(Clone)] +pub(crate) struct TokenStream { + inner: RcVec, +} + +#[derive(Debug)] +pub(crate) struct LexError { + pub(crate) span: Span, +} + +impl LexError { + pub(crate) fn span(&self) -> Span { + self.span + } + + pub(crate) fn call_site() -> Self { + LexError { + span: Span::call_site(), + } + } +} + +impl TokenStream { + pub(crate) fn new() -> Self { + TokenStream { + inner: RcVecBuilder::new().build(), + } + } + + pub(crate) fn from_str_checked(src: &str) -> Result { + // Create a dummy file & add it to the source map + let mut cursor =3D get_cursor(src); + + // Strip a byte order mark if present + const BYTE_ORDER_MARK: &str =3D "\u{feff}"; + if cursor.starts_with(BYTE_ORDER_MARK) { + cursor =3D cursor.advance(BYTE_ORDER_MARK.len()); + } + + parse::token_stream(cursor) + } + + #[cfg(feature =3D "proc-macro")] + pub(crate) fn from_str_unchecked(src: &str) -> Self { + Self::from_str_checked(src).unwrap() + } + + pub(crate) fn is_empty(&self) -> bool { + self.inner.len() =3D=3D 0 + } + + fn take_inner(self) -> RcVecBuilder { + let nodrop =3D ManuallyDrop::new(self); + unsafe { ptr::read(&nodrop.inner) }.make_owned() + } +} + +fn push_token_from_proc_macro(mut vec: RcVecMut, token: TokenTr= ee) { + // https://github.com/dtolnay/proc-macro2/issues/235 + match token { + TokenTree::Literal(crate::Literal { + #[cfg(wrap_proc_macro)] + inner: crate::imp::Literal::Fallback(literal), + #[cfg(not(wrap_proc_macro))] + inner: literal, + .. + }) if literal.repr.starts_with('-') =3D> { + push_negative_literal(vec, literal); + } + _ =3D> vec.push(token), + } + + #[cold] + fn push_negative_literal(mut vec: RcVecMut, mut literal: Li= teral) { + literal.repr.remove(0); + let mut punct =3D crate::Punct::new('-', Spacing::Alone); + punct.set_span(crate::Span::_new_fallback(literal.span)); + vec.push(TokenTree::Punct(punct)); + vec.push(TokenTree::Literal(crate::Literal::_new_fallback(literal)= )); + } +} + +// Nonrecursive to prevent stack overflow. +impl Drop for TokenStream { + fn drop(&mut self) { + let mut stack =3D Vec::new(); + let mut current =3D match self.inner.get_mut() { + Some(inner) =3D> inner.take().into_iter(), + None =3D> return, + }; + loop { + while let Some(token) =3D current.next() { + let group =3D match token { + TokenTree::Group(group) =3D> group.inner, + _ =3D> continue, + }; + #[cfg(wrap_proc_macro)] + let group =3D match group { + crate::imp::Group::Fallback(group) =3D> group, + crate::imp::Group::Compiler(_) =3D> continue, + }; + let mut group =3D group; + if let Some(inner) =3D group.stream.inner.get_mut() { + stack.push(current); + current =3D inner.take().into_iter(); + } + } + match stack.pop() { + Some(next) =3D> current =3D next, + None =3D> return, + } + } + } +} + +pub(crate) struct TokenStreamBuilder { + inner: RcVecBuilder, +} + +impl TokenStreamBuilder { + pub(crate) fn new() -> Self { + TokenStreamBuilder { + inner: RcVecBuilder::new(), + } + } + + pub(crate) fn with_capacity(cap: usize) -> Self { + TokenStreamBuilder { + inner: RcVecBuilder::with_capacity(cap), + } + } + + pub(crate) fn push_token_from_parser(&mut self, tt: TokenTree) { + self.inner.push(tt); + } + + pub(crate) fn build(self) -> TokenStream { + TokenStream { + inner: self.inner.build(), + } + } +} + +#[cfg(span_locations)] +fn get_cursor(src: &str) -> Cursor { + #[cfg(fuzzing)] + return Cursor { rest: src, off: 1 }; + + // Create a dummy file & add it to the source map + #[cfg(not(fuzzing))] + SOURCE_MAP.with(|sm| { + let mut sm =3D sm.borrow_mut(); + let span =3D sm.add_file(src); + Cursor { + rest: src, + off: span.lo, + } + }) +} + +#[cfg(not(span_locations))] +fn get_cursor(src: &str) -> Cursor { + Cursor { rest: src } +} + +impl Display for LexError { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + f.write_str("cannot parse string into token stream") + } +} + +impl Display for TokenStream { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + let mut joint =3D false; + for (i, tt) in self.inner.iter().enumerate() { + if i !=3D 0 && !joint { + write!(f, " ")?; + } + joint =3D false; + match tt { + TokenTree::Group(tt) =3D> Display::fmt(tt, f), + TokenTree::Ident(tt) =3D> Display::fmt(tt, f), + TokenTree::Punct(tt) =3D> { + joint =3D tt.spacing() =3D=3D Spacing::Joint; + Display::fmt(tt, f) + } + TokenTree::Literal(tt) =3D> Display::fmt(tt, f), + }?; + } + + Ok(()) + } +} + +impl Debug for TokenStream { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + f.write_str("TokenStream ")?; + f.debug_list().entries(self.clone()).finish() + } +} + +#[cfg(feature =3D "proc-macro")] +impl From for TokenStream { + fn from(inner: proc_macro::TokenStream) -> Self { + TokenStream::from_str_unchecked(&inner.to_string()) + } +} + +#[cfg(feature =3D "proc-macro")] +impl From for proc_macro::TokenStream { + fn from(inner: TokenStream) -> Self { + proc_macro::TokenStream::from_str_unchecked(&inner.to_string()) + } +} + +impl From for TokenStream { + fn from(tree: TokenTree) -> Self { + let mut stream =3D RcVecBuilder::new(); + push_token_from_proc_macro(stream.as_mut(), tree); + TokenStream { + inner: stream.build(), + } + } +} + +impl FromIterator for TokenStream { + fn from_iter>(tokens: I) -> Self { + let mut stream =3D TokenStream::new(); + stream.extend(tokens); + stream + } +} + +impl FromIterator for TokenStream { + fn from_iter>(streams: I) -> Sel= f { + let mut v =3D RcVecBuilder::new(); + + for stream in streams { + v.extend(stream.take_inner()); + } + + TokenStream { inner: v.build() } + } +} + +impl Extend for TokenStream { + fn extend>(&mut self, tokens: I) { + let mut vec =3D self.inner.make_mut(); + tokens + .into_iter() + .for_each(|token| push_token_from_proc_macro(vec.as_mut(), tok= en)); + } +} + +impl Extend for TokenStream { + fn extend>(&mut self, streams: I= ) { + self.inner.make_mut().extend(streams.into_iter().flatten()); + } +} + +pub(crate) type TokenTreeIter =3D RcVecIntoIter; + +impl IntoIterator for TokenStream { + type Item =3D TokenTree; + type IntoIter =3D TokenTreeIter; + + fn into_iter(self) -> TokenTreeIter { + self.take_inner().into_iter() + } +} + +#[cfg(all(span_locations, not(fuzzing)))] +thread_local! { + static SOURCE_MAP: RefCell =3D RefCell::new(SourceMap { + // Start with a single dummy file which all call_site() and def_si= te() + // spans reference. + files: vec![FileInfo { + source_text: String::new(), + span: Span { lo: 0, hi: 0 }, + lines: vec![0], + char_index_to_byte_offset: BTreeMap::new(), + }], + }); +} + +#[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, + span: Span, + lines: Vec, + char_index_to_byte_offset: BTreeMap, +} + +#[cfg(all(span_locations, not(fuzzing)))] +impl FileInfo { + fn offset_line_column(&self, offset: usize) -> LineColumn { + assert!(self.span_within(Span { + lo: offset as u32, + hi: offset as u32, + })); + let offset =3D offset - self.span.lo as usize; + match self.lines.binary_search(&offset) { + Ok(found) =3D> LineColumn { + line: found + 1, + column: 0, + }, + Err(idx) =3D> LineColumn { + line: idx, + column: offset - self.lines[idx - 1], + }, + } + } + + fn span_within(&self, span: Span) -> bool { + span.lo >=3D self.span.lo && span.hi <=3D self.span.hi + } + + fn byte_range(&mut self, span: Span) -> Range { + let lo_char =3D (span.lo - self.span.lo) as usize; + + // Look up offset of the largest already-computed char index that = is + // less than or equal to the current requested one. We resume coun= ting + // chars from that point. + let (&last_char_index, &last_byte_offset) =3D self + .char_index_to_byte_offset + .range(..=3Dlo_char) + .next_back() + .unwrap_or((&0, &0)); + + let lo_byte =3D if last_char_index =3D=3D lo_char { + last_byte_offset + } else { + let total_byte_offset =3D match self.source_text[last_byte_off= set..] + .char_indices() + .nth(lo_char - last_char_index) + { + Some((additional_offset, _ch)) =3D> last_byte_offset + add= itional_offset, + None =3D> self.source_text.len(), + }; + self.char_index_to_byte_offset + .insert(lo_char, total_byte_offset); + total_byte_offset + }; + + let trunc_lo =3D &self.source_text[lo_byte..]; + let char_len =3D (span.hi - span.lo) as usize; + lo_byte..match trunc_lo.char_indices().nth(char_len) { + Some((offset, _ch)) =3D> lo_byte + offset, + None =3D> self.source_text.len(), + } + } + + fn source_text(&mut self, span: Span) -> String { + let byte_range =3D self.byte_range(span); + self.source_text[byte_range].to_owned() + } +} + +/// Computes the offsets of each line in the given source string +/// and the total number of characters +#[cfg(all(span_locations, not(fuzzing)))] +fn lines_offsets(s: &str) -> (usize, Vec) { + let mut lines =3D vec![0]; + let mut total =3D 0; + + for ch in s.chars() { + total +=3D 1; + if ch =3D=3D '\n' { + lines.push(total); + } + } + + (total, lines) +} + +#[cfg(all(span_locations, not(fuzzing)))] +struct SourceMap { + files: Vec, +} + +#[cfg(all(span_locations, not(fuzzing)))] +impl SourceMap { + fn next_start_pos(&self) -> u32 { + // Add 1 so there's always space between files. + // + // We'll always have at least 1 file, as we initialize our files l= ist + // with a dummy file. + self.files.last().unwrap().span.hi + 1 + } + + fn add_file(&mut self, src: &str) -> Span { + let (len, lines) =3D lines_offsets(src); + let lo =3D self.next_start_pos(); + let span =3D Span { + lo, + hi: lo + (len as u32), + }; + + self.files.push(FileInfo { + source_text: src.to_owned(), + span, + lines, + // Populated lazily by source_text(). + char_index_to_byte_offset: BTreeMap::new(), + }); + + span + } + + fn find(&self, span: Span) -> usize { + match self.files.binary_search_by(|file| { + if file.span.hi < span.lo { + Ordering::Less + } else if file.span.lo > span.hi { + Ordering::Greater + } else { + assert!(file.span_within(span)); + Ordering::Equal + } + }) { + Ok(i) =3D> i, + Err(_) =3D> unreachable!("Invalid span with no related FileInf= o!"), + } + } + + fn filepath(&self, span: Span) -> String { + let i =3D self.find(span); + if i =3D=3D 0 { + "".to_owned() + } else { + format!("", i) + } + } + + fn fileinfo(&self, span: Span) -> &FileInfo { + let i =3D self.find(span); + &self.files[i] + } + + fn fileinfo_mut(&mut self, span: Span) -> &mut FileInfo { + let i =3D self.find(span); + &mut self.files[i] + } +} + +#[derive(Clone, Copy, PartialEq, Eq)] +pub(crate) struct Span { + #[cfg(span_locations)] + pub(crate) lo: u32, + #[cfg(span_locations)] + pub(crate) hi: u32, +} + +impl Span { + #[cfg(not(span_locations))] + pub(crate) fn call_site() -> Self { + Span {} + } + + #[cfg(span_locations)] + pub(crate) fn call_site() -> Self { + Span { lo: 0, hi: 0 } + } + + pub(crate) fn mixed_site() -> Self { + Span::call_site() + } + + #[cfg(procmacro2_semver_exempt)] + pub(crate) fn def_site() -> Self { + Span::call_site() + } + + pub(crate) fn resolved_at(&self, _other: Span) -> Span { + // Stable spans consist only of line/column information, so + // `resolved_at` and `located_at` only select which span the + // caller wants line/column information from. + *self + } + + pub(crate) fn located_at(&self, other: Span) -> Span { + other + } + + #[cfg(span_locations)] + pub(crate) fn byte_range(&self) -> Range { + #[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).b= yte_range(*self)) + } + } + } + + #[cfg(span_locations)] + pub(crate) fn start(&self) -> LineColumn { + #[cfg(fuzzing)] + return LineColumn { line: 0, column: 0 }; + + #[cfg(not(fuzzing))] + SOURCE_MAP.with(|sm| { + let sm =3D sm.borrow(); + let fi =3D sm.fileinfo(*self); + fi.offset_line_column(self.lo as usize) + }) + } + + #[cfg(span_locations)] + pub(crate) fn end(&self) -> LineColumn { + #[cfg(fuzzing)] + return LineColumn { line: 0, column: 0 }; + + #[cfg(not(fuzzing))] + SOURCE_MAP.with(|sm| { + let sm =3D sm.borrow(); + let fi =3D sm.fileinfo(*self); + fi.offset_line_column(self.hi as usize) + }) + } + + #[cfg(span_locations)] + pub(crate) fn file(&self) -> String { + #[cfg(fuzzing)] + return "".to_owned(); + + #[cfg(not(fuzzing))] + SOURCE_MAP.with(|sm| { + let sm =3D sm.borrow(); + sm.filepath(*self) + }) + } + + #[cfg(span_locations)] + pub(crate) fn local_file(&self) -> Option { + None + } + + #[cfg(not(span_locations))] + pub(crate) fn join(&self, _other: Span) -> Option { + Some(Span {}) + } + + #[cfg(span_locations)] + pub(crate) fn join(&self, other: Span) -> Option { + #[cfg(fuzzing)] + return { + let _ =3D other; + None + }; + + #[cfg(not(fuzzing))] + SOURCE_MAP.with(|sm| { + let sm =3D sm.borrow(); + // If `other` is not within the same FileInfo as us, return No= ne. + if !sm.fileinfo(*self).span_within(other) { + return None; + } + Some(Span { + lo: cmp::min(self.lo, other.lo), + hi: cmp::max(self.hi, other.hi), + }) + }) + } + + #[cfg(not(span_locations))] + pub(crate) fn source_text(&self) -> Option { + None + } + + #[cfg(span_locations)] + pub(crate) fn source_text(&self) -> Option { + #[cfg(fuzzing)] + return None; + + #[cfg(not(fuzzing))] + { + if self.is_call_site() { + None + } else { + Some(SOURCE_MAP.with(|sm| sm.borrow_mut().fileinfo_mut(*se= lf).source_text(*self))) + } + } + } + + #[cfg(not(span_locations))] + pub(crate) fn first_byte(self) -> Self { + self + } + + #[cfg(span_locations)] + pub(crate) fn first_byte(self) -> Self { + Span { + lo: self.lo, + hi: cmp::min(self.lo.saturating_add(1), self.hi), + } + } + + #[cfg(not(span_locations))] + pub(crate) fn last_byte(self) -> Self { + self + } + + #[cfg(span_locations)] + pub(crate) fn last_byte(self) -> Self { + Span { + lo: cmp::max(self.hi.saturating_sub(1), self.lo), + hi: self.hi, + } + } + + #[cfg(span_locations)] + fn is_call_site(&self) -> bool { + self.lo =3D=3D 0 && self.hi =3D=3D 0 + } +} + +impl Debug for Span { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + #[cfg(span_locations)] + return write!(f, "bytes({}..{})", self.lo, self.hi); + + #[cfg(not(span_locations))] + write!(f, "Span") + } +} + +pub(crate) fn debug_span_field_if_nontrivial(debug: &mut fmt::DebugStruct,= span: Span) { + #[cfg(span_locations)] + { + if span.is_call_site() { + return; + } + } + + if cfg!(span_locations) { + debug.field("span", &span); + } +} + +#[derive(Clone)] +pub(crate) struct Group { + delimiter: Delimiter, + stream: TokenStream, + span: Span, +} + +impl Group { + pub(crate) fn new(delimiter: Delimiter, stream: TokenStream) -> Self { + Group { + delimiter, + stream, + span: Span::call_site(), + } + } + + pub(crate) fn delimiter(&self) -> Delimiter { + self.delimiter + } + + pub(crate) fn stream(&self) -> TokenStream { + self.stream.clone() + } + + pub(crate) fn span(&self) -> Span { + self.span + } + + pub(crate) fn span_open(&self) -> Span { + self.span.first_byte() + } + + pub(crate) fn span_close(&self) -> Span { + self.span.last_byte() + } + + pub(crate) fn set_span(&mut self, span: Span) { + self.span =3D span; + } +} + +impl Display for Group { + // We attempt to match libproc_macro's formatting. + // Empty parens: () + // Nonempty parens: (...) + // Empty brackets: [] + // Nonempty brackets: [...] + // Empty braces: { } + // Nonempty braces: { ... } + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + let (open, close) =3D match self.delimiter { + Delimiter::Parenthesis =3D> ("(", ")"), + Delimiter::Brace =3D> ("{ ", "}"), + Delimiter::Bracket =3D> ("[", "]"), + Delimiter::None =3D> ("", ""), + }; + + f.write_str(open)?; + Display::fmt(&self.stream, f)?; + if self.delimiter =3D=3D Delimiter::Brace && !self.stream.inner.is= _empty() { + f.write_str(" ")?; + } + f.write_str(close)?; + + Ok(()) + } +} + +impl Debug for Group { + fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { + let mut debug =3D fmt.debug_struct("Group"); + debug.field("delimiter", &self.delimiter); + debug.field("stream", &self.stream); + debug_span_field_if_nontrivial(&mut debug, self.span); + debug.finish() + } +} + +#[derive(Clone)] +pub(crate) struct Ident { + sym: Box, + span: Span, + raw: bool, +} + +impl Ident { + #[track_caller] + pub(crate) fn new_checked(string: &str, span: Span) -> Self { + validate_ident(string); + Ident::new_unchecked(string, span) + } + + pub(crate) fn new_unchecked(string: &str, span: Span) -> Self { + Ident { + sym: Box::from(string), + span, + raw: false, + } + } + + #[track_caller] + pub(crate) fn new_raw_checked(string: &str, span: Span) -> Self { + validate_ident_raw(string); + Ident::new_raw_unchecked(string, span) + } + + pub(crate) fn new_raw_unchecked(string: &str, span: Span) -> Self { + Ident { + sym: Box::from(string), + span, + raw: true, + } + } + + pub(crate) fn span(&self) -> Span { + self.span + } + + pub(crate) fn set_span(&mut self, span: Span) { + self.span =3D span; + } +} + +pub(crate) fn is_ident_start(c: char) -> bool { + c =3D=3D '_' || unicode_ident::is_xid_start(c) +} + +pub(crate) fn is_ident_continue(c: char) -> bool { + unicode_ident::is_xid_continue(c) +} + +#[track_caller] +fn validate_ident(string: &str) { + if string.is_empty() { + panic!("Ident is not allowed to be empty; use Option"); + } + + if string.bytes().all(|digit| b'0' <=3D digit && digit <=3D b'9') { + panic!("Ident cannot be a number; use Literal instead"); + } + + fn ident_ok(string: &str) -> bool { + let mut chars =3D string.chars(); + let first =3D chars.next().unwrap(); + if !is_ident_start(first) { + return false; + } + for ch in chars { + if !is_ident_continue(ch) { + return false; + } + } + true + } + + if !ident_ok(string) { + panic!("{:?} is not a valid Ident", string); + } +} + +#[track_caller] +fn validate_ident_raw(string: &str) { + validate_ident(string); + + match string { + "_" | "super" | "self" | "Self" | "crate" =3D> { + panic!("`r#{}` cannot be a raw identifier", string); + } + _ =3D> {} + } +} + +impl PartialEq for Ident { + fn eq(&self, other: &Ident) -> bool { + self.sym =3D=3D other.sym && self.raw =3D=3D other.raw + } +} + +impl PartialEq for Ident +where + T: ?Sized + AsRef, +{ + fn eq(&self, other: &T) -> bool { + let other =3D other.as_ref(); + if self.raw { + other.starts_with("r#") && *self.sym =3D=3D other[2..] + } else { + *self.sym =3D=3D *other + } + } +} + +impl Display for Ident { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + if self.raw { + f.write_str("r#")?; + } + Display::fmt(&self.sym, f) + } +} + +#[allow(clippy::missing_fields_in_debug)] +impl Debug for Ident { + // Ident(proc_macro), Ident(r#union) + #[cfg(not(span_locations))] + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + let mut debug =3D f.debug_tuple("Ident"); + debug.field(&format_args!("{}", self)); + debug.finish() + } + + // Ident { + // sym: proc_macro, + // span: bytes(128..138) + // } + #[cfg(span_locations)] + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + let mut debug =3D f.debug_struct("Ident"); + debug.field("sym", &format_args!("{}", self)); + debug_span_field_if_nontrivial(&mut debug, self.span); + debug.finish() + } +} + +#[derive(Clone)] +pub(crate) struct Literal { + pub(crate) repr: String, + span: Span, +} + +macro_rules! suffixed_numbers { + ($($name:ident =3D> $kind:ident,)*) =3D> ($( + pub(crate) fn $name(n: $kind) -> Literal { + Literal::_new(format!(concat!("{}", stringify!($kind)), n)) + } + )*) +} + +macro_rules! unsuffixed_numbers { + ($($name:ident =3D> $kind:ident,)*) =3D> ($( + pub(crate) fn $name(n: $kind) -> Literal { + Literal::_new(n.to_string()) + } + )*) +} + +impl Literal { + pub(crate) fn _new(repr: String) -> Self { + Literal { + repr, + span: Span::call_site(), + } + } + + pub(crate) fn from_str_checked(repr: &str) -> Result { + let mut cursor =3D get_cursor(repr); + #[cfg(span_locations)] + let lo =3D cursor.off; + + let negative =3D cursor.starts_with_char('-'); + if negative { + cursor =3D cursor.advance(1); + if !cursor.starts_with_fn(|ch| ch.is_ascii_digit()) { + return Err(LexError::call_site()); + } + } + + if let Ok((rest, mut literal)) =3D parse::literal(cursor) { + if rest.is_empty() { + if negative { + literal.repr.insert(0, '-'); + } + literal.span =3D Span { + #[cfg(span_locations)] + lo, + #[cfg(span_locations)] + hi: rest.off, + }; + return Ok(literal); + } + } + Err(LexError::call_site()) + } + + pub(crate) unsafe fn from_str_unchecked(repr: &str) -> Self { + Literal::_new(repr.to_owned()) + } + + suffixed_numbers! { + u8_suffixed =3D> u8, + u16_suffixed =3D> u16, + u32_suffixed =3D> u32, + u64_suffixed =3D> u64, + u128_suffixed =3D> u128, + usize_suffixed =3D> usize, + i8_suffixed =3D> i8, + i16_suffixed =3D> i16, + i32_suffixed =3D> i32, + i64_suffixed =3D> i64, + i128_suffixed =3D> i128, + isize_suffixed =3D> isize, + + f32_suffixed =3D> f32, + f64_suffixed =3D> f64, + } + + unsuffixed_numbers! { + u8_unsuffixed =3D> u8, + u16_unsuffixed =3D> u16, + u32_unsuffixed =3D> u32, + u64_unsuffixed =3D> u64, + u128_unsuffixed =3D> u128, + usize_unsuffixed =3D> usize, + i8_unsuffixed =3D> i8, + i16_unsuffixed =3D> i16, + i32_unsuffixed =3D> i32, + i64_unsuffixed =3D> i64, + i128_unsuffixed =3D> i128, + isize_unsuffixed =3D> isize, + } + + pub(crate) fn f32_unsuffixed(f: f32) -> Literal { + let mut s =3D f.to_string(); + if !s.contains('.') { + s.push_str(".0"); + } + Literal::_new(s) + } + + pub(crate) fn f64_unsuffixed(f: f64) -> Literal { + let mut s =3D f.to_string(); + if !s.contains('.') { + s.push_str(".0"); + } + Literal::_new(s) + } + + pub(crate) fn string(string: &str) -> Literal { + let mut repr =3D String::with_capacity(string.len() + 2); + repr.push('"'); + escape_utf8(string, &mut repr); + repr.push('"'); + Literal::_new(repr) + } + + pub(crate) fn character(ch: char) -> Literal { + let mut repr =3D String::new(); + repr.push('\''); + if ch =3D=3D '"' { + // escape_debug turns this into '\"' which is unnecessary. + repr.push(ch); + } else { + repr.extend(ch.escape_debug()); + } + repr.push('\''); + Literal::_new(repr) + } + + pub(crate) fn byte_character(byte: u8) -> Literal { + let mut repr =3D "b'".to_string(); + #[allow(clippy::match_overlapping_arm)] + match byte { + b'\0' =3D> repr.push_str(r"\0"), + b'\t' =3D> repr.push_str(r"\t"), + b'\n' =3D> repr.push_str(r"\n"), + b'\r' =3D> repr.push_str(r"\r"), + b'\'' =3D> repr.push_str(r"\'"), + b'\\' =3D> repr.push_str(r"\\"), + b'\x20'..=3Db'\x7E' =3D> repr.push(byte as char), + _ =3D> { + let _ =3D write!(repr, r"\x{:02X}", byte); + } + } + repr.push('\''); + Literal::_new(repr) + } + + pub(crate) fn byte_string(bytes: &[u8]) -> Literal { + let mut repr =3D "b\"".to_string(); + let mut bytes =3D bytes.iter(); + while let Some(&b) =3D bytes.next() { + #[allow(clippy::match_overlapping_arm)] + match b { + b'\0' =3D> repr.push_str(match bytes.as_slice().first() { + // circumvent clippy::octal_escapes lint + Some(b'0'..=3Db'7') =3D> r"\x00", + _ =3D> r"\0", + }), + b'\t' =3D> repr.push_str(r"\t"), + b'\n' =3D> repr.push_str(r"\n"), + b'\r' =3D> repr.push_str(r"\r"), + b'"' =3D> repr.push_str("\\\""), + b'\\' =3D> repr.push_str(r"\\"), + b'\x20'..=3Db'\x7E' =3D> repr.push(b as char), + _ =3D> { + let _ =3D write!(repr, r"\x{:02X}", b); + } + } + } + repr.push('"'); + Literal::_new(repr) + } + + pub(crate) fn c_string(string: &CStr) -> Literal { + let mut repr =3D "c\"".to_string(); + let mut bytes =3D string.to_bytes(); + while !bytes.is_empty() { + let (valid, invalid) =3D match str::from_utf8(bytes) { + Ok(all_valid) =3D> { + bytes =3D b""; + (all_valid, bytes) + } + Err(utf8_error) =3D> { + let (valid, rest) =3D bytes.split_at(utf8_error.valid_= up_to()); + let valid =3D str::from_utf8(valid).unwrap(); + let invalid =3D utf8_error + .error_len() + .map_or(rest, |error_len| &rest[..error_len]); + bytes =3D &bytes[valid.len() + invalid.len()..]; + (valid, invalid) + } + }; + escape_utf8(valid, &mut repr); + for &byte in invalid { + let _ =3D write!(repr, r"\x{:02X}", byte); + } + } + repr.push('"'); + Literal::_new(repr) + } + + pub(crate) fn span(&self) -> Span { + self.span + } + + pub(crate) fn set_span(&mut self, span: Span) { + self.span =3D span; + } + + pub(crate) fn subspan>(&self, range: R) -> Optio= n { + #[cfg(not(span_locations))] + { + let _ =3D range; + None + } + + #[cfg(span_locations)] + { + use core::ops::Bound; + + let lo =3D match range.start_bound() { + Bound::Included(start) =3D> { + let start =3D u32::try_from(*start).ok()?; + self.span.lo.checked_add(start)? + } + Bound::Excluded(start) =3D> { + let start =3D u32::try_from(*start).ok()?; + self.span.lo.checked_add(start)?.checked_add(1)? + } + Bound::Unbounded =3D> self.span.lo, + }; + let hi =3D match range.end_bound() { + Bound::Included(end) =3D> { + let end =3D u32::try_from(*end).ok()?; + self.span.lo.checked_add(end)?.checked_add(1)? + } + Bound::Excluded(end) =3D> { + let end =3D u32::try_from(*end).ok()?; + self.span.lo.checked_add(end)? + } + Bound::Unbounded =3D> self.span.hi, + }; + if lo <=3D hi && hi <=3D self.span.hi { + Some(Span { lo, hi }) + } else { + None + } + } + } +} + +impl Display for Literal { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + Display::fmt(&self.repr, f) + } +} + +impl Debug for Literal { + fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { + let mut debug =3D fmt.debug_struct("Literal"); + debug.field("lit", &format_args!("{}", self.repr)); + debug_span_field_if_nontrivial(&mut debug, self.span); + debug.finish() + } +} + +fn escape_utf8(string: &str, repr: &mut String) { + let mut chars =3D string.chars(); + while let Some(ch) =3D chars.next() { + if ch =3D=3D '\0' { + repr.push_str( + if chars + .as_str() + .starts_with(|next| '0' <=3D next && next <=3D '7') + { + // circumvent clippy::octal_escapes lint + r"\x00" + } else { + r"\0" + }, + ); + } else if ch =3D=3D '\'' { + // escape_debug turns this into "\'" which is unnecessary. + repr.push(ch); + } else { + repr.extend(ch.escape_debug()); + } + } +} + +#[cfg(feature =3D "proc-macro")] +pub(crate) trait FromStr2: FromStr { + #[cfg(wrap_proc_macro)] + fn valid(src: &str) -> bool; + + #[cfg(wrap_proc_macro)] + fn from_str_checked(src: &str) -> Result { + // Validate using fallback parser, because rustc is incapable of + // returning a recoverable Err for certain invalid token streams, = and + // will instead permanently poison the compilation. + if !Self::valid(src) { + return Err(imp::LexError::CompilerPanic); + } + + // Catch panic to work around https://github.com/rust-lang/rust/is= sues/58736. + match panic::catch_unwind(|| Self::from_str(src)) { + Ok(Ok(ok)) =3D> Ok(ok), + Ok(Err(lex)) =3D> Err(imp::LexError::Compiler(lex)), + Err(_panic) =3D> Err(imp::LexError::CompilerPanic), + } + } + + fn from_str_unchecked(src: &str) -> Self { + Self::from_str(src).unwrap() + } +} + +#[cfg(feature =3D "proc-macro")] +impl FromStr2 for proc_macro::TokenStream { + #[cfg(wrap_proc_macro)] + fn valid(src: &str) -> bool { + TokenStream::from_str_checked(src).is_ok() + } +} + +#[cfg(feature =3D "proc-macro")] +impl FromStr2 for proc_macro::Literal { + #[cfg(wrap_proc_macro)] + fn valid(src: &str) -> bool { + Literal::from_str_checked(src).is_ok() + } +} diff --git a/rust/proc-macro2/lib.rs b/rust/proc-macro2/lib.rs new file mode 100644 index 000000000000..2984af335adc --- /dev/null +++ b/rust/proc-macro2/lib.rs @@ -0,0 +1,1349 @@ +//! [![github]](https://github.com/dtolnay/proc-macro2) [![crates-io]= ](https://crates.io/crates/proc-macro2) [![docs-rs]](crate) +//! +//! [github]: https://img.shields.io/badge/github-8da0cb?style=3Dfor-the-b= adge&labelColor=3D555555&logo=3Dgithub +//! [crates-io]: https://img.shields.io/badge/crates.io-fc8d62?style=3Dfor= -the-badge&labelColor=3D555555&logo=3Drust +//! [docs-rs]: https://img.shields.io/badge/docs.rs-66c2a5?style=3Dfor-the= -badge&labelColor=3D555555&logo=3Ddocs.rs +//! +//!
+//! +//! A wrapper around the procedural macro API of the compiler's [`proc_mac= ro`] +//! crate. This library serves two purposes: +//! +//! - **Bring proc-macro-like functionality to other contexts like build.r= s and +//! main.rs.** Types from `proc_macro` are entirely specific to procedur= al +//! macros and cannot ever exist in code outside of a procedural macro. +//! Meanwhile `proc_macro2` types may exist anywhere including non-macro= code. +//! By developing foundational libraries like [syn] and [quote] against +//! `proc_macro2` rather than `proc_macro`, the procedural macro ecosyst= em +//! becomes easily applicable to many other use cases and we avoid +//! reimplementing non-macro equivalents of those libraries. +//! +//! - **Make procedural macros unit testable.** As a consequence of being +//! specific to procedural macros, nothing that uses `proc_macro` can be +//! executed from a unit test. In order for helper libraries or componen= ts of +//! a macro to be testable in isolation, they must be implemented using +//! `proc_macro2`. +//! +//! [syn]: https://github.com/dtolnay/syn +//! [quote]: https://github.com/dtolnay/quote +//! +//! # Usage +//! +//! The skeleton of a typical procedural macro typically looks like this: +//! +//! ``` +//! extern crate proc_macro; +//! +//! # const IGNORE: &str =3D stringify! { +//! #[proc_macro_derive(MyDerive)] +//! # }; +//! # #[cfg(wrap_proc_macro)] +//! pub fn my_derive(input: proc_macro::TokenStream) -> proc_macro::TokenS= tream { +//! let input =3D proc_macro2::TokenStream::from(input); +//! +//! let output: proc_macro2::TokenStream =3D { +//! /* transform input */ +//! # input +//! }; +//! +//! proc_macro::TokenStream::from(output) +//! } +//! ``` +//! +//! If parsing with [Syn], you'll use [`parse_macro_input!`] instead to +//! propagate parse errors correctly back to the compiler when parsing fai= ls. +//! +//! [`parse_macro_input!`]: https://docs.rs/syn/2.0/syn/macro.parse_macro_= input.html +//! +//! # Unstable features +//! +//! The default feature set of proc-macro2 tracks the most recent stable +//! compiler API. Functionality in `proc_macro` that is not yet stable is = not +//! exposed by proc-macro2 by default. +//! +//! To opt into the additional APIs available in the most recent nightly +//! compiler, the `procmacro2_semver_exempt` config flag must be passed to +//! rustc. We will polyfill those nightly-only APIs back to Rust 1.56.0. As +//! these are unstable APIs that track the nightly compiler, minor version= s of +//! proc-macro2 may make breaking changes to them at any time. +//! +//! ```sh +//! RUSTFLAGS=3D'--cfg procmacro2_semver_exempt' cargo build +//! ``` +//! +//! Note that this must not only be done for your crate, but for any crate= that +//! depends on your crate. This infectious nature is intentional, as it se= rves +//! as a reminder that you are outside of the normal semver guarantees. +//! +//! Semver exempt methods are marked as such in the proc-macro2 documentat= ion. +//! +//! # Thread-Safety +//! +//! Most types in this crate are `!Sync` because the underlying compiler +//! types make use of thread-local memory, meaning they cannot be accessed= from +//! a different thread. + +// Proc-macro2 types in rustdoc of other crates get linked to here. +#![doc(html_root_url =3D "https://docs.rs/proc-macro2/1.0.101")] +#![cfg_attr(any(proc_macro_span, super_unstable), feature(proc_macro_span)= )] +#![cfg_attr(super_unstable, feature(proc_macro_def_site))] +#![cfg_attr(docsrs, feature(doc_cfg))] +#![deny(unsafe_op_in_unsafe_fn)] +#![allow( + clippy::cast_lossless, + clippy::cast_possible_truncation, + clippy::checked_conversions, + clippy::doc_markdown, + clippy::elidable_lifetime_names, + clippy::incompatible_msrv, + clippy::items_after_statements, + clippy::iter_without_into_iter, + clippy::let_underscore_untyped, + clippy::manual_assert, + clippy::manual_range_contains, + clippy::missing_panics_doc, + clippy::missing_safety_doc, + clippy::must_use_candidate, + clippy::needless_doctest_main, + clippy::needless_lifetimes, + clippy::new_without_default, + clippy::return_self_not_must_use, + clippy::shadow_unrelated, + clippy::trivially_copy_pass_by_ref, + clippy::unnecessary_wraps, + clippy::unused_self, + clippy::used_underscore_binding, + clippy::vec_init_then_push +)] +#![allow(unknown_lints, mismatched_lifetime_syntaxes)] + +#[cfg(all(procmacro2_semver_exempt, wrap_proc_macro, not(super_unstable)))] +compile_error! {"\ + Something is not right. If you've tried to turn on \ + procmacro2_semver_exempt, you need to ensure that it \ + is turned on for the compilation of the proc-macro2 \ + build script as well. +"} + +#[cfg(all( + procmacro2_nightly_testing, + feature =3D "proc-macro", + not(proc_macro_span) +))] +compile_error! {"\ + Build script probe failed to compile. +"} + +extern crate alloc; + +#[cfg(feature =3D "proc-macro")] +extern crate proc_macro; + +mod marker; +mod parse; +mod probe; +mod rcvec; + +#[cfg(wrap_proc_macro)] +mod detection; + +// Public for proc_macro2::fallback::force() and unforce(), but those are = quite +// a niche use case so we omit it from rustdoc. +#[doc(hidden)] +pub mod fallback; + +pub mod extra; + +#[cfg(not(wrap_proc_macro))] +use crate::fallback as imp; +#[path =3D "wrapper.rs"] +#[cfg(wrap_proc_macro)] +mod imp; + +#[cfg(span_locations)] +mod location; + +use crate::extra::DelimSpan; +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(span_locations)] +use std::path::PathBuf; + +#[cfg(span_locations)] +#[cfg_attr(docsrs, doc(cfg(feature =3D "span-locations")))] +pub use crate::location::LineColumn; + +/// An abstract stream of tokens, or more concretely a sequence of token t= rees. +/// +/// This type provides interfaces for iterating over token trees and for +/// collecting token trees into one stream. +/// +/// Token stream is both the input and output of `#[proc_macro]`, +/// `#[proc_macro_attribute]` and `#[proc_macro_derive]` definitions. +#[derive(Clone)] +pub struct TokenStream { + inner: imp::TokenStream, + _marker: ProcMacroAutoTraits, +} + +/// Error returned from `TokenStream::from_str`. +pub struct LexError { + inner: imp::LexError, + _marker: ProcMacroAutoTraits, +} + +impl TokenStream { + fn _new(inner: imp::TokenStream) -> Self { + TokenStream { + inner, + _marker: MARKER, + } + } + + fn _new_fallback(inner: fallback::TokenStream) -> Self { + TokenStream { + inner: imp::TokenStream::from(inner), + _marker: MARKER, + } + } + + /// Returns an empty `TokenStream` containing no token trees. + pub fn new() -> Self { + TokenStream::_new(imp::TokenStream::new()) + } + + /// Checks if this `TokenStream` is empty. + pub fn is_empty(&self) -> bool { + self.inner.is_empty() + } +} + +/// `TokenStream::default()` returns an empty stream, +/// i.e. this is equivalent with `TokenStream::new()`. +impl Default for TokenStream { + fn default() -> Self { + TokenStream::new() + } +} + +/// Attempts to break the string into tokens and parse those tokens into a= token +/// stream. +/// +/// May fail for a number of reasons, for example, if the string contains +/// unbalanced delimiters or characters not existing in the language. +/// +/// NOTE: Some errors may cause panics instead of returning `LexError`. We +/// reserve the right to change these errors into `LexError`s later. +impl FromStr for TokenStream { + type Err =3D LexError; + + fn from_str(src: &str) -> Result { + match imp::TokenStream::from_str_checked(src) { + Ok(tokens) =3D> Ok(TokenStream::_new(tokens)), + Err(lex) =3D> Err(LexError { + inner: lex, + _marker: MARKER, + }), + } + } +} + +#[cfg(feature =3D "proc-macro")] +#[cfg_attr(docsrs, doc(cfg(feature =3D "proc-macro")))] +impl From for TokenStream { + fn from(inner: proc_macro::TokenStream) -> Self { + TokenStream::_new(imp::TokenStream::from(inner)) + } +} + +#[cfg(feature =3D "proc-macro")] +#[cfg_attr(docsrs, doc(cfg(feature =3D "proc-macro")))] +impl From for proc_macro::TokenStream { + fn from(inner: TokenStream) -> Self { + proc_macro::TokenStream::from(inner.inner) + } +} + +impl From for TokenStream { + fn from(token: TokenTree) -> Self { + TokenStream::_new(imp::TokenStream::from(token)) + } +} + +impl Extend for TokenStream { + fn extend>(&mut self, streams: I) { + self.inner.extend(streams); + } +} + +impl Extend for TokenStream { + fn extend>(&mut self, streams: I= ) { + self.inner + .extend(streams.into_iter().map(|stream| stream.inner)); + } +} + +/// Collects a number of token trees into a single stream. +impl FromIterator for TokenStream { + fn from_iter>(streams: I) -> Self { + TokenStream::_new(streams.into_iter().collect()) + } +} +impl FromIterator for TokenStream { + fn from_iter>(streams: I) -> Sel= f { + TokenStream::_new(streams.into_iter().map(|i| i.inner).collect()) + } +} + +/// Prints the token stream as a string that is supposed to be losslessly +/// convertible back into the same token stream (modulo spans), except for +/// possibly `TokenTree::Group`s with `Delimiter::None` delimiters and neg= ative +/// numeric literals. +impl Display for TokenStream { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + Display::fmt(&self.inner, f) + } +} + +/// Prints token in a form convenient for debugging. +impl Debug for TokenStream { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + Debug::fmt(&self.inner, f) + } +} + +impl LexError { + pub fn span(&self) -> Span { + Span::_new(self.inner.span()) + } +} + +impl Debug for LexError { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + Debug::fmt(&self.inner, f) + } +} + +impl Display for LexError { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + Display::fmt(&self.inner, f) + } +} + +impl Error for LexError {} + +/// A region of source code, along with macro expansion information. +#[derive(Copy, Clone)] +pub struct Span { + inner: imp::Span, + _marker: ProcMacroAutoTraits, +} + +impl Span { + fn _new(inner: imp::Span) -> Self { + Span { + inner, + _marker: MARKER, + } + } + + fn _new_fallback(inner: fallback::Span) -> Self { + Span { + inner: imp::Span::from(inner), + _marker: MARKER, + } + } + + /// The span of the invocation of the current procedural macro. + /// + /// Identifiers created with this span will be resolved as if they were + /// written directly at the macro call location (call-site hygiene) and + /// other code at the macro call site will be able to refer to them as= well. + pub fn call_site() -> Self { + Span::_new(imp::Span::call_site()) + } + + /// The span located at the invocation of the procedural macro, but wi= th + /// local variables, labels, and `$crate` resolved at the definition s= ite + /// of the macro. This is the same hygiene behavior as `macro_rules`. + pub fn mixed_site() -> Self { + Span::_new(imp::Span::mixed_site()) + } + + /// A span that resolves at the macro definition site. + /// + /// This method is semver exempt and not exposed by default. + #[cfg(procmacro2_semver_exempt)] + #[cfg_attr(docsrs, doc(cfg(procmacro2_semver_exempt)))] + pub fn def_site() -> Self { + Span::_new(imp::Span::def_site()) + } + + /// Creates a new span with the same line/column information as `self`= but + /// that resolves symbols as though it were at `other`. + pub fn resolved_at(&self, other: Span) -> Span { + Span::_new(self.inner.resolved_at(other.inner)) + } + + /// Creates a new span with the same name resolution behavior as `self= ` but + /// with the line/column information of `other`. + pub fn located_at(&self, other: Span) -> Span { + Span::_new(self.inner.located_at(other.inner)) + } + + /// Convert `proc_macro2::Span` to `proc_macro::Span`. + /// + /// This method is available when building with a nightly compiler, or= when + /// building with rustc 1.29+ *without* semver exempt features. + /// + /// # Panics + /// + /// Panics if called from outside of a procedural macro. Unlike + /// `proc_macro2::Span`, the `proc_macro::Span` type can only exist wi= thin + /// the context of a procedural macro invocation. + #[cfg(wrap_proc_macro)] + pub fn unwrap(self) -> proc_macro::Span { + self.inner.unwrap() + } + + // Soft deprecated. Please use Span::unwrap. + #[cfg(wrap_proc_macro)] + #[doc(hidden)] + pub fn unstable(self) -> proc_macro::Span { + self.unwrap() + } + + /// 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 i= s only + /// accurate if compiled with a nightly toolchain. The stable toolchai= n does + /// not have this information available. When executing outside of a + /// procedural macro, such as main.rs or build.rs, the byte range is a= lways + /// accurate regardless of toolchain. + #[cfg(span_locations)] + #[cfg_attr(docsrs, doc(cfg(feature =3D "span-locations")))] + pub fn byte_range(&self) -> Range { + 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. + /// + /// When executing in a procedural macro context, the returned line/co= lumn + /// are only meaningful if compiled with a nightly toolchain. The stab= le + /// toolchain does not have this information available. When executing + /// outside of a procedural macro, such as main.rs or build.rs, the + /// line/column are always meaningful regardless of toolchain. + #[cfg(span_locations)] + #[cfg_attr(docsrs, doc(cfg(feature =3D "span-locations")))] + pub fn start(&self) -> LineColumn { + self.inner.start() + } + + /// Get the ending line/column in the source file for this span. + /// + /// This method requires the `"span-locations"` feature to be enabled. + /// + /// When executing in a procedural macro context, the returned line/co= lumn + /// are only meaningful if compiled with a nightly toolchain. The stab= le + /// toolchain does not have this information available. When executing + /// outside of a procedural macro, such as main.rs or build.rs, the + /// line/column are always meaningful regardless of toolchain. + #[cfg(span_locations)] + #[cfg_attr(docsrs, doc(cfg(feature =3D "span-locations")))] + pub fn end(&self) -> LineColumn { + self.inner.end() + } + + /// The path to the source file in which this span occurs, for display + /// purposes. + /// + /// This might not correspond to a valid file system path. It might be + /// remapped, or might be an artificial path such as `""`. + #[cfg(span_locations)] + #[cfg_attr(docsrs, doc(cfg(feature =3D "span-locations")))] + pub fn file(&self) -> String { + self.inner.file() + } + + /// The path to the source file in which this span occurs on disk. + /// + /// This is the actual path on disk. It is unaffected by path remappin= g. + /// + /// This path should not be embedded in the output of the macro; prefer + /// `file()` instead. + #[cfg(span_locations)] + #[cfg_attr(docsrs, doc(cfg(feature =3D "span-locations")))] + pub fn local_file(&self) -> Option { + self.inner.local_file() + } + + /// Create a new span encompassing `self` and `other`. + /// + /// Returns `None` if `self` and `other` are from different files. + /// + /// Warning: the underlying [`proc_macro::Span::join`] method is + /// nightly-only. When called from within a procedural macro not using= a + /// nightly compiler, this method will always return `None`. + pub fn join(&self, other: Span) -> Option { + self.inner.join(other.inner).map(Span::_new) + } + + /// Compares two spans to see if they're equal. + /// + /// This method is semver exempt and not exposed by default. + #[cfg(procmacro2_semver_exempt)] + #[cfg_attr(docsrs, doc(cfg(procmacro2_semver_exempt)))] + pub fn eq(&self, other: &Span) -> bool { + self.inner.eq(&other.inner) + } + + /// Returns the source text behind a span. This preserves the original + /// source code, including spaces and comments. It only returns a resu= lt if + /// the span corresponds to real source code. + /// + /// Note: The observable result of a macro should only rely on the tok= ens + /// and not on this source text. The result of this function is a best + /// effort to be used for diagnostics only. + pub fn source_text(&self) -> Option { + self.inner.source_text() + } +} + +/// Prints a span in a form convenient for debugging. +impl Debug for Span { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + Debug::fmt(&self.inner, f) + } +} + +/// A single token or a delimited sequence of token trees (e.g. `[1, (), .= .]`). +#[derive(Clone)] +pub enum TokenTree { + /// A token stream surrounded by bracket delimiters. + Group(Group), + /// An identifier. + Ident(Ident), + /// A single punctuation character (`+`, `,`, `$`, etc.). + Punct(Punct), + /// A literal character (`'a'`), string (`"hello"`), number (`2.3`), e= tc. + Literal(Literal), +} + +impl TokenTree { + /// Returns the span of this tree, delegating to the `span` method of + /// the contained token or a delimited stream. + pub fn span(&self) -> Span { + match self { + TokenTree::Group(t) =3D> t.span(), + TokenTree::Ident(t) =3D> t.span(), + TokenTree::Punct(t) =3D> t.span(), + TokenTree::Literal(t) =3D> t.span(), + } + } + + /// Configures the span for *only this token*. + /// + /// Note that if this token is a `Group` then this method will not con= figure + /// the span of each of the internal tokens, this will simply delegate= to + /// the `set_span` method of each variant. + pub fn set_span(&mut self, span: Span) { + match self { + TokenTree::Group(t) =3D> t.set_span(span), + TokenTree::Ident(t) =3D> t.set_span(span), + TokenTree::Punct(t) =3D> t.set_span(span), + TokenTree::Literal(t) =3D> t.set_span(span), + } + } +} + +impl From for TokenTree { + fn from(g: Group) -> Self { + TokenTree::Group(g) + } +} + +impl From for TokenTree { + fn from(g: Ident) -> Self { + TokenTree::Ident(g) + } +} + +impl From for TokenTree { + fn from(g: Punct) -> Self { + TokenTree::Punct(g) + } +} + +impl From for TokenTree { + fn from(g: Literal) -> Self { + TokenTree::Literal(g) + } +} + +/// Prints the token tree as a string that is supposed to be losslessly +/// convertible back into the same token tree (modulo spans), except for +/// possibly `TokenTree::Group`s with `Delimiter::None` delimiters and neg= ative +/// numeric literals. +impl Display for TokenTree { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + match self { + TokenTree::Group(t) =3D> Display::fmt(t, f), + TokenTree::Ident(t) =3D> Display::fmt(t, f), + TokenTree::Punct(t) =3D> Display::fmt(t, f), + TokenTree::Literal(t) =3D> Display::fmt(t, f), + } + } +} + +/// Prints token tree in a form convenient for debugging. +impl Debug for TokenTree { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + // Each of these has the name in the struct type in the derived de= bug, + // so don't bother with an extra layer of indirection + match self { + TokenTree::Group(t) =3D> Debug::fmt(t, f), + TokenTree::Ident(t) =3D> { + let mut debug =3D f.debug_struct("Ident"); + debug.field("sym", &format_args!("{}", t)); + imp::debug_span_field_if_nontrivial(&mut debug, t.span().i= nner); + debug.finish() + } + TokenTree::Punct(t) =3D> Debug::fmt(t, f), + TokenTree::Literal(t) =3D> Debug::fmt(t, f), + } + } +} + +/// A delimited token stream. +/// +/// A `Group` internally contains a `TokenStream` which is surrounded by +/// `Delimiter`s. +#[derive(Clone)] +pub struct Group { + inner: imp::Group, +} + +/// Describes how a sequence of token trees is delimited. +#[derive(Copy, Clone, Debug, Eq, PartialEq)] +pub enum Delimiter { + /// `( ... )` + Parenthesis, + /// `{ ... }` + Brace, + /// `[ ... ]` + Bracket, + /// `=E2=88=85 ... =E2=88=85` + /// + /// 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`. + /// Invisible delimiters may not survive roundtrip of a token stream t= hrough + /// a string. + /// + ///
+ /// + /// Note: rustc currently can ignore the grouping of tokens delimited = by `None` in the output + /// of a proc_macro. Only `None`-delimited groups created by a macro_r= ules macro in the input + /// of a proc_macro macro are preserved, and only in very specific cir= cumstances. + /// Any `None`-delimited groups (re)created by a proc_macro will there= fore not preserve + /// operator priorities as indicated above. The other `Delimiter` vari= ants should be used + /// instead in this context. This is a rustc bug. For details, see + /// [rust-lang/rust#67062](https://github.com/rust-lang/rust/issues/67= 062). + /// + ///
+ None, +} + +impl Group { + fn _new(inner: imp::Group) -> Self { + Group { inner } + } + + fn _new_fallback(inner: fallback::Group) -> Self { + Group { + inner: imp::Group::from(inner), + } + } + + /// Creates a new `Group` with the given delimiter and token stream. + /// + /// This constructor will set the span for this group to + /// `Span::call_site()`. To change the span you can use the `set_span` + /// method below. + pub fn new(delimiter: Delimiter, stream: TokenStream) -> Self { + Group { + inner: imp::Group::new(delimiter, stream.inner), + } + } + + /// Returns the punctuation used as the delimiter for this group: a se= t of + /// parentheses, square brackets, or curly braces. + pub fn delimiter(&self) -> Delimiter { + self.inner.delimiter() + } + + /// Returns the `TokenStream` of tokens that are delimited in this `Gr= oup`. + /// + /// Note that the returned token stream does not include the delimiter + /// returned above. + pub fn stream(&self) -> TokenStream { + TokenStream::_new(self.inner.stream()) + } + + /// Returns the span for the delimiters of this token stream, spanning= the + /// entire `Group`. + /// + /// ```text + /// pub fn span(&self) -> Span { + /// ^^^^^^^ + /// ``` + pub fn span(&self) -> Span { + Span::_new(self.inner.span()) + } + + /// Returns the span pointing to the opening delimiter of this group. + /// + /// ```text + /// pub fn span_open(&self) -> Span { + /// ^ + /// ``` + pub fn span_open(&self) -> Span { + Span::_new(self.inner.span_open()) + } + + /// Returns the span pointing to the closing delimiter of this group. + /// + /// ```text + /// pub fn span_close(&self) -> Span { + /// ^ + /// ``` + pub fn span_close(&self) -> Span { + Span::_new(self.inner.span_close()) + } + + /// Returns an object that holds this group's `span_open()` and + /// `span_close()` together (in a more compact representation than hol= ding + /// those 2 spans individually). + pub fn delim_span(&self) -> DelimSpan { + DelimSpan::new(&self.inner) + } + + /// Configures the span for this `Group`'s delimiters, but not its int= ernal + /// tokens. + /// + /// This method will **not** set the span of all the internal tokens s= panned + /// by this group, but rather it will only set the span of the delimit= er + /// tokens at the level of the `Group`. + pub fn set_span(&mut self, span: Span) { + self.inner.set_span(span.inner); + } +} + +/// Prints the group as a string that should be losslessly convertible back +/// into the same group (modulo spans), except for possibly `TokenTree::Gr= oup`s +/// with `Delimiter::None` delimiters. +impl Display for Group { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + Display::fmt(&self.inner, formatter) + } +} + +impl Debug for Group { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + Debug::fmt(&self.inner, formatter) + } +} + +/// A `Punct` is a single punctuation character like `+`, `-` or `#`. +/// +/// Multicharacter operators like `+=3D` are represented as two instances = of +/// `Punct` with different forms of `Spacing` returned. +#[derive(Clone)] +pub struct Punct { + ch: char, + spacing: Spacing, + span: Span, +} + +/// Whether a `Punct` is followed immediately by another `Punct` or follow= ed by +/// another token or whitespace. +#[derive(Copy, Clone, Debug, Eq, PartialEq)] +pub enum Spacing { + /// E.g. `+` is `Alone` in `+ =3D`, `+ident` or `+()`. + Alone, + /// E.g. `+` is `Joint` in `+=3D` or `'` is `Joint` in `'#`. + /// + /// Additionally, single quote `'` can join with identifiers to form + /// lifetimes `'ident`. + Joint, +} + +impl Punct { + /// Creates a new `Punct` from the given character and spacing. + /// + /// The `ch` argument must be a valid punctuation character permitted = by the + /// language, otherwise the function will panic. + /// + /// The returned `Punct` will have the default span of `Span::call_sit= e()` + /// which can be further configured with the `set_span` method below. + pub fn new(ch: char, spacing: Spacing) -> Self { + if let '!' | '#' | '$' | '%' | '&' | '\'' | '*' | '+' | ',' | '-' = | '.' | '/' | ':' | ';' + | '<' | '=3D' | '>' | '?' | '@' | '^' | '|' | '~' =3D ch + { + Punct { + ch, + spacing, + span: Span::call_site(), + } + } else { + panic!("unsupported proc macro punctuation character {:?}", ch= ); + } + } + + /// Returns the value of this punctuation character as `char`. + pub fn as_char(&self) -> char { + self.ch + } + + /// Returns the spacing of this punctuation character, indicating whet= her + /// it's immediately followed by another `Punct` in the token stream, = so + /// they can potentially be combined into a multicharacter operator + /// (`Joint`), or it's followed by some other token or whitespace (`Al= one`) + /// so the operator has certainly ended. + pub fn spacing(&self) -> Spacing { + self.spacing + } + + /// Returns the span for this punctuation character. + pub fn span(&self) -> Span { + self.span + } + + /// Configure the span for this punctuation character. + pub fn set_span(&mut self, span: Span) { + self.span =3D span; + } +} + +/// Prints the punctuation character as a string that should be losslessly +/// convertible back into the same character. +impl Display for Punct { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + Display::fmt(&self.ch, f) + } +} + +impl Debug for Punct { + fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { + let mut debug =3D fmt.debug_struct("Punct"); + debug.field("char", &self.ch); + debug.field("spacing", &self.spacing); + imp::debug_span_field_if_nontrivial(&mut debug, self.span.inner); + debug.finish() + } +} + +/// A word of Rust code, which may be a keyword or legal variable name. +/// +/// An identifier consists of at least one Unicode code point, the first of +/// which has the XID_Start property and the rest of which have the XID_Co= ntinue +/// property. +/// +/// - The empty string is not an identifier. Use `Option`. +/// - A lifetime is not an identifier. Use `syn::Lifetime` instead. +/// +/// An identifier constructed with `Ident::new` is permitted to be a Rust +/// keyword, though parsing one through its [`Parse`] implementation rejec= ts +/// Rust keywords. Use `input.call(Ident::parse_any)` when parsing to matc= h the +/// behaviour of `Ident::new`. +/// +/// [`Parse`]: https://docs.rs/syn/2.0/syn/parse/trait.Parse.html +/// +/// # Examples +/// +/// A new ident can be created from a string using the `Ident::new` functi= on. +/// A span must be provided explicitly which governs the name resolution +/// behavior of the resulting identifier. +/// +/// ``` +/// use proc_macro2::{Ident, Span}; +/// +/// fn main() { +/// let call_ident =3D Ident::new("calligraphy", Span::call_site()); +/// +/// println!("{}", call_ident); +/// } +/// ``` +/// +/// An ident can be interpolated into a token stream using the `quote!` ma= cro. +/// +/// ``` +/// use proc_macro2::{Ident, Span}; +/// use quote::quote; +/// +/// fn main() { +/// let ident =3D Ident::new("demo", Span::call_site()); +/// +/// // Create a variable binding whose name is this ident. +/// let expanded =3D quote! { let #ident =3D 10; }; +/// +/// // Create a variable binding with a slightly different name. +/// let temp_ident =3D Ident::new(&format!("new_{}", ident), Span::cal= l_site()); +/// let expanded =3D quote! { let #temp_ident =3D 10; }; +/// } +/// ``` +/// +/// A string representation of the ident is available through the `to_stri= ng()` +/// method. +/// +/// ``` +/// # use proc_macro2::{Ident, Span}; +/// # +/// # let ident =3D Ident::new("another_identifier", Span::call_site()); +/// # +/// // Examine the ident as a string. +/// let ident_string =3D ident.to_string(); +/// if ident_string.len() > 60 { +/// println!("Very long identifier: {}", ident_string) +/// } +/// ``` +#[derive(Clone)] +pub struct Ident { + inner: imp::Ident, + _marker: ProcMacroAutoTraits, +} + +impl Ident { + fn _new(inner: imp::Ident) -> Self { + Ident { + inner, + _marker: MARKER, + } + } + + fn _new_fallback(inner: fallback::Ident) -> Self { + Ident { + inner: imp::Ident::from(inner), + _marker: MARKER, + } + } + + /// Creates a new `Ident` with the given `string` as well as the speci= fied + /// `span`. + /// + /// The `string` argument must be a valid identifier permitted by the + /// language, otherwise the function will panic. + /// + /// Note that `span`, currently in rustc, configures the hygiene infor= mation + /// for this identifier. + /// + /// As of this time `Span::call_site()` explicitly opts-in to "call-si= te" + /// hygiene meaning that identifiers created with this span will be re= solved + /// as if they were written directly at the location of the macro call= , and + /// other code at the macro call site will be able to refer to them as= well. + /// + /// Later spans like `Span::def_site()` will allow to opt-in to + /// "definition-site" hygiene meaning that identifiers created with th= is + /// span will be resolved at the location of the macro definition and = other + /// code at the macro call site will not be able to refer to them. + /// + /// Due to the current importance of hygiene this constructor, unlike = other + /// tokens, requires a `Span` to be specified at construction. + /// + /// # Panics + /// + /// Panics if the input string is neither a keyword nor a legal variab= le + /// name. If you are not sure whether the string contains an identifie= r and + /// need to handle an error case, use + /// syn::parse_str::<Ident> + /// rather than `Ident::new`. + #[track_caller] + pub fn new(string: &str, span: Span) -> Self { + Ident::_new(imp::Ident::new_checked(string, span.inner)) + } + + /// Same as `Ident::new`, but creates a raw identifier (`r#ident`). The + /// `string` argument must be a valid identifier permitted by the lang= uage + /// (including keywords, e.g. `fn`). Keywords which are usable in path + /// segments (e.g. `self`, `super`) are not supported, and will cause a + /// panic. + #[track_caller] + pub fn new_raw(string: &str, span: Span) -> Self { + Ident::_new(imp::Ident::new_raw_checked(string, span.inner)) + } + + /// Returns the span of this `Ident`. + pub fn span(&self) -> Span { + Span::_new(self.inner.span()) + } + + /// Configures the span of this `Ident`, possibly changing its hygiene + /// context. + pub fn set_span(&mut self, span: Span) { + self.inner.set_span(span.inner); + } +} + +impl PartialEq for Ident { + fn eq(&self, other: &Ident) -> bool { + self.inner =3D=3D other.inner + } +} + +impl PartialEq for Ident +where + T: ?Sized + AsRef, +{ + fn eq(&self, other: &T) -> bool { + self.inner =3D=3D other + } +} + +impl Eq for Ident {} + +impl PartialOrd for Ident { + fn partial_cmp(&self, other: &Ident) -> Option { + Some(self.cmp(other)) + } +} + +impl Ord for Ident { + fn cmp(&self, other: &Ident) -> Ordering { + self.to_string().cmp(&other.to_string()) + } +} + +impl Hash for Ident { + fn hash(&self, hasher: &mut H) { + self.to_string().hash(hasher); + } +} + +/// Prints the identifier as a string that should be losslessly convertibl= e back +/// into the same identifier. +impl Display for Ident { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + Display::fmt(&self.inner, f) + } +} + +impl Debug for Ident { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + Debug::fmt(&self.inner, f) + } +} + +/// A literal string (`"hello"`), byte string (`b"hello"`), character (`'a= '`), +/// byte character (`b'a'`), an integer or floating point number with or w= ithout +/// a suffix (`1`, `1u8`, `2.3`, `2.3f32`). +/// +/// Boolean literals like `true` and `false` do not belong here, they are +/// `Ident`s. +#[derive(Clone)] +pub struct Literal { + inner: imp::Literal, + _marker: ProcMacroAutoTraits, +} + +macro_rules! suffixed_int_literals { + ($($name:ident =3D> $kind:ident,)*) =3D> ($( + /// Creates a new suffixed integer literal with the specified valu= e. + /// + /// This function will create an integer like `1u32` where the int= eger + /// value specified is the first part of the token and the integra= l is + /// also suffixed at the end. Literals created from negative numbe= rs may + /// not survive roundtrips through `TokenStream` or strings and ma= y be + /// broken into two tokens (`-` and positive literal). + /// + /// Literals created through this method have the `Span::call_site= ()` + /// span by default, which can be configured with the `set_span` m= ethod + /// below. + pub fn $name(n: $kind) -> Literal { + Literal::_new(imp::Literal::$name(n)) + } + )*) +} + +macro_rules! unsuffixed_int_literals { + ($($name:ident =3D> $kind:ident,)*) =3D> ($( + /// Creates a new unsuffixed integer literal with the specified va= lue. + /// + /// This function will create an integer like `1` where the integer + /// value specified is the first part of the token. No suffix is + /// specified on this token, meaning that invocations like + /// `Literal::i8_unsuffixed(1)` are equivalent to + /// `Literal::u32_unsuffixed(1)`. Literals created from negative n= umbers + /// may not survive roundtrips through `TokenStream` or strings an= d may + /// be broken into two tokens (`-` and positive literal). + /// + /// Literals created through this method have the `Span::call_site= ()` + /// span by default, which can be configured with the `set_span` m= ethod + /// below. + pub fn $name(n: $kind) -> Literal { + Literal::_new(imp::Literal::$name(n)) + } + )*) +} + +impl Literal { + fn _new(inner: imp::Literal) -> Self { + Literal { + inner, + _marker: MARKER, + } + } + + fn _new_fallback(inner: fallback::Literal) -> Self { + Literal { + inner: imp::Literal::from(inner), + _marker: MARKER, + } + } + + suffixed_int_literals! { + u8_suffixed =3D> u8, + u16_suffixed =3D> u16, + u32_suffixed =3D> u32, + u64_suffixed =3D> u64, + u128_suffixed =3D> u128, + usize_suffixed =3D> usize, + i8_suffixed =3D> i8, + i16_suffixed =3D> i16, + i32_suffixed =3D> i32, + i64_suffixed =3D> i64, + i128_suffixed =3D> i128, + isize_suffixed =3D> isize, + } + + unsuffixed_int_literals! { + u8_unsuffixed =3D> u8, + u16_unsuffixed =3D> u16, + u32_unsuffixed =3D> u32, + u64_unsuffixed =3D> u64, + u128_unsuffixed =3D> u128, + usize_unsuffixed =3D> usize, + i8_unsuffixed =3D> i8, + i16_unsuffixed =3D> i16, + i32_unsuffixed =3D> i32, + i64_unsuffixed =3D> i64, + i128_unsuffixed =3D> i128, + isize_unsuffixed =3D> isize, + } + + /// Creates a new unsuffixed floating-point literal. + /// + /// This constructor is similar to those like `Literal::i8_unsuffixed`= where + /// the float's value is emitted directly into the token but no suffix= is + /// used, so it may be inferred to be a `f64` later in the compiler. + /// Literals created from negative numbers may not survive round-trips + /// through `TokenStream` or strings and may be broken into two tokens= (`-` + /// and positive literal). + /// + /// # Panics + /// + /// This function requires that the specified float is finite, for exa= mple + /// if it is infinity or NaN this function will panic. + pub fn f64_unsuffixed(f: f64) -> Literal { + assert!(f.is_finite()); + Literal::_new(imp::Literal::f64_unsuffixed(f)) + } + + /// Creates a new suffixed floating-point literal. + /// + /// This constructor will create a literal like `1.0f64` where the val= ue + /// specified is the preceding part of the token and `f64` is the suff= ix of + /// the token. This token will always be inferred to be an `f64` in the + /// compiler. Literals created from negative numbers may not survive + /// round-trips through `TokenStream` or strings and may be broken int= o two + /// tokens (`-` and positive literal). + /// + /// # Panics + /// + /// This function requires that the specified float is finite, for exa= mple + /// if it is infinity or NaN this function will panic. + pub fn f64_suffixed(f: f64) -> Literal { + assert!(f.is_finite()); + Literal::_new(imp::Literal::f64_suffixed(f)) + } + + /// Creates a new unsuffixed floating-point literal. + /// + /// This constructor is similar to those like `Literal::i8_unsuffixed`= where + /// the float's value is emitted directly into the token but no suffix= is + /// used, so it may be inferred to be a `f64` later in the compiler. + /// Literals created from negative numbers may not survive round-trips + /// through `TokenStream` or strings and may be broken into two tokens= (`-` + /// and positive literal). + /// + /// # Panics + /// + /// This function requires that the specified float is finite, for exa= mple + /// if it is infinity or NaN this function will panic. + pub fn f32_unsuffixed(f: f32) -> Literal { + assert!(f.is_finite()); + Literal::_new(imp::Literal::f32_unsuffixed(f)) + } + + /// Creates a new suffixed floating-point literal. + /// + /// This constructor will create a literal like `1.0f32` where the val= ue + /// specified is the preceding part of the token and `f32` is the suff= ix of + /// the token. This token will always be inferred to be an `f32` in the + /// compiler. Literals created from negative numbers may not survive + /// round-trips through `TokenStream` or strings and may be broken int= o two + /// tokens (`-` and positive literal). + /// + /// # Panics + /// + /// This function requires that the specified float is finite, for exa= mple + /// if it is infinity or NaN this function will panic. + pub fn f32_suffixed(f: f32) -> Literal { + assert!(f.is_finite()); + Literal::_new(imp::Literal::f32_suffixed(f)) + } + + /// String literal. + pub fn string(string: &str) -> Literal { + Literal::_new(imp::Literal::string(string)) + } + + /// Character literal. + pub fn character(ch: char) -> 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(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. + pub fn span(&self) -> Span { + Span::_new(self.inner.span()) + } + + /// Configures the span associated for this literal. + pub fn set_span(&mut self, span: Span) { + self.inner.set_span(span.inner); + } + + /// Returns a `Span` that is a subset of `self.span()` containing only + /// the source bytes in range `range`. Returns `None` if the would-be + /// trimmed span is outside the bounds of `self`. + /// + /// Warning: the underlying [`proc_macro::Literal::subspan`] method is + /// nightly-only. When called from within a procedural macro not using= a + /// nightly compiler, this method will always return `None`. + pub fn subspan>(&self, range: R) -> Option= { + self.inner.subspan(range).map(Span::_new) + } + + // Intended for the `quote!` macro to use when constructing a proc-mac= ro2 + // token out of a macro_rules $:literal token, which is already known = to be + // a valid literal. This avoids reparsing/validating the literal's str= ing + // representation. This is not public API other than for quote. + #[doc(hidden)] + pub unsafe fn from_str_unchecked(repr: &str) -> Self { + Literal::_new(unsafe { imp::Literal::from_str_unchecked(repr) }) + } +} + +impl FromStr for Literal { + type Err =3D LexError; + + fn from_str(repr: &str) -> Result { + match imp::Literal::from_str_checked(repr) { + Ok(lit) =3D> Ok(Literal::_new(lit)), + Err(lex) =3D> Err(LexError { + inner: lex, + _marker: MARKER, + }), + } + } +} + +impl Debug for Literal { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + Debug::fmt(&self.inner, f) + } +} + +impl Display for Literal { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + Display::fmt(&self.inner, f) + } +} + +/// Public implementation details for the `TokenStream` type, such as iter= ators. +pub mod token_stream { + use crate::marker::{ProcMacroAutoTraits, MARKER}; + use crate::{imp, TokenTree}; + use core::fmt::{self, Debug}; + + pub use crate::TokenStream; + + /// An iterator over `TokenStream`'s `TokenTree`s. + /// + /// The iteration is "shallow", e.g. the iterator doesn't recurse into + /// delimited groups, and returns whole groups as token trees. + #[derive(Clone)] + pub struct IntoIter { + inner: imp::TokenTreeIter, + _marker: ProcMacroAutoTraits, + } + + impl Iterator for IntoIter { + type Item =3D TokenTree; + + fn next(&mut self) -> Option { + self.inner.next() + } + + fn size_hint(&self) -> (usize, Option) { + self.inner.size_hint() + } + } + + impl Debug for IntoIter { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + f.write_str("TokenStream ")?; + f.debug_list().entries(self.clone()).finish() + } + } + + impl IntoIterator for TokenStream { + type Item =3D TokenTree; + type IntoIter =3D IntoIter; + + fn into_iter(self) -> IntoIter { + IntoIter { + inner: self.inner.into_iter(), + _marker: MARKER, + } + } + } +} diff --git a/rust/proc-macro2/location.rs b/rust/proc-macro2/location.rs new file mode 100644 index 000000000000..7190e2d05255 --- /dev/null +++ b/rust/proc-macro2/location.rs @@ -0,0 +1,29 @@ +use core::cmp::Ordering; + +/// A line-column pair representing the start or end of a `Span`. +/// +/// This type is semver exempt and not exposed by default. +#[cfg_attr(docsrs, doc(cfg(feature =3D "span-locations")))] +#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)] +pub struct LineColumn { + /// The 1-indexed line in the source file on which the span starts or = ends + /// (inclusive). + pub line: usize, + /// The 0-indexed column (in UTF-8 characters) in the source file on w= hich + /// the span starts or ends (inclusive). + pub column: usize, +} + +impl Ord for LineColumn { + fn cmp(&self, other: &Self) -> Ordering { + self.line + .cmp(&other.line) + .then(self.column.cmp(&other.column)) + } +} + +impl PartialOrd for LineColumn { + fn partial_cmp(&self, other: &Self) -> Option { + Some(self.cmp(other)) + } +} diff --git a/rust/proc-macro2/marker.rs b/rust/proc-macro2/marker.rs new file mode 100644 index 000000000000..23b94ce6fa85 --- /dev/null +++ b/rust/proc-macro2/marker.rs @@ -0,0 +1,17 @@ +use alloc::rc::Rc; +use core::marker::PhantomData; +use core::panic::{RefUnwindSafe, UnwindSafe}; + +// Zero sized marker with the correct set of autotrait impls we want all p= roc +// macro types to have. +#[derive(Copy, Clone)] +#[cfg_attr( + all(procmacro2_semver_exempt, any(not(wrap_proc_macro), super_unstable= )), + derive(PartialEq, Eq) +)] +pub(crate) struct ProcMacroAutoTraits(PhantomData>); + +pub(crate) const MARKER: ProcMacroAutoTraits =3D ProcMacroAutoTraits(Phant= omData); + +impl UnwindSafe for ProcMacroAutoTraits {} +impl RefUnwindSafe for ProcMacroAutoTraits {} diff --git a/rust/proc-macro2/parse.rs b/rust/proc-macro2/parse.rs new file mode 100644 index 000000000000..b8be403f842f --- /dev/null +++ b/rust/proc-macro2/parse.rs @@ -0,0 +1,995 @@ +use crate::fallback::{ + self, is_ident_continue, is_ident_start, Group, Ident, LexError, Liter= al, Span, TokenStream, + TokenStreamBuilder, +}; +use crate::{Delimiter, Punct, Spacing, TokenTree}; +use core::char; +use core::str::{Bytes, CharIndices, Chars}; + +#[derive(Copy, Clone, Eq, PartialEq)] +pub(crate) struct Cursor<'a> { + pub(crate) rest: &'a str, + #[cfg(span_locations)] + pub(crate) off: u32, +} + +impl<'a> Cursor<'a> { + pub(crate) fn advance(&self, bytes: usize) -> Cursor<'a> { + let (_front, rest) =3D self.rest.split_at(bytes); + Cursor { + rest, + #[cfg(span_locations)] + off: self.off + _front.chars().count() as u32, + } + } + + pub(crate) fn starts_with(&self, s: &str) -> bool { + self.rest.starts_with(s) + } + + pub(crate) fn starts_with_char(&self, ch: char) -> bool { + self.rest.starts_with(ch) + } + + pub(crate) fn starts_with_fn(&self, f: Pattern) -> bool + where + Pattern: FnMut(char) -> bool, + { + self.rest.starts_with(f) + } + + pub(crate) fn is_empty(&self) -> bool { + self.rest.is_empty() + } + + fn len(&self) -> usize { + self.rest.len() + } + + fn as_bytes(&self) -> &'a [u8] { + self.rest.as_bytes() + } + + fn bytes(&self) -> Bytes<'a> { + self.rest.bytes() + } + + fn chars(&self) -> Chars<'a> { + self.rest.chars() + } + + fn char_indices(&self) -> CharIndices<'a> { + self.rest.char_indices() + } + + fn parse(&self, tag: &str) -> Result, Reject> { + if self.starts_with(tag) { + Ok(self.advance(tag.len())) + } else { + Err(Reject) + } + } +} + +pub(crate) struct Reject; +type PResult<'a, O> =3D Result<(Cursor<'a>, O), Reject>; + +fn skip_whitespace(input: Cursor) -> Cursor { + let mut s =3D input; + + while !s.is_empty() { + let byte =3D s.as_bytes()[0]; + if byte =3D=3D b'/' { + if s.starts_with("//") + && (!s.starts_with("///") || s.starts_with("////")) + && !s.starts_with("//!") + { + let (cursor, _) =3D take_until_newline_or_eof(s); + s =3D cursor; + continue; + } else if s.starts_with("/**/") { + s =3D s.advance(4); + continue; + } else if s.starts_with("/*") + && (!s.starts_with("/**") || s.starts_with("/***")) + && !s.starts_with("/*!") + { + match block_comment(s) { + Ok((rest, _)) =3D> { + s =3D rest; + continue; + } + Err(Reject) =3D> return s, + } + } + } + match byte { + b' ' | 0x09..=3D0x0d =3D> { + s =3D s.advance(1); + continue; + } + b if b.is_ascii() =3D> {} + _ =3D> { + let ch =3D s.chars().next().unwrap(); + if is_whitespace(ch) { + s =3D s.advance(ch.len_utf8()); + continue; + } + } + } + return s; + } + s +} + +fn block_comment(input: Cursor) -> PResult<&str> { + if !input.starts_with("/*") { + return Err(Reject); + } + + let mut depth =3D 0usize; + let bytes =3D input.as_bytes(); + let mut i =3D 0usize; + let upper =3D bytes.len() - 1; + + while i < upper { + if bytes[i] =3D=3D b'/' && bytes[i + 1] =3D=3D b'*' { + depth +=3D 1; + i +=3D 1; // eat '*' + } else if bytes[i] =3D=3D b'*' && bytes[i + 1] =3D=3D b'/' { + depth -=3D 1; + if depth =3D=3D 0 { + return Ok((input.advance(i + 2), &input.rest[..i + 2])); + } + i +=3D 1; // eat '/' + } + i +=3D 1; + } + + Err(Reject) +} + +fn is_whitespace(ch: char) -> bool { + // Rust treats left-to-right mark and right-to-left mark as whitespace + ch.is_whitespace() || ch =3D=3D '\u{200e}' || ch =3D=3D '\u{200f}' +} + +fn word_break(input: Cursor) -> Result { + match input.chars().next() { + Some(ch) if is_ident_continue(ch) =3D> Err(Reject), + Some(_) | None =3D> Ok(input), + } +} + +// Rustc's representation of a macro expansion error in expression positio= n or +// type position. +const ERROR: &str =3D "(/*ERROR*/)"; + +pub(crate) fn token_stream(mut input: Cursor) -> Result { + let mut trees =3D TokenStreamBuilder::new(); + let mut stack =3D Vec::new(); + + loop { + input =3D skip_whitespace(input); + + if let Ok((rest, ())) =3D doc_comment(input, &mut trees) { + input =3D rest; + continue; + } + + #[cfg(span_locations)] + let lo =3D input.off; + + let first =3D match input.bytes().next() { + Some(first) =3D> first, + None =3D> match stack.last() { + None =3D> return Ok(trees.build()), + #[cfg(span_locations)] + Some((lo, _frame)) =3D> { + return Err(LexError { + span: Span { lo: *lo, hi: *lo }, + }) + } + #[cfg(not(span_locations))] + Some(_frame) =3D> return Err(LexError { span: Span {} }), + }, + }; + + if let Some(open_delimiter) =3D match first { + b'(' if !input.starts_with(ERROR) =3D> Some(Delimiter::Parenth= esis), + b'[' =3D> Some(Delimiter::Bracket), + b'{' =3D> Some(Delimiter::Brace), + _ =3D> None, + } { + input =3D input.advance(1); + let frame =3D (open_delimiter, trees); + #[cfg(span_locations)] + let frame =3D (lo, frame); + stack.push(frame); + trees =3D TokenStreamBuilder::new(); + } else if let Some(close_delimiter) =3D match first { + b')' =3D> Some(Delimiter::Parenthesis), + b']' =3D> Some(Delimiter::Bracket), + b'}' =3D> Some(Delimiter::Brace), + _ =3D> None, + } { + let frame =3D match stack.pop() { + Some(frame) =3D> frame, + None =3D> return Err(lex_error(input)), + }; + #[cfg(span_locations)] + let (lo, frame) =3D frame; + let (open_delimiter, outer) =3D frame; + if open_delimiter !=3D close_delimiter { + return Err(lex_error(input)); + } + input =3D input.advance(1); + let mut g =3D Group::new(open_delimiter, trees.build()); + g.set_span(Span { + #[cfg(span_locations)] + lo, + #[cfg(span_locations)] + hi: input.off, + }); + trees =3D outer; + trees.push_token_from_parser(TokenTree::Group(crate::Group::_n= ew_fallback(g))); + } else { + let (rest, mut tt) =3D match leaf_token(input) { + Ok((rest, tt)) =3D> (rest, tt), + Err(Reject) =3D> return Err(lex_error(input)), + }; + tt.set_span(crate::Span::_new_fallback(Span { + #[cfg(span_locations)] + lo, + #[cfg(span_locations)] + hi: rest.off, + })); + trees.push_token_from_parser(tt); + input =3D rest; + } + } +} + +fn lex_error(cursor: Cursor) -> LexError { + #[cfg(not(span_locations))] + let _ =3D cursor; + LexError { + span: Span { + #[cfg(span_locations)] + lo: cursor.off, + #[cfg(span_locations)] + hi: cursor.off, + }, + } +} + +fn leaf_token(input: Cursor) -> PResult { + if let Ok((input, l)) =3D literal(input) { + // must be parsed before ident + Ok((input, TokenTree::Literal(crate::Literal::_new_fallback(l)))) + } else if let Ok((input, p)) =3D punct(input) { + Ok((input, TokenTree::Punct(p))) + } else if let Ok((input, i)) =3D ident(input) { + Ok((input, TokenTree::Ident(i))) + } else if input.starts_with(ERROR) { + let rest =3D input.advance(ERROR.len()); + let repr =3D crate::Literal::_new_fallback(Literal::_new(ERROR.to_= owned())); + Ok((rest, TokenTree::Literal(repr))) + } else { + Err(Reject) + } +} + +fn ident(input: Cursor) -> PResult { + if [ + "r\"", "r#\"", "r##", "b\"", "b\'", "br\"", "br#", "c\"", "cr\"", = "cr#", + ] + .iter() + .any(|prefix| input.starts_with(prefix)) + { + Err(Reject) + } else { + ident_any(input) + } +} + +fn ident_any(input: Cursor) -> PResult { + let raw =3D input.starts_with("r#"); + let rest =3D input.advance((raw as usize) << 1); + + let (rest, sym) =3D ident_not_raw(rest)?; + + if !raw { + let ident =3D + crate::Ident::_new_fallback(Ident::new_unchecked(sym, fallback= ::Span::call_site())); + return Ok((rest, ident)); + } + + match sym { + "_" | "super" | "self" | "Self" | "crate" =3D> return Err(Reject), + _ =3D> {} + } + + let ident =3D + crate::Ident::_new_fallback(Ident::new_raw_unchecked(sym, fallback= ::Span::call_site())); + Ok((rest, ident)) +} + +fn ident_not_raw(input: Cursor) -> PResult<&str> { + let mut chars =3D input.char_indices(); + + match chars.next() { + Some((_, ch)) if is_ident_start(ch) =3D> {} + _ =3D> return Err(Reject), + } + + let mut end =3D input.len(); + for (i, ch) in chars { + if !is_ident_continue(ch) { + end =3D i; + break; + } + } + + Ok((input.advance(end), &input.rest[..end])) +} + +pub(crate) fn literal(input: Cursor) -> PResult { + let rest =3D literal_nocapture(input)?; + let end =3D input.len() - rest.len(); + Ok((rest, Literal::_new(input.rest[..end].to_string()))) +} + +fn literal_nocapture(input: Cursor) -> Result { + if let Ok(ok) =3D string(input) { + Ok(ok) + } else if let Ok(ok) =3D byte_string(input) { + Ok(ok) + } else if let Ok(ok) =3D c_string(input) { + Ok(ok) + } else if let Ok(ok) =3D byte(input) { + Ok(ok) + } else if let Ok(ok) =3D character(input) { + Ok(ok) + } else if let Ok(ok) =3D float(input) { + Ok(ok) + } else if let Ok(ok) =3D int(input) { + Ok(ok) + } else { + Err(Reject) + } +} + +fn literal_suffix(input: Cursor) -> Cursor { + match ident_not_raw(input) { + Ok((input, _)) =3D> input, + Err(Reject) =3D> input, + } +} + +fn string(input: Cursor) -> Result { + if let Ok(input) =3D input.parse("\"") { + cooked_string(input) + } else if let Ok(input) =3D input.parse("r") { + raw_string(input) + } else { + Err(Reject) + } +} + +fn cooked_string(mut input: Cursor) -> Result { + let mut chars =3D input.char_indices(); + + while let Some((i, ch)) =3D chars.next() { + match ch { + '"' =3D> { + let input =3D input.advance(i + 1); + return Ok(literal_suffix(input)); + } + '\r' =3D> match chars.next() { + Some((_, '\n')) =3D> {} + _ =3D> break, + }, + '\\' =3D> match chars.next() { + Some((_, 'x')) =3D> { + backslash_x_char(&mut chars)?; + } + Some((_, 'n' | 'r' | 't' | '\\' | '\'' | '"' | '0')) =3D> = {} + Some((_, 'u')) =3D> { + backslash_u(&mut chars)?; + } + Some((newline, ch @ ('\n' | '\r'))) =3D> { + input =3D input.advance(newline + 1); + trailing_backslash(&mut input, ch as u8)?; + chars =3D input.char_indices(); + } + _ =3D> break, + }, + _ch =3D> {} + } + } + Err(Reject) +} + +fn raw_string(input: Cursor) -> Result { + let (input, delimiter) =3D delimiter_of_raw_string(input)?; + let mut bytes =3D input.bytes().enumerate(); + while let Some((i, byte)) =3D bytes.next() { + match byte { + b'"' if input.rest[i + 1..].starts_with(delimiter) =3D> { + let rest =3D input.advance(i + 1 + delimiter.len()); + return Ok(literal_suffix(rest)); + } + b'\r' =3D> match bytes.next() { + Some((_, b'\n')) =3D> {} + _ =3D> break, + }, + _ =3D> {} + } + } + Err(Reject) +} + +fn byte_string(input: Cursor) -> Result { + if let Ok(input) =3D input.parse("b\"") { + cooked_byte_string(input) + } else if let Ok(input) =3D input.parse("br") { + raw_byte_string(input) + } else { + Err(Reject) + } +} + +fn cooked_byte_string(mut input: Cursor) -> Result { + let mut bytes =3D input.bytes().enumerate(); + while let Some((offset, b)) =3D bytes.next() { + match b { + b'"' =3D> { + let input =3D input.advance(offset + 1); + return Ok(literal_suffix(input)); + } + b'\r' =3D> match bytes.next() { + Some((_, b'\n')) =3D> {} + _ =3D> break, + }, + b'\\' =3D> match bytes.next() { + Some((_, b'x')) =3D> { + backslash_x_byte(&mut bytes)?; + } + Some((_, b'n' | b'r' | b't' | b'\\' | b'0' | b'\'' | b'"')= ) =3D> {} + Some((newline, b @ (b'\n' | b'\r'))) =3D> { + input =3D input.advance(newline + 1); + trailing_backslash(&mut input, b)?; + bytes =3D input.bytes().enumerate(); + } + _ =3D> break, + }, + b if b.is_ascii() =3D> {} + _ =3D> break, + } + } + Err(Reject) +} + +fn delimiter_of_raw_string(input: Cursor) -> PResult<&str> { + for (i, byte) in input.bytes().enumerate() { + match byte { + b'"' =3D> { + if i > 255 { + // https://github.com/rust-lang/rust/pull/95251 + return Err(Reject); + } + return Ok((input.advance(i + 1), &input.rest[..i])); + } + b'#' =3D> {} + _ =3D> break, + } + } + Err(Reject) +} + +fn raw_byte_string(input: Cursor) -> Result { + let (input, delimiter) =3D delimiter_of_raw_string(input)?; + let mut bytes =3D input.bytes().enumerate(); + while let Some((i, byte)) =3D bytes.next() { + match byte { + b'"' if input.rest[i + 1..].starts_with(delimiter) =3D> { + let rest =3D input.advance(i + 1 + delimiter.len()); + return Ok(literal_suffix(rest)); + } + b'\r' =3D> match bytes.next() { + Some((_, b'\n')) =3D> {} + _ =3D> break, + }, + other =3D> { + if !other.is_ascii() { + break; + } + } + } + } + Err(Reject) +} + +fn c_string(input: Cursor) -> Result { + if let Ok(input) =3D input.parse("c\"") { + cooked_c_string(input) + } else if let Ok(input) =3D input.parse("cr") { + raw_c_string(input) + } else { + Err(Reject) + } +} + +fn raw_c_string(input: Cursor) -> Result { + let (input, delimiter) =3D delimiter_of_raw_string(input)?; + let mut bytes =3D input.bytes().enumerate(); + while let Some((i, byte)) =3D bytes.next() { + match byte { + b'"' if input.rest[i + 1..].starts_with(delimiter) =3D> { + let rest =3D input.advance(i + 1 + delimiter.len()); + return Ok(literal_suffix(rest)); + } + b'\r' =3D> match bytes.next() { + Some((_, b'\n')) =3D> {} + _ =3D> break, + }, + b'\0' =3D> break, + _ =3D> {} + } + } + Err(Reject) +} + +fn cooked_c_string(mut input: Cursor) -> Result { + let mut chars =3D input.char_indices(); + + while let Some((i, ch)) =3D chars.next() { + match ch { + '"' =3D> { + let input =3D input.advance(i + 1); + return Ok(literal_suffix(input)); + } + '\r' =3D> match chars.next() { + Some((_, '\n')) =3D> {} + _ =3D> break, + }, + '\\' =3D> match chars.next() { + Some((_, 'x')) =3D> { + backslash_x_nonzero(&mut chars)?; + } + Some((_, 'n' | 'r' | 't' | '\\' | '\'' | '"')) =3D> {} + Some((_, 'u')) =3D> { + if backslash_u(&mut chars)? =3D=3D '\0' { + break; + } + } + Some((newline, ch @ ('\n' | '\r'))) =3D> { + input =3D input.advance(newline + 1); + trailing_backslash(&mut input, ch as u8)?; + chars =3D input.char_indices(); + } + _ =3D> break, + }, + '\0' =3D> break, + _ch =3D> {} + } + } + Err(Reject) +} + +fn byte(input: Cursor) -> Result { + let input =3D input.parse("b'")?; + let mut bytes =3D input.bytes().enumerate(); + let ok =3D match bytes.next().map(|(_, b)| b) { + Some(b'\\') =3D> match bytes.next().map(|(_, b)| b) { + Some(b'x') =3D> backslash_x_byte(&mut bytes).is_ok(), + Some(b'n' | b'r' | b't' | b'\\' | b'0' | b'\'' | b'"') =3D> tr= ue, + _ =3D> false, + }, + b =3D> b.is_some(), + }; + if !ok { + return Err(Reject); + } + let (offset, _) =3D bytes.next().ok_or(Reject)?; + if !input.chars().as_str().is_char_boundary(offset) { + return Err(Reject); + } + let input =3D input.advance(offset).parse("'")?; + Ok(literal_suffix(input)) +} + +fn character(input: Cursor) -> Result { + let input =3D input.parse("'")?; + let mut chars =3D input.char_indices(); + let ok =3D match chars.next().map(|(_, ch)| ch) { + Some('\\') =3D> match chars.next().map(|(_, ch)| ch) { + Some('x') =3D> backslash_x_char(&mut chars).is_ok(), + Some('u') =3D> backslash_u(&mut chars).is_ok(), + Some('n' | 'r' | 't' | '\\' | '0' | '\'' | '"') =3D> true, + _ =3D> false, + }, + ch =3D> ch.is_some(), + }; + if !ok { + return Err(Reject); + } + let (idx, _) =3D chars.next().ok_or(Reject)?; + let input =3D input.advance(idx).parse("'")?; + Ok(literal_suffix(input)) +} + +macro_rules! next_ch { + ($chars:ident @ $pat:pat) =3D> { + match $chars.next() { + Some((_, ch)) =3D> match ch { + $pat =3D> ch, + _ =3D> return Err(Reject), + }, + None =3D> return Err(Reject), + } + }; +} + +fn backslash_x_char(chars: &mut I) -> Result<(), Reject> +where + I: Iterator, +{ + next_ch!(chars @ '0'..=3D'7'); + next_ch!(chars @ '0'..=3D'9' | 'a'..=3D'f' | 'A'..=3D'F'); + Ok(()) +} + +fn backslash_x_byte(chars: &mut I) -> Result<(), Reject> +where + I: Iterator, +{ + next_ch!(chars @ b'0'..=3Db'9' | b'a'..=3Db'f' | b'A'..=3Db'F'); + next_ch!(chars @ b'0'..=3Db'9' | b'a'..=3Db'f' | b'A'..=3Db'F'); + Ok(()) +} + +fn backslash_x_nonzero(chars: &mut I) -> Result<(), Reject> +where + I: Iterator, +{ + let first =3D next_ch!(chars @ '0'..=3D'9' | 'a'..=3D'f' | 'A'..=3D'F'= ); + let second =3D next_ch!(chars @ '0'..=3D'9' | 'a'..=3D'f' | 'A'..=3D'F= '); + if first =3D=3D '0' && second =3D=3D '0' { + Err(Reject) + } else { + Ok(()) + } +} + +fn backslash_u(chars: &mut I) -> Result +where + I: Iterator, +{ + next_ch!(chars @ '{'); + let mut value =3D 0; + let mut len =3D 0; + for (_, ch) in chars { + let digit =3D match ch { + '0'..=3D'9' =3D> ch as u8 - b'0', + 'a'..=3D'f' =3D> 10 + ch as u8 - b'a', + 'A'..=3D'F' =3D> 10 + ch as u8 - b'A', + '_' if len > 0 =3D> continue, + '}' if len > 0 =3D> return char::from_u32(value).ok_or(Reject), + _ =3D> break, + }; + if len =3D=3D 6 { + break; + } + value *=3D 0x10; + value +=3D u32::from(digit); + len +=3D 1; + } + Err(Reject) +} + +fn trailing_backslash(input: &mut Cursor, mut last: u8) -> Result<(), Reje= ct> { + let mut whitespace =3D input.bytes().enumerate(); + loop { + if last =3D=3D b'\r' && whitespace.next().map_or(true, |(_, b)| b = !=3D b'\n') { + return Err(Reject); + } + match whitespace.next() { + Some((_, b @ (b' ' | b'\t' | b'\n' | b'\r'))) =3D> { + last =3D b; + } + Some((offset, _)) =3D> { + *input =3D input.advance(offset); + return Ok(()); + } + None =3D> return Err(Reject), + } + } +} + +fn float(input: Cursor) -> Result { + let mut rest =3D float_digits(input)?; + if let Some(ch) =3D rest.chars().next() { + if is_ident_start(ch) { + rest =3D ident_not_raw(rest)?.0; + } + } + word_break(rest) +} + +fn float_digits(input: Cursor) -> Result { + let mut chars =3D input.chars().peekable(); + match chars.next() { + Some(ch) if '0' <=3D ch && ch <=3D '9' =3D> {} + _ =3D> return Err(Reject), + } + + let mut len =3D 1; + let mut has_dot =3D false; + let mut has_exp =3D false; + while let Some(&ch) =3D chars.peek() { + match ch { + '0'..=3D'9' | '_' =3D> { + chars.next(); + len +=3D 1; + } + '.' =3D> { + if has_dot { + break; + } + chars.next(); + if chars + .peek() + .map_or(false, |&ch| ch =3D=3D '.' || is_ident_start(c= h)) + { + return Err(Reject); + } + len +=3D 1; + has_dot =3D true; + } + 'e' | 'E' =3D> { + chars.next(); + len +=3D 1; + has_exp =3D true; + break; + } + _ =3D> break, + } + } + + if !(has_dot || has_exp) { + return Err(Reject); + } + + if has_exp { + let token_before_exp =3D if has_dot { + Ok(input.advance(len - 1)) + } else { + Err(Reject) + }; + let mut has_sign =3D false; + let mut has_exp_value =3D false; + while let Some(&ch) =3D chars.peek() { + match ch { + '+' | '-' =3D> { + if has_exp_value { + break; + } + if has_sign { + return token_before_exp; + } + chars.next(); + len +=3D 1; + has_sign =3D true; + } + '0'..=3D'9' =3D> { + chars.next(); + len +=3D 1; + has_exp_value =3D true; + } + '_' =3D> { + chars.next(); + len +=3D 1; + } + _ =3D> break, + } + } + if !has_exp_value { + return token_before_exp; + } + } + + Ok(input.advance(len)) +} + +fn int(input: Cursor) -> Result { + let mut rest =3D digits(input)?; + if let Some(ch) =3D rest.chars().next() { + if is_ident_start(ch) { + rest =3D ident_not_raw(rest)?.0; + } + } + word_break(rest) +} + +fn digits(mut input: Cursor) -> Result { + let base =3D if input.starts_with("0x") { + input =3D input.advance(2); + 16 + } else if input.starts_with("0o") { + input =3D input.advance(2); + 8 + } else if input.starts_with("0b") { + input =3D input.advance(2); + 2 + } else { + 10 + }; + + let mut len =3D 0; + let mut empty =3D true; + for b in input.bytes() { + match b { + b'0'..=3Db'9' =3D> { + let digit =3D (b - b'0') as u64; + if digit >=3D base { + return Err(Reject); + } + } + b'a'..=3Db'f' =3D> { + let digit =3D 10 + (b - b'a') as u64; + if digit >=3D base { + break; + } + } + b'A'..=3Db'F' =3D> { + let digit =3D 10 + (b - b'A') as u64; + if digit >=3D base { + break; + } + } + b'_' =3D> { + if empty && base =3D=3D 10 { + return Err(Reject); + } + len +=3D 1; + continue; + } + _ =3D> break, + } + len +=3D 1; + empty =3D false; + } + if empty { + Err(Reject) + } else { + Ok(input.advance(len)) + } +} + +fn punct(input: Cursor) -> PResult { + let (rest, ch) =3D punct_char(input)?; + if ch =3D=3D '\'' { + let (after_lifetime, _ident) =3D ident_any(rest)?; + if after_lifetime.starts_with_char('\'') + || (after_lifetime.starts_with_char('#') && !rest.starts_with(= "r#")) + { + Err(Reject) + } else { + Ok((rest, Punct::new('\'', Spacing::Joint))) + } + } else { + let kind =3D match punct_char(rest) { + Ok(_) =3D> Spacing::Joint, + Err(Reject) =3D> Spacing::Alone, + }; + Ok((rest, Punct::new(ch, kind))) + } +} + +fn punct_char(input: Cursor) -> PResult { + if input.starts_with("//") || input.starts_with("/*") { + // Do not accept `/` of a comment as a punct. + return Err(Reject); + } + + let mut chars =3D input.chars(); + let first =3D match chars.next() { + Some(ch) =3D> ch, + None =3D> { + return Err(Reject); + } + }; + let recognized =3D "~!@#$%^&*-=3D+|;:,<.>/?'"; + if recognized.contains(first) { + Ok((input.advance(first.len_utf8()), first)) + } else { + Err(Reject) + } +} + +fn doc_comment<'a>(input: Cursor<'a>, trees: &mut TokenStreamBuilder) -> P= Result<'a, ()> { + #[cfg(span_locations)] + let lo =3D input.off; + let (rest, (comment, inner)) =3D doc_comment_contents(input)?; + let fallback_span =3D Span { + #[cfg(span_locations)] + lo, + #[cfg(span_locations)] + hi: rest.off, + }; + let span =3D crate::Span::_new_fallback(fallback_span); + + let mut scan_for_bare_cr =3D comment; + while let Some(cr) =3D scan_for_bare_cr.find('\r') { + let rest =3D &scan_for_bare_cr[cr + 1..]; + if !rest.starts_with('\n') { + return Err(Reject); + } + scan_for_bare_cr =3D rest; + } + + let mut pound =3D Punct::new('#', Spacing::Alone); + pound.set_span(span); + trees.push_token_from_parser(TokenTree::Punct(pound)); + + if inner { + let mut bang =3D Punct::new('!', Spacing::Alone); + bang.set_span(span); + trees.push_token_from_parser(TokenTree::Punct(bang)); + } + + let doc_ident =3D crate::Ident::_new_fallback(Ident::new_unchecked("do= c", fallback_span)); + let mut equal =3D Punct::new('=3D', Spacing::Alone); + equal.set_span(span); + let mut literal =3D crate::Literal::_new_fallback(Literal::string(comm= ent)); + literal.set_span(span); + let mut bracketed =3D TokenStreamBuilder::with_capacity(3); + bracketed.push_token_from_parser(TokenTree::Ident(doc_ident)); + bracketed.push_token_from_parser(TokenTree::Punct(equal)); + bracketed.push_token_from_parser(TokenTree::Literal(literal)); + let group =3D Group::new(Delimiter::Bracket, bracketed.build()); + let mut group =3D crate::Group::_new_fallback(group); + group.set_span(span); + trees.push_token_from_parser(TokenTree::Group(group)); + + Ok((rest, ())) +} + +fn doc_comment_contents(input: Cursor) -> PResult<(&str, bool)> { + if input.starts_with("//!") { + let input =3D input.advance(3); + let (input, s) =3D take_until_newline_or_eof(input); + Ok((input, (s, true))) + } else if input.starts_with("/*!") { + let (input, s) =3D block_comment(input)?; + Ok((input, (&s[3..s.len() - 2], true))) + } else if input.starts_with("///") { + let input =3D input.advance(3); + if input.starts_with_char('/') { + return Err(Reject); + } + let (input, s) =3D take_until_newline_or_eof(input); + Ok((input, (s, false))) + } else if input.starts_with("/**") && !input.rest[3..].starts_with('*'= ) { + let (input, s) =3D block_comment(input)?; + Ok((input, (&s[3..s.len() - 2], false))) + } else { + Err(Reject) + } +} + +fn take_until_newline_or_eof(input: Cursor) -> (Cursor, &str) { + let chars =3D input.char_indices(); + + for (i, ch) in chars { + if ch =3D=3D '\n' { + return (input.advance(i), &input.rest[..i]); + } else if ch =3D=3D '\r' && input.rest[i + 1..].starts_with('\n') { + return (input.advance(i + 1), &input.rest[..i]); + } + } + + (input.advance(input.len()), input.rest) +} diff --git a/rust/proc-macro2/probe.rs b/rust/proc-macro2/probe.rs new file mode 100644 index 000000000000..b67f52036218 --- /dev/null +++ b/rust/proc-macro2/probe.rs @@ -0,0 +1,10 @@ +#![allow(dead_code)] + +#[cfg(proc_macro_span)] +pub(crate) mod proc_macro_span; + +#[cfg(proc_macro_span_file)] +pub(crate) mod proc_macro_span_file; + +#[cfg(proc_macro_span_location)] +pub(crate) mod proc_macro_span_location; diff --git a/rust/proc-macro2/probe/proc_macro_span.rs b/rust/proc-macro2/p= robe/proc_macro_span.rs new file mode 100644 index 000000000000..2d7d44e07708 --- /dev/null +++ b/rust/proc-macro2/probe/proc_macro_span.rs @@ -0,0 +1,51 @@ +// This code exercises the surface area that we expect of Span's unstable = API. +// If the current toolchain is able to compile it, then proc-macro2 is abl= e to +// offer these APIs too. + +#![cfg_attr(procmacro2_build_probe, feature(proc_macro_span))] + +extern crate proc_macro; + +use core::ops::{Range, RangeBounds}; +use proc_macro::{Literal, Span}; +use std::path::PathBuf; + +pub fn byte_range(this: &Span) -> Range { + this.byte_range() +} + +pub fn start(this: &Span) -> Span { + this.start() +} + +pub fn end(this: &Span) -> Span { + this.end() +} + +pub fn line(this: &Span) -> usize { + this.line() +} + +pub fn column(this: &Span) -> usize { + this.column() +} + +pub fn file(this: &Span) -> String { + this.file() +} + +pub fn local_file(this: &Span) -> Option { + this.local_file() +} + +pub fn join(this: &Span, other: Span) -> Option { + this.join(other) +} + +pub fn subspan>(this: &Literal, range: R) -> Option<= Span> { + this.subspan(range) +} + +// Include in sccache cache key. +#[cfg(procmacro2_build_probe)] +const _: Option<&str> =3D option_env!("RUSTC_BOOTSTRAP"); diff --git a/rust/proc-macro2/probe/proc_macro_span_file.rs b/rust/proc-mac= ro2/probe/proc_macro_span_file.rs new file mode 100644 index 000000000000..8b76bdf5007b --- /dev/null +++ b/rust/proc-macro2/probe/proc_macro_span_file.rs @@ -0,0 +1,14 @@ +// The subset of Span's API stabilized in Rust 1.88. + +extern crate proc_macro; + +use proc_macro::Span; +use std::path::PathBuf; + +pub fn file(this: &Span) -> String { + this.file() +} + +pub fn local_file(this: &Span) -> Option { + this.local_file() +} diff --git a/rust/proc-macro2/probe/proc_macro_span_location.rs b/rust/proc= -macro2/probe/proc_macro_span_location.rs new file mode 100644 index 000000000000..79da34af54af --- /dev/null +++ b/rust/proc-macro2/probe/proc_macro_span_location.rs @@ -0,0 +1,21 @@ +// The subset of Span's API stabilized in Rust 1.88. + +extern crate proc_macro; + +use proc_macro::Span; + +pub fn start(this: &Span) -> Span { + this.start() +} + +pub fn end(this: &Span) -> Span { + this.end() +} + +pub fn line(this: &Span) -> usize { + this.line() +} + +pub fn column(this: &Span) -> usize { + this.column() +} diff --git a/rust/proc-macro2/rcvec.rs b/rust/proc-macro2/rcvec.rs new file mode 100644 index 000000000000..23edc77d597f --- /dev/null +++ b/rust/proc-macro2/rcvec.rs @@ -0,0 +1,146 @@ +use alloc::rc::Rc; +use alloc::vec; +use core::mem; +use core::panic::RefUnwindSafe; +use core::slice; + +pub(crate) struct RcVec { + inner: Rc>, +} + +pub(crate) struct RcVecBuilder { + inner: Vec, +} + +pub(crate) struct RcVecMut<'a, T> { + inner: &'a mut Vec, +} + +#[derive(Clone)] +pub(crate) struct RcVecIntoIter { + inner: vec::IntoIter, +} + +impl RcVec { + pub(crate) fn is_empty(&self) -> bool { + self.inner.is_empty() + } + + pub(crate) fn len(&self) -> usize { + self.inner.len() + } + + pub(crate) fn iter(&self) -> slice::Iter { + self.inner.iter() + } + + pub(crate) fn make_mut(&mut self) -> RcVecMut + where + T: Clone, + { + RcVecMut { + inner: Rc::make_mut(&mut self.inner), + } + } + + pub(crate) fn get_mut(&mut self) -> Option> { + let inner =3D Rc::get_mut(&mut self.inner)?; + Some(RcVecMut { inner }) + } + + pub(crate) fn make_owned(mut self) -> RcVecBuilder + where + T: Clone, + { + let vec =3D if let Some(owned) =3D Rc::get_mut(&mut self.inner) { + mem::take(owned) + } else { + Vec::clone(&self.inner) + }; + RcVecBuilder { inner: vec } + } +} + +impl RcVecBuilder { + pub(crate) fn new() -> Self { + RcVecBuilder { inner: Vec::new() } + } + + pub(crate) fn with_capacity(cap: usize) -> Self { + RcVecBuilder { + inner: Vec::with_capacity(cap), + } + } + + pub(crate) fn push(&mut self, element: T) { + self.inner.push(element); + } + + pub(crate) fn extend(&mut self, iter: impl IntoIterator) { + self.inner.extend(iter); + } + + pub(crate) fn as_mut(&mut self) -> RcVecMut { + RcVecMut { + inner: &mut self.inner, + } + } + + pub(crate) fn build(self) -> RcVec { + RcVec { + inner: Rc::new(self.inner), + } + } +} + +impl<'a, T> RcVecMut<'a, T> { + pub(crate) fn push(&mut self, element: T) { + self.inner.push(element); + } + + pub(crate) fn extend(&mut self, iter: impl IntoIterator) { + self.inner.extend(iter); + } + + pub(crate) fn as_mut(&mut self) -> RcVecMut { + RcVecMut { inner: self.inner } + } + + pub(crate) fn take(self) -> RcVecBuilder { + let vec =3D mem::take(self.inner); + RcVecBuilder { inner: vec } + } +} + +impl Clone for RcVec { + fn clone(&self) -> Self { + RcVec { + inner: Rc::clone(&self.inner), + } + } +} + +impl IntoIterator for RcVecBuilder { + type Item =3D T; + type IntoIter =3D RcVecIntoIter; + + fn into_iter(self) -> Self::IntoIter { + RcVecIntoIter { + inner: self.inner.into_iter(), + } + } +} + +impl Iterator for RcVecIntoIter { + type Item =3D T; + + fn next(&mut self) -> Option { + self.inner.next() + } + + fn size_hint(&self) -> (usize, Option) { + self.inner.size_hint() + } +} + +impl RefUnwindSafe for RcVec where T: RefUnwindSafe {} diff --git a/rust/proc-macro2/wrapper.rs b/rust/proc-macro2/wrapper.rs new file mode 100644 index 000000000000..2e3eb5b4d04e --- /dev/null +++ b/rust/proc-macro2/wrapper.rs @@ -0,0 +1,984 @@ +use crate::detection::inside_proc_macro; +use crate::fallback::{self, FromStr2 as _}; +#[cfg(span_locations)] +use crate::location::LineColumn; +#[cfg(proc_macro_span)] +use crate::probe::proc_macro_span; +#[cfg(all(span_locations, proc_macro_span_file))] +use crate::probe::proc_macro_span_file; +#[cfg(all(span_locations, proc_macro_span_location))] +use crate::probe::proc_macro_span_location; +use crate::{Delimiter, Punct, Spacing, TokenTree}; +use core::fmt::{self, Debug, Display}; +#[cfg(span_locations)] +use core::ops::Range; +use core::ops::RangeBounds; +use std::ffi::CStr; +#[cfg(span_locations)] +use std::path::PathBuf; + +#[derive(Clone)] +pub(crate) enum TokenStream { + Compiler(DeferredTokenStream), + Fallback(fallback::TokenStream), +} + +// Work around https://github.com/rust-lang/rust/issues/65080. +// In `impl Extend for TokenStream` which is used heavily by qu= ote, +// we hold on to the appended tokens and do proc_macro::TokenStream::exten= d as +// late as possible to batch together consecutive uses of the Extend impl. +#[derive(Clone)] +pub(crate) struct DeferredTokenStream { + stream: proc_macro::TokenStream, + extra: Vec, +} + +pub(crate) enum LexError { + Compiler(proc_macro::LexError), + Fallback(fallback::LexError), + + // Rustc was supposed to return a LexError, but it panicked instead. + // https://github.com/rust-lang/rust/issues/58736 + CompilerPanic, +} + +#[cold] +fn mismatch(line: u32) -> ! { + #[cfg(procmacro2_backtrace)] + { + let backtrace =3D std::backtrace::Backtrace::force_capture(); + panic!("compiler/fallback mismatch L{}\n\n{}", line, backtrace) + } + #[cfg(not(procmacro2_backtrace))] + { + panic!("compiler/fallback mismatch L{}", line) + } +} + +impl DeferredTokenStream { + fn new(stream: proc_macro::TokenStream) -> Self { + DeferredTokenStream { + stream, + extra: Vec::new(), + } + } + + fn is_empty(&self) -> bool { + self.stream.is_empty() && self.extra.is_empty() + } + + fn evaluate_now(&mut self) { + // If-check provides a fast short circuit for the common case of `= extra` + // being empty, which saves a round trip over the proc macro bridg= e. + // Improves macro expansion time in winrt by 6% in debug mode. + if !self.extra.is_empty() { + self.stream.extend(self.extra.drain(..)); + } + } + + fn into_token_stream(mut self) -> proc_macro::TokenStream { + self.evaluate_now(); + self.stream + } +} + +impl TokenStream { + pub(crate) fn new() -> Self { + if inside_proc_macro() { + TokenStream::Compiler(DeferredTokenStream::new(proc_macro::Tok= enStream::new())) + } else { + TokenStream::Fallback(fallback::TokenStream::new()) + } + } + + pub(crate) fn from_str_checked(src: &str) -> Result { + if inside_proc_macro() { + Ok(TokenStream::Compiler(DeferredTokenStream::new( + proc_macro::TokenStream::from_str_checked(src)?, + ))) + } else { + Ok(TokenStream::Fallback( + fallback::TokenStream::from_str_checked(src)?, + )) + } + } + + pub(crate) fn is_empty(&self) -> bool { + match self { + TokenStream::Compiler(tts) =3D> tts.is_empty(), + TokenStream::Fallback(tts) =3D> tts.is_empty(), + } + } + + fn unwrap_nightly(self) -> proc_macro::TokenStream { + match self { + TokenStream::Compiler(s) =3D> s.into_token_stream(), + TokenStream::Fallback(_) =3D> mismatch(line!()), + } + } + + fn unwrap_stable(self) -> fallback::TokenStream { + match self { + TokenStream::Compiler(_) =3D> mismatch(line!()), + TokenStream::Fallback(s) =3D> s, + } + } +} + +impl Display for TokenStream { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + match self { + TokenStream::Compiler(tts) =3D> Display::fmt(&tts.clone().into= _token_stream(), f), + TokenStream::Fallback(tts) =3D> Display::fmt(tts, f), + } + } +} + +impl From for TokenStream { + fn from(inner: proc_macro::TokenStream) -> Self { + TokenStream::Compiler(DeferredTokenStream::new(inner)) + } +} + +impl From for proc_macro::TokenStream { + fn from(inner: TokenStream) -> Self { + match inner { + TokenStream::Compiler(inner) =3D> inner.into_token_stream(), + TokenStream::Fallback(inner) =3D> { + proc_macro::TokenStream::from_str_unchecked(&inner.to_stri= ng()) + } + } + } +} + +impl From for TokenStream { + fn from(inner: fallback::TokenStream) -> Self { + TokenStream::Fallback(inner) + } +} + +// Assumes inside_proc_macro(). +fn into_compiler_token(token: TokenTree) -> proc_macro::TokenTree { + match token { + TokenTree::Group(tt) =3D> proc_macro::TokenTree::Group(tt.inner.un= wrap_nightly()), + TokenTree::Punct(tt) =3D> { + let spacing =3D match tt.spacing() { + Spacing::Joint =3D> proc_macro::Spacing::Joint, + Spacing::Alone =3D> proc_macro::Spacing::Alone, + }; + let mut punct =3D proc_macro::Punct::new(tt.as_char(), spacing= ); + punct.set_span(tt.span().inner.unwrap_nightly()); + proc_macro::TokenTree::Punct(punct) + } + TokenTree::Ident(tt) =3D> proc_macro::TokenTree::Ident(tt.inner.un= wrap_nightly()), + TokenTree::Literal(tt) =3D> proc_macro::TokenTree::Literal(tt.inne= r.unwrap_nightly()), + } +} + +impl From for TokenStream { + fn from(token: TokenTree) -> Self { + if inside_proc_macro() { + TokenStream::Compiler(DeferredTokenStream::new(proc_macro::Tok= enStream::from( + into_compiler_token(token), + ))) + } else { + TokenStream::Fallback(fallback::TokenStream::from(token)) + } + } +} + +impl FromIterator for TokenStream { + fn from_iter>(trees: I) -> Self { + if inside_proc_macro() { + TokenStream::Compiler(DeferredTokenStream::new( + trees.into_iter().map(into_compiler_token).collect(), + )) + } else { + TokenStream::Fallback(trees.into_iter().collect()) + } + } +} + +impl FromIterator for TokenStream { + fn from_iter>(streams: I) -> Sel= f { + let mut streams =3D streams.into_iter(); + match streams.next() { + Some(TokenStream::Compiler(mut first)) =3D> { + first.evaluate_now(); + first.stream.extend(streams.map(|s| match s { + TokenStream::Compiler(s) =3D> s.into_token_stream(), + TokenStream::Fallback(_) =3D> mismatch(line!()), + })); + TokenStream::Compiler(first) + } + Some(TokenStream::Fallback(mut first)) =3D> { + first.extend(streams.map(|s| match s { + TokenStream::Fallback(s) =3D> s, + TokenStream::Compiler(_) =3D> mismatch(line!()), + })); + TokenStream::Fallback(first) + } + None =3D> TokenStream::new(), + } + } +} + +impl Extend for TokenStream { + fn extend>(&mut self, stream: I) { + match self { + TokenStream::Compiler(tts) =3D> { + // Here is the reason for DeferredTokenStream. + for token in stream { + tts.extra.push(into_compiler_token(token)); + } + } + TokenStream::Fallback(tts) =3D> tts.extend(stream), + } + } +} + +impl Extend for TokenStream { + fn extend>(&mut self, streams: I= ) { + match self { + TokenStream::Compiler(tts) =3D> { + tts.evaluate_now(); + tts.stream + .extend(streams.into_iter().map(TokenStream::unwrap_ni= ghtly)); + } + TokenStream::Fallback(tts) =3D> { + tts.extend(streams.into_iter().map(TokenStream::unwrap_sta= ble)); + } + } + } +} + +impl Debug for TokenStream { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + match self { + TokenStream::Compiler(tts) =3D> Debug::fmt(&tts.clone().into_t= oken_stream(), f), + TokenStream::Fallback(tts) =3D> Debug::fmt(tts, f), + } + } +} + +impl LexError { + pub(crate) fn span(&self) -> Span { + match self { + LexError::Compiler(_) | LexError::CompilerPanic =3D> Span::cal= l_site(), + LexError::Fallback(e) =3D> Span::Fallback(e.span()), + } + } +} + +impl From for LexError { + fn from(e: proc_macro::LexError) -> Self { + LexError::Compiler(e) + } +} + +impl From for LexError { + fn from(e: fallback::LexError) -> Self { + LexError::Fallback(e) + } +} + +impl Debug for LexError { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + match self { + LexError::Compiler(e) =3D> Debug::fmt(e, f), + LexError::Fallback(e) =3D> Debug::fmt(e, f), + LexError::CompilerPanic =3D> { + let fallback =3D fallback::LexError::call_site(); + Debug::fmt(&fallback, f) + } + } + } +} + +impl Display for LexError { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + match self { + LexError::Compiler(e) =3D> Display::fmt(e, f), + LexError::Fallback(e) =3D> Display::fmt(e, f), + LexError::CompilerPanic =3D> { + let fallback =3D fallback::LexError::call_site(); + Display::fmt(&fallback, f) + } + } + } +} + +#[derive(Clone)] +pub(crate) enum TokenTreeIter { + Compiler(proc_macro::token_stream::IntoIter), + Fallback(fallback::TokenTreeIter), +} + +impl IntoIterator for TokenStream { + type Item =3D TokenTree; + type IntoIter =3D TokenTreeIter; + + fn into_iter(self) -> TokenTreeIter { + match self { + TokenStream::Compiler(tts) =3D> { + TokenTreeIter::Compiler(tts.into_token_stream().into_iter(= )) + } + TokenStream::Fallback(tts) =3D> TokenTreeIter::Fallback(tts.in= to_iter()), + } + } +} + +impl Iterator for TokenTreeIter { + type Item =3D TokenTree; + + fn next(&mut self) -> Option { + let token =3D match self { + TokenTreeIter::Compiler(iter) =3D> iter.next()?, + TokenTreeIter::Fallback(iter) =3D> return iter.next(), + }; + Some(match token { + proc_macro::TokenTree::Group(tt) =3D> { + TokenTree::Group(crate::Group::_new(Group::Compiler(tt))) + } + proc_macro::TokenTree::Punct(tt) =3D> { + let spacing =3D match tt.spacing() { + proc_macro::Spacing::Joint =3D> Spacing::Joint, + proc_macro::Spacing::Alone =3D> Spacing::Alone, + }; + let mut o =3D Punct::new(tt.as_char(), spacing); + o.set_span(crate::Span::_new(Span::Compiler(tt.span()))); + TokenTree::Punct(o) + } + proc_macro::TokenTree::Ident(s) =3D> { + TokenTree::Ident(crate::Ident::_new(Ident::Compiler(s))) + } + proc_macro::TokenTree::Literal(l) =3D> { + TokenTree::Literal(crate::Literal::_new(Literal::Compiler(= l))) + } + }) + } + + fn size_hint(&self) -> (usize, Option) { + match self { + TokenTreeIter::Compiler(tts) =3D> tts.size_hint(), + TokenTreeIter::Fallback(tts) =3D> tts.size_hint(), + } + } +} + +#[derive(Copy, Clone)] +pub(crate) enum Span { + Compiler(proc_macro::Span), + Fallback(fallback::Span), +} + +impl Span { + pub(crate) fn call_site() -> Self { + if inside_proc_macro() { + Span::Compiler(proc_macro::Span::call_site()) + } else { + Span::Fallback(fallback::Span::call_site()) + } + } + + pub(crate) fn mixed_site() -> Self { + if inside_proc_macro() { + Span::Compiler(proc_macro::Span::mixed_site()) + } else { + Span::Fallback(fallback::Span::mixed_site()) + } + } + + #[cfg(super_unstable)] + pub(crate) fn def_site() -> Self { + if inside_proc_macro() { + Span::Compiler(proc_macro::Span::def_site()) + } else { + Span::Fallback(fallback::Span::def_site()) + } + } + + pub(crate) fn resolved_at(&self, other: Span) -> Span { + match (self, other) { + (Span::Compiler(a), Span::Compiler(b)) =3D> Span::Compiler(a.r= esolved_at(b)), + (Span::Fallback(a), Span::Fallback(b)) =3D> Span::Fallback(a.r= esolved_at(b)), + (Span::Compiler(_), Span::Fallback(_)) =3D> mismatch(line!()), + (Span::Fallback(_), Span::Compiler(_)) =3D> mismatch(line!()), + } + } + + pub(crate) fn located_at(&self, other: Span) -> Span { + match (self, other) { + (Span::Compiler(a), Span::Compiler(b)) =3D> Span::Compiler(a.l= ocated_at(b)), + (Span::Fallback(a), Span::Fallback(b)) =3D> Span::Fallback(a.l= ocated_at(b)), + (Span::Compiler(_), Span::Fallback(_)) =3D> mismatch(line!()), + (Span::Fallback(_), Span::Compiler(_)) =3D> mismatch(line!()), + } + } + + pub(crate) fn unwrap(self) -> proc_macro::Span { + match self { + Span::Compiler(s) =3D> s, + Span::Fallback(_) =3D> panic!("proc_macro::Span is only availa= ble in procedural macros"), + } + } + + #[cfg(span_locations)] + pub(crate) fn byte_range(&self) -> Range { + match self { + #[cfg(proc_macro_span)] + Span::Compiler(s) =3D> proc_macro_span::byte_range(s), + #[cfg(not(proc_macro_span))] + Span::Compiler(_) =3D> 0..0, + Span::Fallback(s) =3D> s.byte_range(), + } + } + + #[cfg(span_locations)] + pub(crate) fn start(&self) -> LineColumn { + match self { + #[cfg(proc_macro_span_location)] + Span::Compiler(s) =3D> LineColumn { + line: proc_macro_span_location::line(s), + column: proc_macro_span_location::column(s).saturating_sub= (1), + }, + #[cfg(not(proc_macro_span_location))] + Span::Compiler(_) =3D> LineColumn { line: 0, column: 0 }, + Span::Fallback(s) =3D> s.start(), + } + } + + #[cfg(span_locations)] + pub(crate) fn end(&self) -> LineColumn { + match self { + #[cfg(proc_macro_span_location)] + Span::Compiler(s) =3D> { + let end =3D proc_macro_span_location::end(s); + LineColumn { + line: proc_macro_span_location::line(&end), + column: proc_macro_span_location::column(&end).saturat= ing_sub(1), + } + } + #[cfg(not(proc_macro_span_location))] + Span::Compiler(_) =3D> LineColumn { line: 0, column: 0 }, + Span::Fallback(s) =3D> s.end(), + } + } + + #[cfg(span_locations)] + pub(crate) fn file(&self) -> String { + match self { + #[cfg(proc_macro_span_file)] + Span::Compiler(s) =3D> proc_macro_span_file::file(s), + #[cfg(not(proc_macro_span_file))] + Span::Compiler(_) =3D> "".to_owned(), + Span::Fallback(s) =3D> s.file(), + } + } + + #[cfg(span_locations)] + pub(crate) fn local_file(&self) -> Option { + match self { + #[cfg(proc_macro_span_file)] + Span::Compiler(s) =3D> proc_macro_span_file::local_file(s), + #[cfg(not(proc_macro_span_file))] + Span::Compiler(_) =3D> None, + Span::Fallback(s) =3D> s.local_file(), + } + } + + pub(crate) fn join(&self, other: Span) -> Option { + let ret =3D match (self, other) { + #[cfg(proc_macro_span)] + (Span::Compiler(a), Span::Compiler(b)) =3D> Span::Compiler(pro= c_macro_span::join(a, b)?), + (Span::Fallback(a), Span::Fallback(b)) =3D> Span::Fallback(a.j= oin(b)?), + _ =3D> return None, + }; + Some(ret) + } + + #[cfg(super_unstable)] + pub(crate) fn eq(&self, other: &Span) -> bool { + match (self, other) { + (Span::Compiler(a), Span::Compiler(b)) =3D> a.eq(b), + (Span::Fallback(a), Span::Fallback(b)) =3D> a.eq(b), + _ =3D> false, + } + } + + pub(crate) fn source_text(&self) -> Option { + match self { + #[cfg(not(no_source_text))] + Span::Compiler(s) =3D> s.source_text(), + #[cfg(no_source_text)] + Span::Compiler(_) =3D> None, + Span::Fallback(s) =3D> s.source_text(), + } + } + + fn unwrap_nightly(self) -> proc_macro::Span { + match self { + Span::Compiler(s) =3D> s, + Span::Fallback(_) =3D> mismatch(line!()), + } + } +} + +impl From for crate::Span { + fn from(proc_span: proc_macro::Span) -> Self { + crate::Span::_new(Span::Compiler(proc_span)) + } +} + +impl From for Span { + fn from(inner: fallback::Span) -> Self { + Span::Fallback(inner) + } +} + +impl Debug for Span { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + match self { + Span::Compiler(s) =3D> Debug::fmt(s, f), + Span::Fallback(s) =3D> Debug::fmt(s, f), + } + } +} + +pub(crate) fn debug_span_field_if_nontrivial(debug: &mut fmt::DebugStruct,= span: Span) { + match span { + Span::Compiler(s) =3D> { + debug.field("span", &s); + } + Span::Fallback(s) =3D> fallback::debug_span_field_if_nontrivial(de= bug, s), + } +} + +#[derive(Clone)] +pub(crate) enum Group { + Compiler(proc_macro::Group), + Fallback(fallback::Group), +} + +impl Group { + pub(crate) fn new(delimiter: Delimiter, stream: TokenStream) -> Self { + match stream { + TokenStream::Compiler(tts) =3D> { + let delimiter =3D match delimiter { + Delimiter::Parenthesis =3D> proc_macro::Delimiter::Par= enthesis, + Delimiter::Bracket =3D> proc_macro::Delimiter::Bracket, + Delimiter::Brace =3D> proc_macro::Delimiter::Brace, + Delimiter::None =3D> proc_macro::Delimiter::None, + }; + Group::Compiler(proc_macro::Group::new(delimiter, tts.into= _token_stream())) + } + TokenStream::Fallback(stream) =3D> { + Group::Fallback(fallback::Group::new(delimiter, stream)) + } + } + } + + pub(crate) fn delimiter(&self) -> Delimiter { + match self { + Group::Compiler(g) =3D> match g.delimiter() { + proc_macro::Delimiter::Parenthesis =3D> Delimiter::Parenth= esis, + proc_macro::Delimiter::Bracket =3D> Delimiter::Bracket, + proc_macro::Delimiter::Brace =3D> Delimiter::Brace, + proc_macro::Delimiter::None =3D> Delimiter::None, + }, + Group::Fallback(g) =3D> g.delimiter(), + } + } + + pub(crate) fn stream(&self) -> TokenStream { + match self { + Group::Compiler(g) =3D> TokenStream::Compiler(DeferredTokenStr= eam::new(g.stream())), + Group::Fallback(g) =3D> TokenStream::Fallback(g.stream()), + } + } + + pub(crate) fn span(&self) -> Span { + match self { + Group::Compiler(g) =3D> Span::Compiler(g.span()), + Group::Fallback(g) =3D> Span::Fallback(g.span()), + } + } + + pub(crate) fn span_open(&self) -> Span { + match self { + Group::Compiler(g) =3D> Span::Compiler(g.span_open()), + Group::Fallback(g) =3D> Span::Fallback(g.span_open()), + } + } + + pub(crate) fn span_close(&self) -> Span { + match self { + Group::Compiler(g) =3D> Span::Compiler(g.span_close()), + Group::Fallback(g) =3D> Span::Fallback(g.span_close()), + } + } + + pub(crate) fn set_span(&mut self, span: Span) { + match (self, span) { + (Group::Compiler(g), Span::Compiler(s)) =3D> g.set_span(s), + (Group::Fallback(g), Span::Fallback(s)) =3D> g.set_span(s), + (Group::Compiler(_), Span::Fallback(_)) =3D> mismatch(line!()), + (Group::Fallback(_), Span::Compiler(_)) =3D> mismatch(line!()), + } + } + + fn unwrap_nightly(self) -> proc_macro::Group { + match self { + Group::Compiler(g) =3D> g, + Group::Fallback(_) =3D> mismatch(line!()), + } + } +} + +impl From for Group { + fn from(g: fallback::Group) -> Self { + Group::Fallback(g) + } +} + +impl Display for Group { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + match self { + Group::Compiler(group) =3D> Display::fmt(group, formatter), + Group::Fallback(group) =3D> Display::fmt(group, formatter), + } + } +} + +impl Debug for Group { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + match self { + Group::Compiler(group) =3D> Debug::fmt(group, formatter), + Group::Fallback(group) =3D> Debug::fmt(group, formatter), + } + } +} + +#[derive(Clone)] +pub(crate) enum Ident { + Compiler(proc_macro::Ident), + Fallback(fallback::Ident), +} + +impl Ident { + #[track_caller] + pub(crate) fn new_checked(string: &str, span: Span) -> Self { + match span { + Span::Compiler(s) =3D> Ident::Compiler(proc_macro::Ident::new(= string, s)), + Span::Fallback(s) =3D> Ident::Fallback(fallback::Ident::new_ch= ecked(string, s)), + } + } + + #[track_caller] + pub(crate) fn new_raw_checked(string: &str, span: Span) -> Self { + match span { + Span::Compiler(s) =3D> Ident::Compiler(proc_macro::Ident::new_= raw(string, s)), + Span::Fallback(s) =3D> Ident::Fallback(fallback::Ident::new_ra= w_checked(string, s)), + } + } + + pub(crate) fn span(&self) -> Span { + match self { + Ident::Compiler(t) =3D> Span::Compiler(t.span()), + Ident::Fallback(t) =3D> Span::Fallback(t.span()), + } + } + + pub(crate) fn set_span(&mut self, span: Span) { + match (self, span) { + (Ident::Compiler(t), Span::Compiler(s)) =3D> t.set_span(s), + (Ident::Fallback(t), Span::Fallback(s)) =3D> t.set_span(s), + (Ident::Compiler(_), Span::Fallback(_)) =3D> mismatch(line!()), + (Ident::Fallback(_), Span::Compiler(_)) =3D> mismatch(line!()), + } + } + + fn unwrap_nightly(self) -> proc_macro::Ident { + match self { + Ident::Compiler(s) =3D> s, + Ident::Fallback(_) =3D> mismatch(line!()), + } + } +} + +impl From for Ident { + fn from(inner: fallback::Ident) -> Self { + Ident::Fallback(inner) + } +} + +impl PartialEq for Ident { + fn eq(&self, other: &Ident) -> bool { + match (self, other) { + (Ident::Compiler(t), Ident::Compiler(o)) =3D> t.to_string() = =3D=3D o.to_string(), + (Ident::Fallback(t), Ident::Fallback(o)) =3D> t =3D=3D o, + (Ident::Compiler(_), Ident::Fallback(_)) =3D> mismatch(line!()= ), + (Ident::Fallback(_), Ident::Compiler(_)) =3D> mismatch(line!()= ), + } + } +} + +impl PartialEq for Ident +where + T: ?Sized + AsRef, +{ + fn eq(&self, other: &T) -> bool { + let other =3D other.as_ref(); + match self { + Ident::Compiler(t) =3D> t.to_string() =3D=3D other, + Ident::Fallback(t) =3D> t =3D=3D other, + } + } +} + +impl Display for Ident { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + match self { + Ident::Compiler(t) =3D> Display::fmt(t, f), + Ident::Fallback(t) =3D> Display::fmt(t, f), + } + } +} + +impl Debug for Ident { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + match self { + Ident::Compiler(t) =3D> Debug::fmt(t, f), + Ident::Fallback(t) =3D> Debug::fmt(t, f), + } + } +} + +#[derive(Clone)] +pub(crate) enum Literal { + Compiler(proc_macro::Literal), + Fallback(fallback::Literal), +} + +macro_rules! suffixed_numbers { + ($($name:ident =3D> $kind:ident,)*) =3D> ($( + pub(crate) fn $name(n: $kind) -> Literal { + if inside_proc_macro() { + Literal::Compiler(proc_macro::Literal::$name(n)) + } else { + Literal::Fallback(fallback::Literal::$name(n)) + } + } + )*) +} + +macro_rules! unsuffixed_integers { + ($($name:ident =3D> $kind:ident,)*) =3D> ($( + pub(crate) fn $name(n: $kind) -> Literal { + if inside_proc_macro() { + Literal::Compiler(proc_macro::Literal::$name(n)) + } else { + Literal::Fallback(fallback::Literal::$name(n)) + } + } + )*) +} + +impl Literal { + pub(crate) fn from_str_checked(repr: &str) -> Result { + if inside_proc_macro() { + let literal =3D proc_macro::Literal::from_str_checked(repr)?; + Ok(Literal::Compiler(literal)) + } else { + let literal =3D fallback::Literal::from_str_checked(repr)?; + Ok(Literal::Fallback(literal)) + } + } + + pub(crate) unsafe fn from_str_unchecked(repr: &str) -> Self { + if inside_proc_macro() { + Literal::Compiler(proc_macro::Literal::from_str_unchecked(repr= )) + } else { + Literal::Fallback(unsafe { fallback::Literal::from_str_uncheck= ed(repr) }) + } + } + + suffixed_numbers! { + u8_suffixed =3D> u8, + u16_suffixed =3D> u16, + u32_suffixed =3D> u32, + u64_suffixed =3D> u64, + u128_suffixed =3D> u128, + usize_suffixed =3D> usize, + i8_suffixed =3D> i8, + i16_suffixed =3D> i16, + i32_suffixed =3D> i32, + i64_suffixed =3D> i64, + i128_suffixed =3D> i128, + isize_suffixed =3D> isize, + + f32_suffixed =3D> f32, + f64_suffixed =3D> f64, + } + + unsuffixed_integers! { + u8_unsuffixed =3D> u8, + u16_unsuffixed =3D> u16, + u32_unsuffixed =3D> u32, + u64_unsuffixed =3D> u64, + u128_unsuffixed =3D> u128, + usize_unsuffixed =3D> usize, + i8_unsuffixed =3D> i8, + i16_unsuffixed =3D> i16, + i32_unsuffixed =3D> i32, + i64_unsuffixed =3D> i64, + i128_unsuffixed =3D> i128, + isize_unsuffixed =3D> isize, + } + + pub(crate) fn f32_unsuffixed(f: f32) -> Literal { + if inside_proc_macro() { + Literal::Compiler(proc_macro::Literal::f32_unsuffixed(f)) + } else { + Literal::Fallback(fallback::Literal::f32_unsuffixed(f)) + } + } + + pub(crate) fn f64_unsuffixed(f: f64) -> Literal { + if inside_proc_macro() { + Literal::Compiler(proc_macro::Literal::f64_unsuffixed(f)) + } else { + Literal::Fallback(fallback::Literal::f64_unsuffixed(f)) + } + } + + pub(crate) fn string(string: &str) -> Literal { + if inside_proc_macro() { + Literal::Compiler(proc_macro::Literal::string(string)) + } else { + Literal::Fallback(fallback::Literal::string(string)) + } + } + + pub(crate) fn character(ch: char) -> Literal { + if inside_proc_macro() { + Literal::Compiler(proc_macro::Literal::character(ch)) + } else { + Literal::Fallback(fallback::Literal::character(ch)) + } + } + + pub(crate) 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 =3D fallback::Literal::byte_character(byt= e); + proc_macro::Literal::from_str_unchecked(&fallback.repr) + } + }) + } else { + Literal::Fallback(fallback::Literal::byte_character(byte)) + } + } + + pub(crate) fn byte_string(bytes: &[u8]) -> Literal { + if inside_proc_macro() { + Literal::Compiler(proc_macro::Literal::byte_string(bytes)) + } else { + Literal::Fallback(fallback::Literal::byte_string(bytes)) + } + } + + pub(crate) 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 =3D fallback::Literal::c_string(string); + proc_macro::Literal::from_str_unchecked(&fallback.repr) + } + }) + } else { + Literal::Fallback(fallback::Literal::c_string(string)) + } + } + + pub(crate) fn span(&self) -> Span { + match self { + Literal::Compiler(lit) =3D> Span::Compiler(lit.span()), + Literal::Fallback(lit) =3D> Span::Fallback(lit.span()), + } + } + + pub(crate) fn set_span(&mut self, span: Span) { + match (self, span) { + (Literal::Compiler(lit), Span::Compiler(s)) =3D> lit.set_span(= s), + (Literal::Fallback(lit), Span::Fallback(s)) =3D> lit.set_span(= s), + (Literal::Compiler(_), Span::Fallback(_)) =3D> mismatch(line!(= )), + (Literal::Fallback(_), Span::Compiler(_)) =3D> mismatch(line!(= )), + } + } + + pub(crate) fn subspan>(&self, range: R) -> Optio= n { + match self { + #[cfg(proc_macro_span)] + Literal::Compiler(lit) =3D> proc_macro_span::subspan(lit, rang= e).map(Span::Compiler), + #[cfg(not(proc_macro_span))] + Literal::Compiler(_lit) =3D> None, + Literal::Fallback(lit) =3D> lit.subspan(range).map(Span::Fallb= ack), + } + } + + fn unwrap_nightly(self) -> proc_macro::Literal { + match self { + Literal::Compiler(s) =3D> s, + Literal::Fallback(_) =3D> mismatch(line!()), + } + } +} + +impl From for Literal { + fn from(s: fallback::Literal) -> Self { + Literal::Fallback(s) + } +} + +impl Display for Literal { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + match self { + Literal::Compiler(t) =3D> Display::fmt(t, f), + Literal::Fallback(t) =3D> Display::fmt(t, f), + } + } +} + +impl Debug for Literal { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + match self { + Literal::Compiler(t) =3D> Debug::fmt(t, f), + Literal::Fallback(t) =3D> Debug::fmt(t, f), + } + } +} + +#[cfg(span_locations)] +pub(crate) fn invalidate_current_thread_spans() { + if inside_proc_macro() { + panic!( + "proc_macro2::extra::invalidate_current_thread_spans is not av= ailable in procedural macros" + ); + } else { + crate::fallback::invalidate_current_thread_spans(); + } +} --=20 2.52.0