Snap for 7550930 from 5bba24088af19dfc9b313ed9bd8ae15c16a35b60 to mainline-captiveportallogin-release

Change-Id: I2208c83dba3be85e0659811df827248dc95ebc3e
diff --git a/.cargo_vcs_info.json b/.cargo_vcs_info.json
index c5b6105..e15e24e 100644
--- a/.cargo_vcs_info.json
+++ b/.cargo_vcs_info.json
@@ -1,5 +1,5 @@
 {
   "git": {
-    "sha1": "727436c6c137b20f0f34dde5d8fda2679b9747ad"
+    "sha1": "68ebadbc1b4242531c5a78fbba01c648bd58c8e7"
   }
 }
diff --git a/Android.bp b/Android.bp
index 2a3cb09..c894868 100644
--- a/Android.bp
+++ b/Android.bp
@@ -1,6 +1,42 @@
-// This file is generated by cargo2android.py.
+// This file is generated by cargo2android.py --run --dependencies --host-first-multilib.
 
-rust_library_host_rlib {
+package {
+    default_applicable_licenses: ["external_rust_crates_quote_license"],
+}
+
+// Added automatically by a large-scale-change that took the approach of
+// 'apply every license found to every target'. While this makes sure we respect
+// every license restriction, it may not be entirely correct.
+//
+// e.g. GPL in an MIT project might only apply to the contrib/ directory.
+//
+// Please consider splitting the single license below into multiple licenses,
+// taking care not to lose any license_kind information, and overriding the
+// default license using the 'licenses: [...]' property on targets as needed.
+//
+// For unused files, consider creating a 'fileGroup' with "//visibility:private"
+// to attach the license to, and including a comment whether the files may be
+// used in the current project.
+//
+// large-scale-change included anything that looked like it might be a license
+// text as a license_text. e.g. LICENSE, NOTICE, COPYING etc.
+//
+// Please consider removing redundant or irrelevant files from 'license_text:'.
+// See: http://go/android-license-faq
+license {
+    name: "external_rust_crates_quote_license",
+    visibility: [":__subpackages__"],
+    license_kinds: [
+        "SPDX-license-identifier-Apache-2.0",
+        "SPDX-license-identifier-MIT",
+    ],
+    license_text: [
+        "LICENSE-APACHE",
+        "LICENSE-MIT",
+    ],
+}
+
+rust_library_host {
     name: "libquote",
     crate_name: "quote",
     srcs: ["src/lib.rs"],
@@ -9,7 +45,12 @@
         "default",
         "proc-macro",
     ],
-    rlibs: [
+    rustlibs: [
         "libproc_macro2",
     ],
+    compile_multilib: "first",
 }
+
+// dependent_library ["feature_list"]
+//   proc-macro2-1.0.24 "default,proc-macro"
+//   unicode-xid-0.2.1 "default"
diff --git a/Cargo.toml b/Cargo.toml
index a7a956d..411f943 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -13,7 +13,7 @@
 [package]
 edition = "2018"
 name = "quote"
-version = "1.0.2"
+version = "1.0.9"
 authors = ["David Tolnay <dtolnay@gmail.com>"]
 include = ["Cargo.toml", "src/**/*.rs", "tests/**/*.rs", "README.md", "LICENSE-APACHE", "LICENSE-MIT"]
 description = "Quasi-quoting macro quote!(...)"
@@ -23,20 +23,18 @@
 categories = ["development-tools::procedural-macro-helpers"]
 license = "MIT OR Apache-2.0"
 repository = "https://github.com/dtolnay/quote"
-
-[lib]
-name = "quote"
+[package.metadata.docs.rs]
+targets = ["x86_64-unknown-linux-gnu"]
 [dependencies.proc-macro2]
-version = "1.0"
+version = "1.0.20"
 default-features = false
 [dev-dependencies.rustversion]
-version = "0.1"
+version = "1.0"
 
 [dev-dependencies.trybuild]
-version = "1.0"
+version = "1.0.19"
+features = ["diff"]
 
 [features]
 default = ["proc-macro"]
 proc-macro = ["proc-macro2/proc-macro"]
-[badges.travis-ci]
-repository = "dtolnay/quote"
diff --git a/Cargo.toml.orig b/Cargo.toml.orig
index c052022..b95c6c5 100644
--- a/Cargo.toml.orig
+++ b/Cargo.toml.orig
@@ -1,6 +1,6 @@
 [package]
 name = "quote"
-version = "1.0.2" # don't forget to update html_root_url, version in readme for breaking changes
+version = "1.0.9" # don't forget to update html_root_url, version in readme for breaking changes
 authors = ["David Tolnay <dtolnay@gmail.com>"]
 license = "MIT OR Apache-2.0"
 description = "Quasi-quoting macro quote!(...)"
@@ -12,15 +12,12 @@
 include = ["Cargo.toml", "src/**/*.rs", "tests/**/*.rs", "README.md", "LICENSE-APACHE", "LICENSE-MIT"]
 edition = "2018"
 
-[lib]
-name = "quote"
-
 [dependencies]
-proc-macro2 = { version = "1.0", default-features = false }
+proc-macro2 = { version = "1.0.20", default-features = false }
 
 [dev-dependencies]
-rustversion = "0.1"
-trybuild = "1.0"
+rustversion = "1.0"
+trybuild = { version = "1.0.19", features = ["diff"] }
 
 [features]
 default = ["proc-macro"]
@@ -28,5 +25,5 @@
 # libproc_macro in the rustc compiler.
 proc-macro = ["proc-macro2/proc-macro"]
 
-[badges]
-travis-ci = { repository = "dtolnay/quote" }
+[package.metadata.docs.rs]
+targets = ["x86_64-unknown-linux-gnu"]
diff --git a/LICENSE b/LICENSE
new file mode 120000
index 0000000..6b579aa
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1 @@
+LICENSE-APACHE
\ No newline at end of file
diff --git a/METADATA b/METADATA
new file mode 100644
index 0000000..ee587f2
--- /dev/null
+++ b/METADATA
@@ -0,0 +1,19 @@
+name: "quote"
+description: "Quasi-quoting macro quote!(...)"
+third_party {
+  url {
+    type: HOMEPAGE
+    value: "https://crates.io/crates/quote"
+  }
+  url {
+    type: ARCHIVE
+    value: "https://static.crates.io/crates/quote/quote-1.0.9.crate"
+  }
+  version: "1.0.9"
+  license_type: NOTICE
+  last_upgrade_date {
+    year: 2021
+    month: 2
+    day: 12
+  }
+}
diff --git a/MODULE_LICENSE_APACHE2 b/MODULE_LICENSE_APACHE2
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/MODULE_LICENSE_APACHE2
diff --git a/OWNERS b/OWNERS
new file mode 100644
index 0000000..46fc303
--- /dev/null
+++ b/OWNERS
@@ -0,0 +1 @@
+include platform/prebuilts/rust:/OWNERS
diff --git a/README.md b/README.md
index 7c7f743..57b2a62 100644
--- a/README.md
+++ b/README.md
@@ -1,9 +1,10 @@
 Rust Quasi-Quoting
 ==================
 
-[![Build Status](https://api.travis-ci.org/dtolnay/quote.svg?branch=master)](https://travis-ci.org/dtolnay/quote)
-[![Latest Version](https://img.shields.io/crates/v/quote.svg)](https://crates.io/crates/quote)
-[![Rust Documentation](https://img.shields.io/badge/api-rustdoc-blue.svg)](https://docs.rs/quote/)
+[<img alt="github" src="https://img.shields.io/badge/github-dtolnay/quote-8da0cb?style=for-the-badge&labelColor=555555&logo=github" height="20">](https://github.com/dtolnay/quote)
+[<img alt="crates.io" src="https://img.shields.io/crates/v/quote.svg?style=for-the-badge&color=fc8d62&logo=rust" height="20">](https://crates.io/crates/quote)
+[<img alt="docs.rs" src="https://img.shields.io/badge/docs.rs-quote-66c2a5?style=for-the-badge&labelColor=555555&logoColor=white&logo=data:image/svg+xml;base64,PHN2ZyByb2xlPSJpbWciIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgdmlld0JveD0iMCAwIDUxMiA1MTIiPjxwYXRoIGZpbGw9IiNmNWY1ZjUiIGQ9Ik00ODguNiAyNTAuMkwzOTIgMjE0VjEwNS41YzAtMTUtOS4zLTI4LjQtMjMuNC0zMy43bC0xMDAtMzcuNWMtOC4xLTMuMS0xNy4xLTMuMS0yNS4zIDBsLTEwMCAzNy41Yy0xNC4xIDUuMy0yMy40IDE4LjctMjMuNCAzMy43VjIxNGwtOTYuNiAzNi4yQzkuMyAyNTUuNSAwIDI2OC45IDAgMjgzLjlWMzk0YzAgMTMuNiA3LjcgMjYuMSAxOS45IDMyLjJsMTAwIDUwYzEwLjEgNS4xIDIyLjEgNS4xIDMyLjIgMGwxMDMuOS01MiAxMDMuOSA1MmMxMC4xIDUuMSAyMi4xIDUuMSAzMi4yIDBsMTAwLTUwYzEyLjItNi4xIDE5LjktMTguNiAxOS45LTMyLjJWMjgzLjljMC0xNS05LjMtMjguNC0yMy40LTMzLjd6TTM1OCAyMTQuOGwtODUgMzEuOXYtNjguMmw4NS0zN3Y3My4zek0xNTQgMTA0LjFsMTAyLTM4LjIgMTAyIDM4LjJ2LjZsLTEwMiA0MS40LTEwMi00MS40di0uNnptODQgMjkxLjFsLTg1IDQyLjV2LTc5LjFsODUtMzguOHY3NS40em0wLTExMmwtMTAyIDQxLjQtMTAyLTQxLjR2LS42bDEwMi0zOC4yIDEwMiAzOC4ydi42em0yNDAgMTEybC04NSA0Mi41di03OS4xbDg1LTM4Ljh2NzUuNHptMC0xMTJsLTEwMiA0MS40LTEwMi00MS40di0uNmwxMDItMzguMiAxMDIgMzguMnYuNnoiPjwvcGF0aD48L3N2Zz4K" height="20">](https://docs.rs/quote)
+[<img alt="build status" src="https://img.shields.io/github/workflow/status/dtolnay/quote/CI/master?style=for-the-badge" height="20">](https://github.com/dtolnay/quote/actions?query=branch%3Amaster)
 
 This crate provides the [`quote!`] macro for turning Rust syntax tree data
 structures into tokens of source code.
@@ -28,16 +29,16 @@
 general-purpose Rust quasi-quoting library and is not specific to procedural
 macros.
 
-*Version requirement: Quote supports any compiler version back to Rust's very
-first support for procedural macros in Rust 1.15.0.*
-
-[*Release notes*](https://github.com/dtolnay/quote/releases)
-
 ```toml
 [dependencies]
 quote = "1.0"
 ```
 
+*Version requirement: Quote supports rustc 1.31 and up.*<br>
+[*Release notes*](https://github.com/dtolnay/quote/releases)
+
+<br>
+
 ## Syntax
 
 The quote crate provides a [`quote!`] macro within which you can write Rust code
@@ -76,6 +77,8 @@
 };
 ```
 
+<br>
+
 ## Repetition
 
 Repetition is done using `#(...)*` or `#(...),*` similar to `macro_rules!`. This
@@ -93,6 +96,8 @@
 does not produce a trailing comma. This matches the behavior of delimiters in
 `macro_rules!`.
 
+<br>
+
 ## Returning tokens to the compiler
 
 The `quote!` macro evaluates to an expression of type
@@ -112,6 +117,8 @@
 
 [`From`]: https://doc.rust-lang.org/std/convert/trait.From.html
 
+<br>
+
 ## Examples
 
 ### Combining quoted fragments
@@ -206,6 +213,8 @@
 }
 ```
 
+<br>
+
 ## Hygiene
 
 Any interpolated tokens preserve the `Span` information provided by their
@@ -221,6 +230,21 @@
 
 <br>
 
+## Non-macro code generators
+
+When using `quote` in a build.rs or main.rs and writing the output out to a
+file, consider having the code generator pass the tokens through [rustfmt]
+before writing (either by shelling out to the `rustfmt` binary or by pulling in
+the `rustfmt` library as a dependency). This way if an error occurs in the
+generated code it is convenient for a human to read and debug.
+
+Be aware that no kind of hygiene or span information is retained when tokens are
+written to a file; the conversion from tokens to source code is lossy.
+
+[rustfmt]: https://github.com/rust-lang/rustfmt
+
+<br>
+
 #### License
 
 <sup>
diff --git a/TEST_MAPPING b/TEST_MAPPING
new file mode 100644
index 0000000..a1620b5
--- /dev/null
+++ b/TEST_MAPPING
@@ -0,0 +1,68 @@
+// Generated by update_crate_tests.py for tests that depend on this crate.
+{
+  "presubmit": [
+    {
+      "name": "url_device_test_src_lib"
+    },
+    {
+      "name": "anyhow_device_test_tests_test_downcast"
+    },
+    {
+      "name": "anyhow_device_test_tests_test_repr"
+    },
+    {
+      "name": "keystore2_selinux_test"
+    },
+    {
+      "name": "anyhow_device_test_tests_test_fmt"
+    },
+    {
+      "name": "libm_device_test_src_lib"
+    },
+    {
+      "name": "anyhow_device_test_tests_test_convert"
+    },
+    {
+      "name": "libsqlite3-sys_device_test_src_lib"
+    },
+    {
+      "name": "anyhow_device_test_tests_test_source"
+    },
+    {
+      "name": "unicode-bidi_device_test_src_lib"
+    },
+    {
+      "name": "anyhow_device_test_src_lib"
+    },
+    {
+      "name": "anyhow_device_test_tests_test_autotrait"
+    },
+    {
+      "name": "anyhow_device_test_tests_test_context"
+    },
+    {
+      "name": "anyhow_device_test_tests_test_macros"
+    },
+    {
+      "name": "anyhow_device_test_tests_test_chain"
+    },
+    {
+      "name": "anyhow_device_test_tests_test_ffi"
+    },
+    {
+      "name": "serde_test_device_test_src_lib"
+    },
+    {
+      "name": "futures-util_device_test_src_lib"
+    },
+    {
+      "name": "keystore2_test"
+    },
+    {
+      "name": "anyhow_device_test_tests_test_boxed"
+    },
+    {
+      "name": "keystore2_crypto_test_rust"
+    }
+  ]
+}
diff --git a/src/format.rs b/src/format.rs
index 13c8811..745cb5d 100644
--- a/src/format.rs
+++ b/src/format.rs
@@ -128,7 +128,7 @@
 macro_rules! format_ident_impl {
     // Final state
     ([$span:expr, $($fmt:tt)*]) => {
-        $crate::__rt::mk_ident(&format!($($fmt)*), $span)
+        $crate::__private::mk_ident(&format!($($fmt)*), $span)
     };
 
     // Span argument
@@ -137,7 +137,7 @@
     };
     ([$old:expr, $($fmt:tt)*] span = $span:expr, $($rest:tt)*) => {
         $crate::format_ident_impl!([
-            ::std::option::Option::Some::<$crate::__rt::Span>($span),
+            ::std::option::Option::Some::<$crate::__private::Span>($span),
             $($fmt)*
         ] $($rest)*)
     };
@@ -147,7 +147,7 @@
         $crate::format_ident_impl!([$span, $($fmt)*] $name = $arg,)
     };
     ([$span:expr, $($fmt:tt)*] $name:ident = $arg:expr, $($rest:tt)*) => {
-        match $crate::__rt::IdentFragmentAdapter(&$arg) {
+        match $crate::__private::IdentFragmentAdapter(&$arg) {
             arg => $crate::format_ident_impl!([$span.or(arg.span()), $($fmt)*, $name = arg] $($rest)*),
         }
     };
@@ -157,7 +157,7 @@
         $crate::format_ident_impl!([$span, $($fmt)*] $arg,)
     };
     ([$span:expr, $($fmt:tt)*] $arg:expr, $($rest:tt)*) => {
-        match $crate::__rt::IdentFragmentAdapter(&$arg) {
+        match $crate::__private::IdentFragmentAdapter(&$arg) {
             arg => $crate::format_ident_impl!([$span.or(arg.span()), $($fmt)*, arg] $($rest)*),
         }
     };
diff --git a/src/ident_fragment.rs b/src/ident_fragment.rs
index 09ead65..e7472fe 100644
--- a/src/ident_fragment.rs
+++ b/src/ident_fragment.rs
@@ -1,4 +1,5 @@
 use proc_macro2::{Ident, Span};
+use std::borrow::Cow;
 use std::fmt;
 
 /// Specialized formatting trait used by `format_ident!`.
@@ -19,7 +20,7 @@
     }
 }
 
-impl<'a, T: IdentFragment + ?Sized> IdentFragment for &'a T {
+impl<T: IdentFragment + ?Sized> IdentFragment for &T {
     fn span(&self) -> Option<Span> {
         <T as IdentFragment>::span(*self)
     }
@@ -29,7 +30,7 @@
     }
 }
 
-impl<'a, T: IdentFragment + ?Sized> IdentFragment for &'a mut T {
+impl<T: IdentFragment + ?Sized> IdentFragment for &mut T {
     fn span(&self) -> Option<Span> {
         <T as IdentFragment>::span(*self)
     }
@@ -54,6 +55,19 @@
     }
 }
 
+impl<T> IdentFragment for Cow<'_, T>
+where
+    T: IdentFragment + ToOwned + ?Sized,
+{
+    fn span(&self) -> Option<Span> {
+        T::span(self)
+    }
+
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        T::fmt(self, f)
+    }
+}
+
 // Limited set of types which this is implemented for, as we want to avoid types
 // which will often include non-identifier characters in their `Display` impl.
 macro_rules! ident_fragment_display {
@@ -68,5 +82,5 @@
     }
 }
 
-ident_fragment_display!(bool, str, String);
+ident_fragment_display!(bool, str, String, char);
 ident_fragment_display!(u8, u16, u32, u64, u128, usize);
diff --git a/src/lib.rs b/src/lib.rs
index 3341a16..356e43a 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -1,3 +1,11 @@
+//! [![github]](https://github.com/dtolnay/quote)&ensp;[![crates-io]](https://crates.io/crates/quote)&ensp;[![docs-rs]](https://docs.rs/quote)
+//!
+//! [github]: https://img.shields.io/badge/github-8da0cb?style=for-the-badge&labelColor=555555&logo=github
+//! [crates-io]: https://img.shields.io/badge/crates.io-fc8d62?style=for-the-badge&labelColor=555555&logo=rust
+//! [docs-rs]: https://img.shields.io/badge/docs.rs-66c2a5?style=for-the-badge&labelColor=555555&logoColor=white&logo=data:image/svg+xml;base64,PHN2ZyByb2xlPSJpbWciIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgdmlld0JveD0iMCAwIDUxMiA1MTIiPjxwYXRoIGZpbGw9IiNmNWY1ZjUiIGQ9Ik00ODguNiAyNTAuMkwzOTIgMjE0VjEwNS41YzAtMTUtOS4zLTI4LjQtMjMuNC0zMy43bC0xMDAtMzcuNWMtOC4xLTMuMS0xNy4xLTMuMS0yNS4zIDBsLTEwMCAzNy41Yy0xNC4xIDUuMy0yMy40IDE4LjctMjMuNCAzMy43VjIxNGwtOTYuNiAzNi4yQzkuMyAyNTUuNSAwIDI2OC45IDAgMjgzLjlWMzk0YzAgMTMuNiA3LjcgMjYuMSAxOS45IDMyLjJsMTAwIDUwYzEwLjEgNS4xIDIyLjEgNS4xIDMyLjIgMGwxMDMuOS01MiAxMDMuOSA1MmMxMC4xIDUuMSAyMi4xIDUuMSAzMi4yIDBsMTAwLTUwYzEyLjItNi4xIDE5LjktMTguNiAxOS45LTMyLjJWMjgzLjljMC0xNS05LjMtMjguNC0yMy40LTMzLjd6TTM1OCAyMTQuOGwtODUgMzEuOXYtNjguMmw4NS0zN3Y3My4zek0xNTQgMTA0LjFsMTAyLTM4LjIgMTAyIDM4LjJ2LjZsLTEwMiA0MS40LTEwMi00MS40di0uNnptODQgMjkxLjFsLTg1IDQyLjV2LTc5LjFsODUtMzguOHY3NS40em0wLTExMmwtMTAyIDQxLjQtMTAyLTQxLjR2LS42bDEwMi0zOC4yIDEwMiAzOC4ydi42em0yNDAgMTEybC04NSA0Mi41di03OS4xbDg1LTM4Ljh2NzUuNHptMC0xMTJsLTEwMiA0MS40LTEwMi00MS40di0uNmwxMDItMzguMiAxMDIgMzguMnYuNnoiPjwvcGF0aD48L3N2Zz4K
+//!
+//! <br>
+//!
 //! This crate provides the [`quote!`] macro for turning Rust syntax tree data
 //! structures into tokens of source code.
 //!
@@ -73,7 +81,13 @@
 //! ```
 
 // Quote types in rustdoc of other crates get linked to here.
-#![doc(html_root_url = "https://docs.rs/quote/1.0.2")]
+#![doc(html_root_url = "https://docs.rs/quote/1.0.9")]
+#![allow(
+    clippy::doc_markdown,
+    clippy::missing_errors_doc,
+    clippy::missing_panics_doc,
+    clippy::module_name_repetitions
+)]
 
 #[cfg(all(
     not(all(target_arch = "wasm32", target_os = "unknown")),
@@ -89,7 +103,7 @@
 // Not public API.
 #[doc(hidden)]
 #[path = "runtime.rs"]
-pub mod __rt;
+pub mod __private;
 
 pub use crate::ext::TokenStreamExt;
 pub use crate::ident_fragment::IdentFragment;
@@ -462,9 +476,14 @@
 /// ```
 #[macro_export]
 macro_rules! quote {
-    ($($tt:tt)*) => {
-        $crate::quote_spanned!($crate::__rt::Span::call_site()=> $($tt)*)
+    () => {
+        $crate::__private::TokenStream::new()
     };
+    ($($tt:tt)*) => {{
+        let mut _s = $crate::__private::TokenStream::new();
+        $crate::quote_each_token!(_s $($tt)*);
+        _s
+    }};
 }
 
 /// Same as `quote!`, but applies a given span to all tokens originating within
@@ -550,7 +569,7 @@
 /// ```
 ///
 /// If the assertion fails, the user will see an error like the following. The
-/// input span of their type is hightlighted in the error.
+/// input span of their type is highlighted in the error.
 ///
 /// ```text
 /// error[E0277]: the trait bound `*const (): std::marker::Sync` is not satisfied
@@ -565,10 +584,14 @@
 /// placed appropriately by the compiler.
 #[macro_export]
 macro_rules! quote_spanned {
+    ($span:expr=>) => {{
+        let _: $crate::__private::Span = $span;
+        $crate::__private::TokenStream::new()
+    }};
     ($span:expr=> $($tt:tt)*) => {{
-        let mut _s = $crate::__rt::TokenStream::new();
-        let _span: $crate::__rt::Span = $span;
-        $crate::quote_each_token!(_s _span $($tt)*);
+        let mut _s = $crate::__private::TokenStream::new();
+        let _span: $crate::__private::Span = $span;
+        $crate::quote_each_token_spanned!(_s _span $($tt)*);
         _s
     }};
 }
@@ -638,7 +661,7 @@
 macro_rules! quote_bind_next_or_break {
     ($var:ident) => {
         let $var = match $var.next() {
-            Some(_x) => $crate::__rt::RepInterp(_x),
+            Some(_x) => $crate::__private::RepInterp(_x),
             None => break,
         };
     };
@@ -647,8 +670,24 @@
 #[macro_export]
 #[doc(hidden)]
 macro_rules! quote_each_token {
+    ($tokens:ident $($tts:tt)*) => {
+        $crate::quote_tokens_with_context!($tokens
+            (@ @ @ @ @ @ $($tts)*)
+            (@ @ @ @ @ $($tts)* @)
+            (@ @ @ @ $($tts)* @ @)
+            (@ @ @ $(($tts))* @ @ @)
+            (@ @ $($tts)* @ @ @ @)
+            (@ $($tts)* @ @ @ @ @)
+            ($($tts)* @ @ @ @ @ @)
+        );
+    };
+}
+
+#[macro_export]
+#[doc(hidden)]
+macro_rules! quote_each_token_spanned {
     ($tokens:ident $span:ident $($tts:tt)*) => {
-        $crate::quote_tokens_with_context!($tokens $span
+        $crate::quote_tokens_with_context_spanned!($tokens $span
             (@ @ @ @ @ @ $($tts)*)
             (@ @ @ @ @ $($tts)* @)
             (@ @ @ @ $($tts)* @ @)
@@ -663,13 +702,27 @@
 #[macro_export]
 #[doc(hidden)]
 macro_rules! quote_tokens_with_context {
+    ($tokens:ident
+        ($($b3:tt)*) ($($b2:tt)*) ($($b1:tt)*)
+        ($($curr:tt)*)
+        ($($a1:tt)*) ($($a2:tt)*) ($($a3:tt)*)
+    ) => {
+        $(
+            $crate::quote_token_with_context!($tokens $b3 $b2 $b1 $curr $a1 $a2 $a3);
+        )*
+    };
+}
+
+#[macro_export]
+#[doc(hidden)]
+macro_rules! quote_tokens_with_context_spanned {
     ($tokens:ident $span:ident
         ($($b3:tt)*) ($($b2:tt)*) ($($b1:tt)*)
         ($($curr:tt)*)
         ($($a1:tt)*) ($($a2:tt)*) ($($a3:tt)*)
     ) => {
         $(
-            $crate::quote_token_with_context!($tokens $span $b3 $b2 $b1 $curr $a1 $a2 $a3);
+            $crate::quote_token_with_context_spanned!($tokens $span $b3 $b2 $b1 $curr $a1 $a2 $a3);
         )*
     };
 }
@@ -677,13 +730,13 @@
 #[macro_export]
 #[doc(hidden)]
 macro_rules! quote_token_with_context {
-    ($tokens:ident $span:ident $b3:tt $b2:tt $b1:tt @ $a1:tt $a2:tt $a3:tt) => {};
+    ($tokens:ident $b3:tt $b2:tt $b1:tt @ $a1:tt $a2:tt $a3:tt) => {};
 
-    ($tokens:ident $span:ident $b3:tt $b2:tt $b1:tt (#) ( $($inner:tt)* ) * $a3:tt) => {{
-        use $crate::__rt::ext::*;
-        let has_iter = $crate::__rt::ThereIsNoIteratorInRepetition;
+    ($tokens:ident $b3:tt $b2:tt $b1:tt (#) ( $($inner:tt)* ) * $a3:tt) => {{
+        use $crate::__private::ext::*;
+        let has_iter = $crate::__private::ThereIsNoIteratorInRepetition;
         $crate::pounded_var_names!(quote_bind_into_iter!(has_iter) () $($inner)*);
-        let _: $crate::__rt::HasIterator = has_iter;
+        let _: $crate::__private::HasIterator = has_iter;
         // This is `while true` instead of `loop` because if there are no
         // iterators used inside of this repetition then the body would not
         // contain any `break`, so the compiler would emit unreachable code
@@ -692,32 +745,88 @@
         // around the unneeded extra warning.
         while true {
             $crate::pounded_var_names!(quote_bind_next_or_break!() () $($inner)*);
-            $crate::quote_each_token!($tokens $span $($inner)*);
+            $crate::quote_each_token!($tokens $($inner)*);
+        }
+    }};
+    ($tokens:ident $b3:tt $b2:tt # (( $($inner:tt)* )) * $a2:tt $a3:tt) => {};
+    ($tokens:ident $b3:tt # ( $($inner:tt)* ) (*) $a1:tt $a2:tt $a3:tt) => {};
+
+    ($tokens:ident $b3:tt $b2:tt $b1:tt (#) ( $($inner:tt)* ) $sep:tt *) => {{
+        use $crate::__private::ext::*;
+        let mut _i = 0usize;
+        let has_iter = $crate::__private::ThereIsNoIteratorInRepetition;
+        $crate::pounded_var_names!(quote_bind_into_iter!(has_iter) () $($inner)*);
+        let _: $crate::__private::HasIterator = has_iter;
+        while true {
+            $crate::pounded_var_names!(quote_bind_next_or_break!() () $($inner)*);
+            if _i > 0 {
+                $crate::quote_token!($tokens $sep);
+            }
+            _i += 1;
+            $crate::quote_each_token!($tokens $($inner)*);
+        }
+    }};
+    ($tokens:ident $b3:tt $b2:tt # (( $($inner:tt)* )) $sep:tt * $a3:tt) => {};
+    ($tokens:ident $b3:tt # ( $($inner:tt)* ) ($sep:tt) * $a2:tt $a3:tt) => {};
+    ($tokens:ident # ( $($inner:tt)* ) * (*) $a1:tt $a2:tt $a3:tt) => {
+        // https://github.com/dtolnay/quote/issues/130
+        $crate::quote_token!($tokens *);
+    };
+    ($tokens:ident # ( $($inner:tt)* ) $sep:tt (*) $a1:tt $a2:tt $a3:tt) => {};
+
+    ($tokens:ident $b3:tt $b2:tt $b1:tt (#) $var:ident $a2:tt $a3:tt) => {
+        $crate::ToTokens::to_tokens(&$var, &mut $tokens);
+    };
+    ($tokens:ident $b3:tt $b2:tt # ($var:ident) $a1:tt $a2:tt $a3:tt) => {};
+    ($tokens:ident $b3:tt $b2:tt $b1:tt ($curr:tt) $a1:tt $a2:tt $a3:tt) => {
+        $crate::quote_token!($tokens $curr);
+    };
+}
+
+#[macro_export]
+#[doc(hidden)]
+macro_rules! quote_token_with_context_spanned {
+    ($tokens:ident $span:ident $b3:tt $b2:tt $b1:tt @ $a1:tt $a2:tt $a3:tt) => {};
+
+    ($tokens:ident $span:ident $b3:tt $b2:tt $b1:tt (#) ( $($inner:tt)* ) * $a3:tt) => {{
+        use $crate::__private::ext::*;
+        let has_iter = $crate::__private::ThereIsNoIteratorInRepetition;
+        $crate::pounded_var_names!(quote_bind_into_iter!(has_iter) () $($inner)*);
+        let _: $crate::__private::HasIterator = has_iter;
+        // This is `while true` instead of `loop` because if there are no
+        // iterators used inside of this repetition then the body would not
+        // contain any `break`, so the compiler would emit unreachable code
+        // warnings on anything below the loop. We use has_iter to detect and
+        // fail to compile when there are no iterators, so here we just work
+        // around the unneeded extra warning.
+        while true {
+            $crate::pounded_var_names!(quote_bind_next_or_break!() () $($inner)*);
+            $crate::quote_each_token_spanned!($tokens $span $($inner)*);
         }
     }};
     ($tokens:ident $span:ident $b3:tt $b2:tt # (( $($inner:tt)* )) * $a2:tt $a3:tt) => {};
     ($tokens:ident $span:ident $b3:tt # ( $($inner:tt)* ) (*) $a1:tt $a2:tt $a3:tt) => {};
 
     ($tokens:ident $span:ident $b3:tt $b2:tt $b1:tt (#) ( $($inner:tt)* ) $sep:tt *) => {{
-        use $crate::__rt::ext::*;
+        use $crate::__private::ext::*;
         let mut _i = 0usize;
-        let has_iter = $crate::__rt::ThereIsNoIteratorInRepetition;
+        let has_iter = $crate::__private::ThereIsNoIteratorInRepetition;
         $crate::pounded_var_names!(quote_bind_into_iter!(has_iter) () $($inner)*);
-        let _: $crate::__rt::HasIterator = has_iter;
+        let _: $crate::__private::HasIterator = has_iter;
         while true {
             $crate::pounded_var_names!(quote_bind_next_or_break!() () $($inner)*);
             if _i > 0 {
-                $crate::quote_token!($tokens $span $sep);
+                $crate::quote_token_spanned!($tokens $span $sep);
             }
             _i += 1;
-            $crate::quote_each_token!($tokens $span $($inner)*);
+            $crate::quote_each_token_spanned!($tokens $span $($inner)*);
         }
     }};
     ($tokens:ident $span:ident $b3:tt $b2:tt # (( $($inner:tt)* )) $sep:tt * $a3:tt) => {};
     ($tokens:ident $span:ident $b3:tt # ( $($inner:tt)* ) ($sep:tt) * $a2:tt $a3:tt) => {};
     ($tokens:ident $span:ident # ( $($inner:tt)* ) * (*) $a1:tt $a2:tt $a3:tt) => {
         // https://github.com/dtolnay/quote/issues/130
-        $crate::quote_token!($tokens $span *);
+        $crate::quote_token_spanned!($tokens $span *);
     };
     ($tokens:ident $span:ident # ( $($inner:tt)* ) $sep:tt (*) $a1:tt $a2:tt $a3:tt) => {};
 
@@ -726,223 +835,433 @@
     };
     ($tokens:ident $span:ident $b3:tt $b2:tt # ($var:ident) $a1:tt $a2:tt $a3:tt) => {};
     ($tokens:ident $span:ident $b3:tt $b2:tt $b1:tt ($curr:tt) $a1:tt $a2:tt $a3:tt) => {
-        $crate::quote_token!($tokens $span $curr);
+        $crate::quote_token_spanned!($tokens $span $curr);
     };
 }
 
 #[macro_export]
 #[doc(hidden)]
 macro_rules! quote_token {
+    ($tokens:ident ( $($inner:tt)* )) => {
+        $crate::__private::push_group(
+            &mut $tokens,
+            $crate::__private::Delimiter::Parenthesis,
+            $crate::quote!($($inner)*),
+        );
+    };
+
+    ($tokens:ident [ $($inner:tt)* ]) => {
+        $crate::__private::push_group(
+            &mut $tokens,
+            $crate::__private::Delimiter::Bracket,
+            $crate::quote!($($inner)*),
+        );
+    };
+
+    ($tokens:ident { $($inner:tt)* }) => {
+        $crate::__private::push_group(
+            &mut $tokens,
+            $crate::__private::Delimiter::Brace,
+            $crate::quote!($($inner)*),
+        );
+    };
+
+    ($tokens:ident +) => {
+        $crate::__private::push_add(&mut $tokens);
+    };
+
+    ($tokens:ident +=) => {
+        $crate::__private::push_add_eq(&mut $tokens);
+    };
+
+    ($tokens:ident &) => {
+        $crate::__private::push_and(&mut $tokens);
+    };
+
+    ($tokens:ident &&) => {
+        $crate::__private::push_and_and(&mut $tokens);
+    };
+
+    ($tokens:ident &=) => {
+        $crate::__private::push_and_eq(&mut $tokens);
+    };
+
+    ($tokens:ident @) => {
+        $crate::__private::push_at(&mut $tokens);
+    };
+
+    ($tokens:ident !) => {
+        $crate::__private::push_bang(&mut $tokens);
+    };
+
+    ($tokens:ident ^) => {
+        $crate::__private::push_caret(&mut $tokens);
+    };
+
+    ($tokens:ident ^=) => {
+        $crate::__private::push_caret_eq(&mut $tokens);
+    };
+
+    ($tokens:ident :) => {
+        $crate::__private::push_colon(&mut $tokens);
+    };
+
+    ($tokens:ident ::) => {
+        $crate::__private::push_colon2(&mut $tokens);
+    };
+
+    ($tokens:ident ,) => {
+        $crate::__private::push_comma(&mut $tokens);
+    };
+
+    ($tokens:ident /) => {
+        $crate::__private::push_div(&mut $tokens);
+    };
+
+    ($tokens:ident /=) => {
+        $crate::__private::push_div_eq(&mut $tokens);
+    };
+
+    ($tokens:ident .) => {
+        $crate::__private::push_dot(&mut $tokens);
+    };
+
+    ($tokens:ident ..) => {
+        $crate::__private::push_dot2(&mut $tokens);
+    };
+
+    ($tokens:ident ...) => {
+        $crate::__private::push_dot3(&mut $tokens);
+    };
+
+    ($tokens:ident ..=) => {
+        $crate::__private::push_dot_dot_eq(&mut $tokens);
+    };
+
+    ($tokens:ident =) => {
+        $crate::__private::push_eq(&mut $tokens);
+    };
+
+    ($tokens:ident ==) => {
+        $crate::__private::push_eq_eq(&mut $tokens);
+    };
+
+    ($tokens:ident >=) => {
+        $crate::__private::push_ge(&mut $tokens);
+    };
+
+    ($tokens:ident >) => {
+        $crate::__private::push_gt(&mut $tokens);
+    };
+
+    ($tokens:ident <=) => {
+        $crate::__private::push_le(&mut $tokens);
+    };
+
+    ($tokens:ident <) => {
+        $crate::__private::push_lt(&mut $tokens);
+    };
+
+    ($tokens:ident *=) => {
+        $crate::__private::push_mul_eq(&mut $tokens);
+    };
+
+    ($tokens:ident !=) => {
+        $crate::__private::push_ne(&mut $tokens);
+    };
+
+    ($tokens:ident |) => {
+        $crate::__private::push_or(&mut $tokens);
+    };
+
+    ($tokens:ident |=) => {
+        $crate::__private::push_or_eq(&mut $tokens);
+    };
+
+    ($tokens:ident ||) => {
+        $crate::__private::push_or_or(&mut $tokens);
+    };
+
+    ($tokens:ident #) => {
+        $crate::__private::push_pound(&mut $tokens);
+    };
+
+    ($tokens:ident ?) => {
+        $crate::__private::push_question(&mut $tokens);
+    };
+
+    ($tokens:ident ->) => {
+        $crate::__private::push_rarrow(&mut $tokens);
+    };
+
+    ($tokens:ident <-) => {
+        $crate::__private::push_larrow(&mut $tokens);
+    };
+
+    ($tokens:ident %) => {
+        $crate::__private::push_rem(&mut $tokens);
+    };
+
+    ($tokens:ident %=) => {
+        $crate::__private::push_rem_eq(&mut $tokens);
+    };
+
+    ($tokens:ident =>) => {
+        $crate::__private::push_fat_arrow(&mut $tokens);
+    };
+
+    ($tokens:ident ;) => {
+        $crate::__private::push_semi(&mut $tokens);
+    };
+
+    ($tokens:ident <<) => {
+        $crate::__private::push_shl(&mut $tokens);
+    };
+
+    ($tokens:ident <<=) => {
+        $crate::__private::push_shl_eq(&mut $tokens);
+    };
+
+    ($tokens:ident >>) => {
+        $crate::__private::push_shr(&mut $tokens);
+    };
+
+    ($tokens:ident >>=) => {
+        $crate::__private::push_shr_eq(&mut $tokens);
+    };
+
+    ($tokens:ident *) => {
+        $crate::__private::push_star(&mut $tokens);
+    };
+
+    ($tokens:ident -) => {
+        $crate::__private::push_sub(&mut $tokens);
+    };
+
+    ($tokens:ident -=) => {
+        $crate::__private::push_sub_eq(&mut $tokens);
+    };
+
+    ($tokens:ident $ident:ident) => {
+        $crate::__private::push_ident(&mut $tokens, stringify!($ident));
+    };
+
+    ($tokens:ident $other:tt) => {
+        $crate::__private::parse(&mut $tokens, stringify!($other));
+    };
+}
+
+#[macro_export]
+#[doc(hidden)]
+macro_rules! quote_token_spanned {
     ($tokens:ident $span:ident ( $($inner:tt)* )) => {
-        $tokens.extend({
-            let mut g = $crate::__rt::Group::new(
-                $crate::__rt::Delimiter::Parenthesis,
-                $crate::quote_spanned!($span=> $($inner)*),
-            );
-            g.set_span($span);
-            Some($crate::__rt::TokenTree::from(g))
-        });
+        $crate::__private::push_group_spanned(
+            &mut $tokens,
+            $span,
+            $crate::__private::Delimiter::Parenthesis,
+            $crate::quote_spanned!($span=> $($inner)*),
+        );
     };
 
     ($tokens:ident $span:ident [ $($inner:tt)* ]) => {
-        $tokens.extend({
-            let mut g = $crate::__rt::Group::new(
-                $crate::__rt::Delimiter::Bracket,
-                $crate::quote_spanned!($span=> $($inner)*),
-            );
-            g.set_span($span);
-            Some($crate::__rt::TokenTree::from(g))
-        });
+        $crate::__private::push_group_spanned(
+            &mut $tokens,
+            $span,
+            $crate::__private::Delimiter::Bracket,
+            $crate::quote_spanned!($span=> $($inner)*),
+        );
     };
 
     ($tokens:ident $span:ident { $($inner:tt)* }) => {
-        $tokens.extend({
-            let mut g = $crate::__rt::Group::new(
-                $crate::__rt::Delimiter::Brace,
-                $crate::quote_spanned!($span=> $($inner)*),
-            );
-            g.set_span($span);
-            Some($crate::__rt::TokenTree::from(g))
-        });
+        $crate::__private::push_group_spanned(
+            &mut $tokens,
+            $span,
+            $crate::__private::Delimiter::Brace,
+            $crate::quote_spanned!($span=> $($inner)*),
+        );
     };
 
     ($tokens:ident $span:ident +) => {
-        $crate::__rt::push_add(&mut $tokens, $span);
+        $crate::__private::push_add_spanned(&mut $tokens, $span);
     };
 
     ($tokens:ident $span:ident +=) => {
-        $crate::__rt::push_add_eq(&mut $tokens, $span);
+        $crate::__private::push_add_eq_spanned(&mut $tokens, $span);
     };
 
     ($tokens:ident $span:ident &) => {
-        $crate::__rt::push_and(&mut $tokens, $span);
+        $crate::__private::push_and_spanned(&mut $tokens, $span);
     };
 
     ($tokens:ident $span:ident &&) => {
-        $crate::__rt::push_and_and(&mut $tokens, $span);
+        $crate::__private::push_and_and_spanned(&mut $tokens, $span);
     };
 
     ($tokens:ident $span:ident &=) => {
-        $crate::__rt::push_and_eq(&mut $tokens, $span);
+        $crate::__private::push_and_eq_spanned(&mut $tokens, $span);
     };
 
     ($tokens:ident $span:ident @) => {
-        $crate::__rt::push_at(&mut $tokens, $span);
+        $crate::__private::push_at_spanned(&mut $tokens, $span);
     };
 
     ($tokens:ident $span:ident !) => {
-        $crate::__rt::push_bang(&mut $tokens, $span);
+        $crate::__private::push_bang_spanned(&mut $tokens, $span);
     };
 
     ($tokens:ident $span:ident ^) => {
-        $crate::__rt::push_caret(&mut $tokens, $span);
+        $crate::__private::push_caret_spanned(&mut $tokens, $span);
     };
 
     ($tokens:ident $span:ident ^=) => {
-        $crate::__rt::push_caret_eq(&mut $tokens, $span);
+        $crate::__private::push_caret_eq_spanned(&mut $tokens, $span);
     };
 
     ($tokens:ident $span:ident :) => {
-        $crate::__rt::push_colon(&mut $tokens, $span);
+        $crate::__private::push_colon_spanned(&mut $tokens, $span);
     };
 
     ($tokens:ident $span:ident ::) => {
-        $crate::__rt::push_colon2(&mut $tokens, $span);
+        $crate::__private::push_colon2_spanned(&mut $tokens, $span);
     };
 
     ($tokens:ident $span:ident ,) => {
-        $crate::__rt::push_comma(&mut $tokens, $span);
+        $crate::__private::push_comma_spanned(&mut $tokens, $span);
     };
 
     ($tokens:ident $span:ident /) => {
-        $crate::__rt::push_div(&mut $tokens, $span);
+        $crate::__private::push_div_spanned(&mut $tokens, $span);
     };
 
     ($tokens:ident $span:ident /=) => {
-        $crate::__rt::push_div_eq(&mut $tokens, $span);
+        $crate::__private::push_div_eq_spanned(&mut $tokens, $span);
     };
 
     ($tokens:ident $span:ident .) => {
-        $crate::__rt::push_dot(&mut $tokens, $span);
+        $crate::__private::push_dot_spanned(&mut $tokens, $span);
     };
 
     ($tokens:ident $span:ident ..) => {
-        $crate::__rt::push_dot2(&mut $tokens, $span);
+        $crate::__private::push_dot2_spanned(&mut $tokens, $span);
     };
 
     ($tokens:ident $span:ident ...) => {
-        $crate::__rt::push_dot3(&mut $tokens, $span);
+        $crate::__private::push_dot3_spanned(&mut $tokens, $span);
     };
 
     ($tokens:ident $span:ident ..=) => {
-        $crate::__rt::push_dot_dot_eq(&mut $tokens, $span);
+        $crate::__private::push_dot_dot_eq_spanned(&mut $tokens, $span);
     };
 
     ($tokens:ident $span:ident =) => {
-        $crate::__rt::push_eq(&mut $tokens, $span);
+        $crate::__private::push_eq_spanned(&mut $tokens, $span);
     };
 
     ($tokens:ident $span:ident ==) => {
-        $crate::__rt::push_eq_eq(&mut $tokens, $span);
+        $crate::__private::push_eq_eq_spanned(&mut $tokens, $span);
     };
 
     ($tokens:ident $span:ident >=) => {
-        $crate::__rt::push_ge(&mut $tokens, $span);
+        $crate::__private::push_ge_spanned(&mut $tokens, $span);
     };
 
     ($tokens:ident $span:ident >) => {
-        $crate::__rt::push_gt(&mut $tokens, $span);
+        $crate::__private::push_gt_spanned(&mut $tokens, $span);
     };
 
     ($tokens:ident $span:ident <=) => {
-        $crate::__rt::push_le(&mut $tokens, $span);
+        $crate::__private::push_le_spanned(&mut $tokens, $span);
     };
 
     ($tokens:ident $span:ident <) => {
-        $crate::__rt::push_lt(&mut $tokens, $span);
+        $crate::__private::push_lt_spanned(&mut $tokens, $span);
     };
 
     ($tokens:ident $span:ident *=) => {
-        $crate::__rt::push_mul_eq(&mut $tokens, $span);
+        $crate::__private::push_mul_eq_spanned(&mut $tokens, $span);
     };
 
     ($tokens:ident $span:ident !=) => {
-        $crate::__rt::push_ne(&mut $tokens, $span);
+        $crate::__private::push_ne_spanned(&mut $tokens, $span);
     };
 
     ($tokens:ident $span:ident |) => {
-        $crate::__rt::push_or(&mut $tokens, $span);
+        $crate::__private::push_or_spanned(&mut $tokens, $span);
     };
 
     ($tokens:ident $span:ident |=) => {
-        $crate::__rt::push_or_eq(&mut $tokens, $span);
+        $crate::__private::push_or_eq_spanned(&mut $tokens, $span);
     };
 
     ($tokens:ident $span:ident ||) => {
-        $crate::__rt::push_or_or(&mut $tokens, $span);
+        $crate::__private::push_or_or_spanned(&mut $tokens, $span);
     };
 
     ($tokens:ident $span:ident #) => {
-        $crate::__rt::push_pound(&mut $tokens, $span);
+        $crate::__private::push_pound_spanned(&mut $tokens, $span);
     };
 
     ($tokens:ident $span:ident ?) => {
-        $crate::__rt::push_question(&mut $tokens, $span);
+        $crate::__private::push_question_spanned(&mut $tokens, $span);
     };
 
     ($tokens:ident $span:ident ->) => {
-        $crate::__rt::push_rarrow(&mut $tokens, $span);
+        $crate::__private::push_rarrow_spanned(&mut $tokens, $span);
     };
 
     ($tokens:ident $span:ident <-) => {
-        $crate::__rt::push_larrow(&mut $tokens, $span);
+        $crate::__private::push_larrow_spanned(&mut $tokens, $span);
     };
 
     ($tokens:ident $span:ident %) => {
-        $crate::__rt::push_rem(&mut $tokens, $span);
+        $crate::__private::push_rem_spanned(&mut $tokens, $span);
     };
 
     ($tokens:ident $span:ident %=) => {
-        $crate::__rt::push_rem_eq(&mut $tokens, $span);
+        $crate::__private::push_rem_eq_spanned(&mut $tokens, $span);
     };
 
     ($tokens:ident $span:ident =>) => {
-        $crate::__rt::push_fat_arrow(&mut $tokens, $span);
+        $crate::__private::push_fat_arrow_spanned(&mut $tokens, $span);
     };
 
     ($tokens:ident $span:ident ;) => {
-        $crate::__rt::push_semi(&mut $tokens, $span);
+        $crate::__private::push_semi_spanned(&mut $tokens, $span);
     };
 
     ($tokens:ident $span:ident <<) => {
-        $crate::__rt::push_shl(&mut $tokens, $span);
+        $crate::__private::push_shl_spanned(&mut $tokens, $span);
     };
 
     ($tokens:ident $span:ident <<=) => {
-        $crate::__rt::push_shl_eq(&mut $tokens, $span);
+        $crate::__private::push_shl_eq_spanned(&mut $tokens, $span);
     };
 
     ($tokens:ident $span:ident >>) => {
-        $crate::__rt::push_shr(&mut $tokens, $span);
+        $crate::__private::push_shr_spanned(&mut $tokens, $span);
     };
 
     ($tokens:ident $span:ident >>=) => {
-        $crate::__rt::push_shr_eq(&mut $tokens, $span);
+        $crate::__private::push_shr_eq_spanned(&mut $tokens, $span);
     };
 
     ($tokens:ident $span:ident *) => {
-        $crate::__rt::push_star(&mut $tokens, $span);
+        $crate::__private::push_star_spanned(&mut $tokens, $span);
     };
 
     ($tokens:ident $span:ident -) => {
-        $crate::__rt::push_sub(&mut $tokens, $span);
+        $crate::__private::push_sub_spanned(&mut $tokens, $span);
     };
 
     ($tokens:ident $span:ident -=) => {
-        $crate::__rt::push_sub_eq(&mut $tokens, $span);
+        $crate::__private::push_sub_eq_spanned(&mut $tokens, $span);
+    };
+
+    ($tokens:ident $span:ident $ident:ident) => {
+        $crate::__private::push_ident_spanned(&mut $tokens, $span, stringify!($ident));
     };
 
     ($tokens:ident $span:ident $other:tt) => {
-        $crate::__rt::parse(&mut $tokens, $span, stringify!($other));
+        $crate::__private::parse_spanned(&mut $tokens, $span, stringify!($other));
     };
 }
diff --git a/src/runtime.rs b/src/runtime.rs
index 4a1c14c..db3b6a9 100644
--- a/src/runtime.rs
+++ b/src/runtime.rs
@@ -180,44 +180,75 @@
     }
 }
 
-fn is_ident_start(c: u8) -> bool {
-    (b'a' <= c && c <= b'z') || (b'A' <= c && c <= b'Z') || c == b'_'
+pub fn push_group(tokens: &mut TokenStream, delimiter: Delimiter, inner: TokenStream) {
+    tokens.append(Group::new(delimiter, inner));
 }
 
-fn is_ident_continue(c: u8) -> bool {
-    (b'a' <= c && c <= b'z') || (b'A' <= c && c <= b'Z') || c == b'_' || (b'0' <= c && c <= b'9')
+pub fn push_group_spanned(
+    tokens: &mut TokenStream,
+    span: Span,
+    delimiter: Delimiter,
+    inner: TokenStream,
+) {
+    let mut g = Group::new(delimiter, inner);
+    g.set_span(span);
+    tokens.append(g);
 }
 
-fn is_ident(token: &str) -> bool {
-    let mut iter = token.bytes();
-    let first_ok = iter.next().map(is_ident_start).unwrap_or(false);
-
-    first_ok && iter.all(is_ident_continue)
+pub fn parse(tokens: &mut TokenStream, s: &str) {
+    let s: TokenStream = s.parse().expect("invalid token stream");
+    tokens.extend(s);
 }
 
-pub fn parse(tokens: &mut TokenStream, span: Span, s: &str) {
-    if is_ident(s) {
-        // Fast path, since idents are the most common token.
-        tokens.append(Ident::new(s, span));
+pub fn parse_spanned(tokens: &mut TokenStream, span: Span, s: &str) {
+    let s: TokenStream = s.parse().expect("invalid token stream");
+    tokens.extend(s.into_iter().map(|mut t| {
+        t.set_span(span);
+        t
+    }));
+}
+
+pub fn push_ident(tokens: &mut TokenStream, s: &str) {
+    // Optimization over `mk_ident`, as `s` is guaranteed to be a valid ident.
+    //
+    // FIXME: When `Ident::new_raw` becomes stable, this method should be
+    // updated to call it when available.
+    if s.starts_with("r#") {
+        parse(tokens, s);
     } else {
-        let s: TokenStream = s.parse().expect("invalid token stream");
-        tokens.extend(s.into_iter().map(|mut t| {
-            t.set_span(span);
-            t
-        }));
+        tokens.append(Ident::new(s, Span::call_site()));
+    }
+}
+
+pub fn push_ident_spanned(tokens: &mut TokenStream, span: Span, s: &str) {
+    // Optimization over `mk_ident`, as `s` is guaranteed to be a valid ident.
+    //
+    // FIXME: When `Ident::new_raw` becomes stable, this method should be
+    // updated to call it when available.
+    if s.starts_with("r#") {
+        parse_spanned(tokens, span, s);
+    } else {
+        tokens.append(Ident::new(s, span));
     }
 }
 
 macro_rules! push_punct {
-    ($name:ident $char1:tt) => {
-        pub fn $name(tokens: &mut TokenStream, span: Span) {
+    ($name:ident $spanned:ident $char1:tt) => {
+        pub fn $name(tokens: &mut TokenStream) {
+            tokens.append(Punct::new($char1, Spacing::Alone));
+        }
+        pub fn $spanned(tokens: &mut TokenStream, span: Span) {
             let mut punct = Punct::new($char1, Spacing::Alone);
             punct.set_span(span);
             tokens.append(punct);
         }
     };
-    ($name:ident $char1:tt $char2:tt) => {
-        pub fn $name(tokens: &mut TokenStream, span: Span) {
+    ($name:ident $spanned:ident $char1:tt $char2:tt) => {
+        pub fn $name(tokens: &mut TokenStream) {
+            tokens.append(Punct::new($char1, Spacing::Joint));
+            tokens.append(Punct::new($char2, Spacing::Alone));
+        }
+        pub fn $spanned(tokens: &mut TokenStream, span: Span) {
             let mut punct = Punct::new($char1, Spacing::Joint);
             punct.set_span(span);
             tokens.append(punct);
@@ -226,8 +257,13 @@
             tokens.append(punct);
         }
     };
-    ($name:ident $char1:tt $char2:tt $char3:tt) => {
-        pub fn $name(tokens: &mut TokenStream, span: Span) {
+    ($name:ident $spanned:ident $char1:tt $char2:tt $char3:tt) => {
+        pub fn $name(tokens: &mut TokenStream) {
+            tokens.append(Punct::new($char1, Spacing::Joint));
+            tokens.append(Punct::new($char2, Spacing::Joint));
+            tokens.append(Punct::new($char3, Spacing::Alone));
+        }
+        pub fn $spanned(tokens: &mut TokenStream, span: Span) {
             let mut punct = Punct::new($char1, Spacing::Joint);
             punct.set_span(span);
             tokens.append(punct);
@@ -241,50 +277,50 @@
     };
 }
 
-push_punct!(push_add '+');
-push_punct!(push_add_eq '+' '=');
-push_punct!(push_and '&');
-push_punct!(push_and_and '&' '&');
-push_punct!(push_and_eq '&' '=');
-push_punct!(push_at '@');
-push_punct!(push_bang '!');
-push_punct!(push_caret '^');
-push_punct!(push_caret_eq '^' '=');
-push_punct!(push_colon ':');
-push_punct!(push_colon2 ':' ':');
-push_punct!(push_comma ',');
-push_punct!(push_div '/');
-push_punct!(push_div_eq '/' '=');
-push_punct!(push_dot '.');
-push_punct!(push_dot2 '.' '.');
-push_punct!(push_dot3 '.' '.' '.');
-push_punct!(push_dot_dot_eq '.' '.' '=');
-push_punct!(push_eq '=');
-push_punct!(push_eq_eq '=' '=');
-push_punct!(push_ge '>' '=');
-push_punct!(push_gt '>');
-push_punct!(push_le '<' '=');
-push_punct!(push_lt '<');
-push_punct!(push_mul_eq '*' '=');
-push_punct!(push_ne '!' '=');
-push_punct!(push_or '|');
-push_punct!(push_or_eq '|' '=');
-push_punct!(push_or_or '|' '|');
-push_punct!(push_pound '#');
-push_punct!(push_question '?');
-push_punct!(push_rarrow '-' '>');
-push_punct!(push_larrow '<' '-');
-push_punct!(push_rem '%');
-push_punct!(push_rem_eq '%' '=');
-push_punct!(push_fat_arrow '=' '>');
-push_punct!(push_semi ';');
-push_punct!(push_shl '<' '<');
-push_punct!(push_shl_eq '<' '<' '=');
-push_punct!(push_shr '>' '>');
-push_punct!(push_shr_eq '>' '>' '=');
-push_punct!(push_star '*');
-push_punct!(push_sub '-');
-push_punct!(push_sub_eq '-' '=');
+push_punct!(push_add push_add_spanned '+');
+push_punct!(push_add_eq push_add_eq_spanned '+' '=');
+push_punct!(push_and push_and_spanned '&');
+push_punct!(push_and_and push_and_and_spanned '&' '&');
+push_punct!(push_and_eq push_and_eq_spanned '&' '=');
+push_punct!(push_at push_at_spanned '@');
+push_punct!(push_bang push_bang_spanned '!');
+push_punct!(push_caret push_caret_spanned '^');
+push_punct!(push_caret_eq push_caret_eq_spanned '^' '=');
+push_punct!(push_colon push_colon_spanned ':');
+push_punct!(push_colon2 push_colon2_spanned ':' ':');
+push_punct!(push_comma push_comma_spanned ',');
+push_punct!(push_div push_div_spanned '/');
+push_punct!(push_div_eq push_div_eq_spanned '/' '=');
+push_punct!(push_dot push_dot_spanned '.');
+push_punct!(push_dot2 push_dot2_spanned '.' '.');
+push_punct!(push_dot3 push_dot3_spanned '.' '.' '.');
+push_punct!(push_dot_dot_eq push_dot_dot_eq_spanned '.' '.' '=');
+push_punct!(push_eq push_eq_spanned '=');
+push_punct!(push_eq_eq push_eq_eq_spanned '=' '=');
+push_punct!(push_ge push_ge_spanned '>' '=');
+push_punct!(push_gt push_gt_spanned '>');
+push_punct!(push_le push_le_spanned '<' '=');
+push_punct!(push_lt push_lt_spanned '<');
+push_punct!(push_mul_eq push_mul_eq_spanned '*' '=');
+push_punct!(push_ne push_ne_spanned '!' '=');
+push_punct!(push_or push_or_spanned '|');
+push_punct!(push_or_eq push_or_eq_spanned '|' '=');
+push_punct!(push_or_or push_or_or_spanned '|' '|');
+push_punct!(push_pound push_pound_spanned '#');
+push_punct!(push_question push_question_spanned '?');
+push_punct!(push_rarrow push_rarrow_spanned '-' '>');
+push_punct!(push_larrow push_larrow_spanned '<' '-');
+push_punct!(push_rem push_rem_spanned '%');
+push_punct!(push_rem_eq push_rem_eq_spanned '%' '=');
+push_punct!(push_fat_arrow push_fat_arrow_spanned '=' '>');
+push_punct!(push_semi push_semi_spanned ';');
+push_punct!(push_shl push_shl_spanned '<' '<');
+push_punct!(push_shl_eq push_shl_eq_spanned '<' '<' '=');
+push_punct!(push_shr push_shr_spanned '>' '>');
+push_punct!(push_shr_eq push_shr_eq_spanned '>' '>' '=');
+push_punct!(push_star push_star_spanned '*');
+push_punct!(push_sub push_sub_spanned '-');
+push_punct!(push_sub_eq push_sub_eq_spanned '-' '=');
 
 // Helper method for constructing identifiers from the `format_ident!` macro,
 // handling `r#` prefixes.
@@ -293,9 +329,6 @@
 // although the input string was invalid, due to ignored characters such as
 // whitespace and comments. Instead, we always create a non-raw identifier
 // to validate that the string is OK, and only parse again if needed.
-//
-// The `is_ident` method defined above is insufficient for validation, as it
-// will reject non-ASCII identifiers.
 pub fn mk_ident(id: &str, span: Option<Span>) -> Ident {
     let span = span.unwrap_or_else(Span::call_site);
 
@@ -312,19 +345,15 @@
     //
     // FIXME: When `Ident::new_raw` becomes stable, this method should be
     // updated to call it when available.
-    match id.parse::<TokenStream>() {
-        Ok(ts) => {
-            let mut iter = ts.into_iter();
-            match (iter.next(), iter.next()) {
-                (Some(TokenTree::Ident(mut id)), None) => {
-                    id.set_span(span);
-                    id
-                }
-                _ => unreachable!("valid raw ident fails to parse"),
-            }
+    if let Ok(ts) = id.parse::<TokenStream>() {
+        let mut iter = ts.into_iter();
+        if let (Some(TokenTree::Ident(mut id)), None) = (iter.next(), iter.next()) {
+            id.set_span(span);
+            return id;
         }
-        Err(_) => unreachable!("valid raw ident fails to parse"),
     }
+
+    panic!("not allowed as a raw identifier: `{}`", id);
 }
 
 // Adapts from `IdentFragment` to `fmt::Display` for use by the `format_ident!`
diff --git a/tests/test.rs b/tests/test.rs
index 957d470..d5a3490 100644
--- a/tests/test.rs
+++ b/tests/test.rs
@@ -4,7 +4,7 @@
 use std::collections::BTreeSet;
 
 use proc_macro2::{Ident, Span, TokenStream};
-use quote::{format_ident, quote, TokenStreamExt};
+use quote::{format_ident, quote, quote_spanned, TokenStreamExt};
 
 struct X;
 
@@ -26,8 +26,30 @@
 
     let expected = concat!(
         "impl < 'a , T : ToTokens > ToTokens for & 'a T { ",
-        "fn to_tokens ( & self , tokens : & mut TokenStream ) { ",
-        "( * * self ) . to_tokens ( tokens ) ",
+        "fn to_tokens (& self , tokens : & mut TokenStream) { ",
+        "(* * self) . to_tokens (tokens) ",
+        "} ",
+        "}"
+    );
+
+    assert_eq!(expected, tokens.to_string());
+}
+
+#[test]
+fn test_quote_spanned_impl() {
+    let span = Span::call_site();
+    let tokens = quote_spanned! {span=>
+        impl<'a, T: ToTokens> ToTokens for &'a T {
+            fn to_tokens(&self, tokens: &mut TokenStream) {
+                (**self).to_tokens(tokens)
+            }
+        }
+    };
+
+    let expected = concat!(
+        "impl < 'a , T : ToTokens > ToTokens for & 'a T { ",
+        "fn to_tokens (& self , tokens : & mut TokenStream) { ",
+        "(* * self) . to_tokens (tokens) ",
         "} ",
         "}"
     );
@@ -40,7 +62,7 @@
     let x = X;
     let tokens = quote!(#x <#x> (#x) [#x] {#x});
 
-    let expected = "X < X > ( X ) [ X ] { X }";
+    let expected = "X < X > (X) [X] { X }";
 
     assert_eq!(expected, tokens.to_string());
 }
@@ -96,10 +118,10 @@
         "phantom : :: std :: marker :: PhantomData < Cow < 'a , str > > , ",
         "} ",
         "impl < 'a , T > :: serde :: Serialize for SerializeWith < 'a , T > where T : Serialize { ",
-        "fn serialize < S > ( & self , s : & mut S ) -> Result < ( ) , S :: Error > ",
+        "fn serialize < S > (& self , s : & mut S) -> Result < () , S :: Error > ",
         "where S : :: serde :: Serializer ",
         "{ ",
-        "SomeTrait :: serialize_with ( self . value , s ) ",
+        "SomeTrait :: serialize_with (self . value , s) ",
         "} ",
         "} ",
         "SerializeWith { ",
@@ -130,7 +152,7 @@
         #ii8 #ii16 #ii32 #ii64 #ii128 #iisize
         #uu8 #uu16 #uu32 #uu64 #uu128 #uusize
     };
-    let expected = "-1i8 -1i16 -1i32 -1i64 -1i128 -1isize 1u8 1u16 1u32 1u64 1u128 1usize";
+    let expected = "- 1i8 - 1i16 - 1i32 - 1i64 - 1i128 - 1isize 1u8 1u16 1u32 1u64 1u128 1usize";
     assert_eq!(expected, tokens.to_string());
 }
 
@@ -160,7 +182,7 @@
     let tokens = quote! {
         #zero #pound #quote #apost #newline #heart
     };
-    let expected = "'\\u{0}' '#' '\"' '\\'' '\\n' '\\u{2764}'";
+    let expected = "'\\u{0}' '#' '\"' '\\'' '\\n' '\u{2764}'";
     assert_eq!(expected, tokens.to_string());
 }
 
@@ -341,12 +363,14 @@
     let id2 = format_ident!("Hello{x}", x = 5usize);
     let id3 = format_ident!("Hello{}_{x}", id0, x = 10usize);
     let id4 = format_ident!("Aa", span = Span::call_site());
+    let id5 = format_ident!("Hello{}", Cow::Borrowed("World"));
 
     assert_eq!(id0, "Aa");
     assert_eq!(id1, "HelloAa");
     assert_eq!(id2, "Hello5");
     assert_eq!(id3, "HelloAa_10");
     assert_eq!(id4, "Aa");
+    assert_eq!(id5, "HelloWorld");
 }
 
 #[test]
@@ -365,7 +389,7 @@
     let tokens = quote! {
         /// doc
     };
-    let expected = "# [ doc = r\" doc\" ]";
+    let expected = "# [doc = r\" doc\"]";
     assert_eq!(expected, tokens.to_string());
 }
 
@@ -374,7 +398,7 @@
     let tokens = quote! {
         //! doc
     };
-    let expected = "# ! [ doc = r\" doc\" ]";
+    let expected = "# ! [doc = r\" doc\"]";
     assert_eq!(expected, tokens.to_string());
 }
 
@@ -383,7 +407,7 @@
     let tokens = quote! {
         /** doc */
     };
-    let expected = "# [ doc = r\" doc \" ]";
+    let expected = "# [doc = r\" doc \"]";
     assert_eq!(expected, tokens.to_string());
 }
 
@@ -392,7 +416,7 @@
     let tokens = quote! {
         /*! doc */
     };
-    let expected = "# ! [ doc = r\" doc \" ]";
+    let expected = "# ! [doc = r\" doc \"]";
     assert_eq!(expected, tokens.to_string());
 }
 
@@ -401,7 +425,7 @@
     let tokens = quote! {
         #[inline]
     };
-    let expected = "# [ inline ]";
+    let expected = "# [inline]";
     assert_eq!(expected, tokens.to_string());
 }
 
@@ -410,7 +434,7 @@
     let tokens = quote! {
         #![no_std]
     };
-    let expected = "# ! [ no_std ]";
+    let expected = "# ! [no_std]";
     assert_eq!(expected, tokens.to_string());
 }
 
@@ -424,6 +448,12 @@
         )*
         *out = None;
     };
-    let expected = "f ( '0' ) ; f ( '1' ) ; * out = None ;";
+    let expected = "f ('0') ; f ('1') ; * out = None ;";
     assert_eq!(expected, tokens.to_string());
 }
+
+#[test]
+fn test_quote_raw_id() {
+    let id = quote!(r#raw_id);
+    assert_eq!(id.to_string(), "r#raw_id");
+}
diff --git a/tests/ui/not-repeatable.rs b/tests/ui/not-repeatable.rs
index ff18060..a8f0fe7 100644
--- a/tests/ui/not-repeatable.rs
+++ b/tests/ui/not-repeatable.rs
@@ -1,7 +1,8 @@
 use quote::quote;
-use std::net::Ipv4Addr;
+
+struct Ipv4Addr;
 
 fn main() {
-    let ip = Ipv4Addr::LOCALHOST;
+    let ip = Ipv4Addr;
     let _ = quote! { #(#ip)* };
 }