Snap for 8570526 from 617311a4bebe2c56aed1eac5c16b023d893e28b9 to mainline-networking-release

Change-Id: Ie50b7494c49968049f8e2360a0f8f8d87ca73438
diff --git a/.cargo_vcs_info.json b/.cargo_vcs_info.json
index e15e24e..a0fb259 100644
--- a/.cargo_vcs_info.json
+++ b/.cargo_vcs_info.json
@@ -1,5 +1,6 @@
 {
   "git": {
-    "sha1": "68ebadbc1b4242531c5a78fbba01c648bd58c8e7"
-  }
-}
+    "sha1": "278057d0d2e59c7de95d79d42e4934783d013e83"
+  },
+  "path_in_vcs": ""
+}
\ No newline at end of file
diff --git a/.clippy.toml b/.clippy.toml
new file mode 100644
index 0000000..3d30690
--- /dev/null
+++ b/.clippy.toml
@@ -0,0 +1 @@
+msrv = "1.31.0"
diff --git a/.github/FUNDING.yml b/.github/FUNDING.yml
new file mode 100644
index 0000000..7507077
--- /dev/null
+++ b/.github/FUNDING.yml
@@ -0,0 +1 @@
+github: dtolnay
diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
new file mode 100644
index 0000000..b7f0028
--- /dev/null
+++ b/.github/workflows/ci.yml
@@ -0,0 +1,62 @@
+name: CI
+
+on:
+  push:
+  pull_request:
+  schedule: [cron: "40 1 * * *"]
+
+env:
+  RUSTFLAGS: '-Dwarnings'
+
+jobs:
+  test:
+    name: Rust ${{matrix.rust}}
+    runs-on: ubuntu-latest
+    strategy:
+      fail-fast: false
+      matrix:
+        rust: [stable, beta, 1.36.0]
+    steps:
+      - uses: actions/checkout@v2
+      - uses: dtolnay/rust-toolchain@master
+        with:
+          toolchain: ${{matrix.rust}}
+      - run: cargo test
+
+  nightly:
+    name: Rust nightly
+    runs-on: ubuntu-latest
+    steps:
+      - uses: actions/checkout@v2
+      - uses: dtolnay/rust-toolchain@nightly
+        with:
+          components: rust-src
+      - run: cargo test
+      - run: cargo update -Z minimal-versions
+      - run: cargo build
+
+  msrv:
+    name: Rust 1.31.0
+    runs-on: ubuntu-latest
+    steps:
+      - uses: actions/checkout@v2
+      - uses: dtolnay/rust-toolchain@1.31.0
+      - run: cargo check
+
+  clippy:
+    name: Clippy
+    runs-on: ubuntu-latest
+    if: github.event_name != 'pull_request'
+    steps:
+      - uses: actions/checkout@v2
+      - uses: dtolnay/rust-toolchain@clippy
+      - run: cargo clippy --tests -- -Dclippy::all -Dclippy::pedantic
+
+  outdated:
+    name: Outdated
+    runs-on: ubuntu-latest
+    if: github.event_name != 'pull_request'
+    steps:
+      - uses: actions/checkout@v2
+      - uses: dtolnay/install@cargo-outdated
+      - run: cargo outdated --exit-code 1
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..4fffb2f
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,2 @@
+/target
+/Cargo.lock
diff --git a/Android.bp b/Android.bp
index c894868..2ce1823 100644
--- a/Android.bp
+++ b/Android.bp
@@ -1,4 +1,5 @@
-// This file is generated by cargo2android.py --run --dependencies --host-first-multilib.
+// This file is generated by cargo2android.py --config cargo2android.json.
+// Do not modify this file as changes will be overridden on upgrade.
 
 package {
     default_applicable_licenses: ["external_rust_crates_quote_license"],
@@ -39,6 +40,8 @@
 rust_library_host {
     name: "libquote",
     crate_name: "quote",
+    cargo_env_compat: true,
+    cargo_pkg_version: "1.0.15",
     srcs: ["src/lib.rs"],
     edition: "2018",
     features: [
@@ -50,7 +53,3 @@
     ],
     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 411f943..c06ec0c 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -3,19 +3,19 @@
 # When uploading crates to the registry Cargo will automatically
 # "normalize" Cargo.toml files for maximal compatibility
 # with all versions of Cargo and also rewrite `path` dependencies
-# to registry (e.g., crates.io) dependencies
+# to registry (e.g., crates.io) dependencies.
 #
-# If you believe there's an error in this file please file an
-# issue against the rust-lang/cargo repository. If you're
-# editing this file be aware that the upstream Cargo.toml
-# will likely look very different (and much more reasonable)
+# If you are reading this file be aware that the original Cargo.toml
+# will likely look very different (and much more reasonable).
+# See Cargo.toml.orig for the original contents.
 
 [package]
 edition = "2018"
+rust-version = "1.31"
 name = "quote"
-version = "1.0.9"
+version = "1.0.15"
 authors = ["David Tolnay <dtolnay@gmail.com>"]
-include = ["Cargo.toml", "src/**/*.rs", "tests/**/*.rs", "README.md", "LICENSE-APACHE", "LICENSE-MIT"]
+autobenches = false
 description = "Quasi-quoting macro quote!(...)"
 documentation = "https://docs.rs/quote/"
 readme = "README.md"
@@ -26,13 +26,13 @@
 [package.metadata.docs.rs]
 targets = ["x86_64-unknown-linux-gnu"]
 [dependencies.proc-macro2]
-version = "1.0.20"
+version = "1.0.36"
 default-features = false
 [dev-dependencies.rustversion]
 version = "1.0"
 
 [dev-dependencies.trybuild]
-version = "1.0.19"
+version = "1.0.52"
 features = ["diff"]
 
 [features]
diff --git a/Cargo.toml.orig b/Cargo.toml.orig
index b95c6c5..9dd4c77 100644
--- a/Cargo.toml.orig
+++ b/Cargo.toml.orig
@@ -1,6 +1,6 @@
 [package]
 name = "quote"
-version = "1.0.9" # don't forget to update html_root_url, version in readme for breaking changes
+version = "1.0.15" # 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!(...)"
@@ -9,15 +9,16 @@
 keywords = ["syn"]
 categories = ["development-tools::procedural-macro-helpers"]
 readme = "README.md"
-include = ["Cargo.toml", "src/**/*.rs", "tests/**/*.rs", "README.md", "LICENSE-APACHE", "LICENSE-MIT"]
 edition = "2018"
+autobenches = false
+rust-version = "1.31"
 
 [dependencies]
-proc-macro2 = { version = "1.0.20", default-features = false }
+proc-macro2 = { version = "1.0.36", default-features = false }
 
 [dev-dependencies]
 rustversion = "1.0"
-trybuild = { version = "1.0.19", features = ["diff"] }
+trybuild = { version = "1.0.52", features = ["diff"] }
 
 [features]
 default = ["proc-macro"]
@@ -25,5 +26,8 @@
 # libproc_macro in the rustc compiler.
 proc-macro = ["proc-macro2/proc-macro"]
 
+[workspace]
+members = ["benches"]
+
 [package.metadata.docs.rs]
 targets = ["x86_64-unknown-linux-gnu"]
diff --git a/METADATA b/METADATA
index ee587f2..f788fb6 100644
--- a/METADATA
+++ b/METADATA
@@ -7,13 +7,13 @@
   }
   url {
     type: ARCHIVE
-    value: "https://static.crates.io/crates/quote/quote-1.0.9.crate"
+    value: "https://static.crates.io/crates/quote/quote-1.0.15.crate"
   }
-  version: "1.0.9"
+  version: "1.0.15"
   license_type: NOTICE
   last_upgrade_date {
-    year: 2021
-    month: 2
-    day: 12
+    year: 2022
+    month: 3
+    day: 1
   }
 }
diff --git a/TEST_MAPPING b/TEST_MAPPING
index a1620b5..76a8253 100644
--- a/TEST_MAPPING
+++ b/TEST_MAPPING
@@ -1,68 +1,231 @@
 // Generated by update_crate_tests.py for tests that depend on this crate.
 {
+  "imports": [
+    {
+      "path": "external/rust/crates/anyhow"
+    },
+    {
+      "path": "external/rust/crates/arbitrary"
+    },
+    {
+      "path": "external/rust/crates/argh"
+    },
+    {
+      "path": "external/rust/crates/base64"
+    },
+    {
+      "path": "external/rust/crates/bitflags"
+    },
+    {
+      "path": "external/rust/crates/bytes"
+    },
+    {
+      "path": "external/rust/crates/either"
+    },
+    {
+      "path": "external/rust/crates/futures-util"
+    },
+    {
+      "path": "external/rust/crates/jni"
+    },
+    {
+      "path": "external/rust/crates/libm"
+    },
+    {
+      "path": "external/rust/crates/libsqlite3-sys"
+    },
+    {
+      "path": "external/rust/crates/oid-registry"
+    },
+    {
+      "path": "external/rust/crates/rand_chacha"
+    },
+    {
+      "path": "external/rust/crates/serde"
+    },
+    {
+      "path": "external/rust/crates/serde-xml-rs"
+    },
+    {
+      "path": "external/rust/crates/serde_cbor"
+    },
+    {
+      "path": "external/rust/crates/slab"
+    },
+    {
+      "path": "external/rust/crates/tinytemplate"
+    },
+    {
+      "path": "external/rust/crates/tinyvec"
+    },
+    {
+      "path": "external/rust/crates/tokio"
+    },
+    {
+      "path": "external/rust/crates/tokio-test"
+    },
+    {
+      "path": "external/rust/crates/unicode-bidi"
+    },
+    {
+      "path": "external/rust/crates/unicode-xid"
+    },
+    {
+      "path": "external/rust/crates/url"
+    }
+  ],
   "presubmit": [
     {
-      "name": "url_device_test_src_lib"
+      "name": "ZipFuseTest"
     },
     {
-      "name": "anyhow_device_test_tests_test_downcast"
+      "name": "apkdmverity.test"
     },
     {
-      "name": "anyhow_device_test_tests_test_repr"
+      "name": "authfs_device_test_src_lib"
+    },
+    {
+      "name": "diced_open_dice_cbor_test"
+    },
+    {
+      "name": "diced_sample_inputs_test"
+    },
+    {
+      "name": "diced_test"
+    },
+    {
+      "name": "diced_utils_test"
+    },
+    {
+      "name": "diced_vendor_test"
+    },
+    {
+      "name": "doh_unit_test"
+    },
+    {
+      "name": "keystore2_crypto_test_rust"
+    },
+    {
+      "name": "keystore2_km_compat_test"
+    },
+    {
+      "name": "keystore2_selinux_concurrency_test"
     },
     {
       "name": "keystore2_selinux_test"
     },
     {
-      "name": "anyhow_device_test_tests_test_fmt"
+      "name": "keystore2_test"
     },
     {
-      "name": "libm_device_test_src_lib"
+      "name": "keystore2_test_utils_test"
     },
     {
-      "name": "anyhow_device_test_tests_test_convert"
+      "name": "keystore2_vintf_test"
     },
     {
-      "name": "libsqlite3-sys_device_test_src_lib"
+      "name": "legacykeystore_test"
     },
     {
-      "name": "anyhow_device_test_tests_test_source"
+      "name": "libapkverify.integration_test"
     },
     {
-      "name": "unicode-bidi_device_test_src_lib"
+      "name": "libapkverify.test"
     },
     {
-      "name": "anyhow_device_test_src_lib"
+      "name": "libcert_request_validator_tests"
     },
     {
-      "name": "anyhow_device_test_tests_test_autotrait"
+      "name": "libidsig.test"
     },
     {
-      "name": "anyhow_device_test_tests_test_context"
+      "name": "librustutils_test"
     },
     {
-      "name": "anyhow_device_test_tests_test_macros"
+      "name": "microdroid_manager_test"
     },
     {
-      "name": "anyhow_device_test_tests_test_chain"
+      "name": "rustBinderTest"
     },
     {
-      "name": "anyhow_device_test_tests_test_ffi"
+      "name": "virtualizationservice_device_test"
+    }
+  ],
+  "presubmit-rust": [
+    {
+      "name": "ZipFuseTest"
     },
     {
-      "name": "serde_test_device_test_src_lib"
+      "name": "apkdmverity.test"
     },
     {
-      "name": "futures-util_device_test_src_lib"
+      "name": "authfs_device_test_src_lib"
+    },
+    {
+      "name": "diced_open_dice_cbor_test"
+    },
+    {
+      "name": "diced_sample_inputs_test"
+    },
+    {
+      "name": "diced_test"
+    },
+    {
+      "name": "diced_utils_test"
+    },
+    {
+      "name": "diced_vendor_test"
+    },
+    {
+      "name": "doh_unit_test"
+    },
+    {
+      "name": "keystore2_crypto_test_rust"
+    },
+    {
+      "name": "keystore2_km_compat_test"
+    },
+    {
+      "name": "keystore2_selinux_concurrency_test"
+    },
+    {
+      "name": "keystore2_selinux_test"
     },
     {
       "name": "keystore2_test"
     },
     {
-      "name": "anyhow_device_test_tests_test_boxed"
+      "name": "keystore2_test_utils_test"
     },
     {
-      "name": "keystore2_crypto_test_rust"
+      "name": "keystore2_vintf_test"
+    },
+    {
+      "name": "legacykeystore_test"
+    },
+    {
+      "name": "libapkverify.integration_test"
+    },
+    {
+      "name": "libapkverify.test"
+    },
+    {
+      "name": "libcert_request_validator_tests"
+    },
+    {
+      "name": "libidsig.test"
+    },
+    {
+      "name": "librustutils_test"
+    },
+    {
+      "name": "microdroid_manager_test"
+    },
+    {
+      "name": "rustBinderTest"
+    },
+    {
+      "name": "virtualizationservice_device_test"
     }
   ]
 }
diff --git a/cargo2android.json b/cargo2android.json
new file mode 100644
index 0000000..bb77633
--- /dev/null
+++ b/cargo2android.json
@@ -0,0 +1,4 @@
+{
+  "host-first-multilib": true,
+  "run": true
+}
\ No newline at end of file
diff --git a/rust-toolchain.toml b/rust-toolchain.toml
new file mode 100644
index 0000000..20fe888
--- /dev/null
+++ b/rust-toolchain.toml
@@ -0,0 +1,2 @@
+[toolchain]
+components = ["rust-src"]
diff --git a/src/format.rs b/src/format.rs
index 745cb5d..5e44b01 100644
--- a/src/format.rs
+++ b/src/format.rs
@@ -11,10 +11,10 @@
 /// of format types to traits is:
 ///
 /// * `{}` ⇒ [`IdentFragment`]
-/// * `{:o}` ⇒ [`Octal`](`std::fmt::Octal`)
-/// * `{:x}` ⇒ [`LowerHex`](`std::fmt::LowerHex`)
-/// * `{:X}` ⇒ [`UpperHex`](`std::fmt::UpperHex`)
-/// * `{:b}` ⇒ [`Binary`](`std::fmt::Binary`)
+/// * `{:o}` ⇒ [`Octal`](std::fmt::Octal)
+/// * `{:x}` ⇒ [`LowerHex`](std::fmt::LowerHex)
+/// * `{:X}` ⇒ [`UpperHex`](std::fmt::UpperHex)
+/// * `{:b}` ⇒ [`Binary`](std::fmt::Binary)
 ///
 /// See [`std::fmt`] for more information.
 ///
@@ -29,7 +29,8 @@
 ///    unsigned integers and strings.
 /// * [`Ident`] arguments will have their `r#` prefixes stripped, if present.
 ///
-/// [`Ident`]: `proc_macro2::Ident`
+/// [`IdentFragment`]: crate::IdentFragment
+/// [`Ident`]: proc_macro2::Ident
 ///
 /// <br>
 ///
@@ -59,8 +60,8 @@
 /// format_ident!("MyIdent", span = my_span);
 /// ```
 ///
-/// [`Span`]: `proc_macro2::Span`
-/// [`Span::call_site`]: `proc_macro2::Span::call_site`
+/// [`Span`]: proc_macro2::Span
+/// [`Span::call_site`]: proc_macro2::Span::call_site
 ///
 /// <p><br></p>
 ///
diff --git a/src/ident_fragment.rs b/src/ident_fragment.rs
index e7472fe..67e2e33 100644
--- a/src/ident_fragment.rs
+++ b/src/ident_fragment.rs
@@ -79,7 +79,7 @@
                 }
             }
         )*
-    }
+    };
 }
 
 ident_fragment_display!(bool, str, String, char);
diff --git a/src/lib.rs b/src/lib.rs
index 356e43a..02f6532 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -81,12 +81,14 @@
 //! ```
 
 // Quote types in rustdoc of other crates get linked to here.
-#![doc(html_root_url = "https://docs.rs/quote/1.0.9")]
+#![doc(html_root_url = "https://docs.rs/quote/1.0.15")]
 #![allow(
     clippy::doc_markdown,
     clippy::missing_errors_doc,
     clippy::missing_panics_doc,
-    clippy::module_name_repetitions
+    clippy::module_name_repetitions,
+    // false positive https://github.com/rust-lang/rust-clippy/issues/6983
+    clippy::wrong_self_convention,
 )]
 
 #[cfg(all(
@@ -743,9 +745,15 @@
         // 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 {
+        //
+        // FIXME: temporariliy working around Clippy regression.
+        // https://github.com/rust-lang/rust-clippy/issues/7768
+        loop {
             $crate::pounded_var_names!(quote_bind_next_or_break!() () $($inner)*);
             $crate::quote_each_token!($tokens $($inner)*);
+            if false {
+                break;
+            }
         }
     }};
     ($tokens:ident $b3:tt $b2:tt # (( $($inner:tt)* )) * $a2:tt $a3:tt) => {};
@@ -757,13 +765,16 @@
         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 {
+        loop {
             $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)*);
+            if false {
+                break;
+            }
         }
     }};
     ($tokens:ident $b3:tt $b2:tt # (( $($inner:tt)* )) $sep:tt * $a3:tt) => {};
@@ -799,9 +810,15 @@
         // 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 {
+        //
+        // FIXME: temporariliy working around Clippy regression.
+        // https://github.com/rust-lang/rust-clippy/issues/7768
+        loop {
             $crate::pounded_var_names!(quote_bind_next_or_break!() () $($inner)*);
             $crate::quote_each_token_spanned!($tokens $span $($inner)*);
+            if false {
+                break;
+            }
         }
     }};
     ($tokens:ident $span:ident $b3:tt $b2:tt # (( $($inner:tt)* )) * $a2:tt $a3:tt) => {};
@@ -813,13 +830,16 @@
         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 {
+        loop {
             $crate::pounded_var_names!(quote_bind_next_or_break!() () $($inner)*);
             if _i > 0 {
                 $crate::quote_token_spanned!($tokens $span $sep);
             }
             _i += 1;
             $crate::quote_each_token_spanned!($tokens $span $($inner)*);
+            if false {
+                break;
+            }
         }
     }};
     ($tokens:ident $span:ident $b3:tt $b2:tt # (( $($inner:tt)* )) $sep:tt * $a3:tt) => {};
@@ -1046,6 +1066,14 @@
         $crate::__private::push_ident(&mut $tokens, stringify!($ident));
     };
 
+    ($tokens:ident $lifetime:lifetime) => {
+        $crate::__private::push_lifetime(&mut $tokens, stringify!($lifetime));
+    };
+
+    ($tokens:ident _) => {
+        $crate::__private::push_underscore(&mut $tokens);
+    };
+
     ($tokens:ident $other:tt) => {
         $crate::__private::parse(&mut $tokens, stringify!($other));
     };
@@ -1261,6 +1289,14 @@
         $crate::__private::push_ident_spanned(&mut $tokens, $span, stringify!($ident));
     };
 
+    ($tokens:ident $span:ident $lifetime:lifetime) => {
+        $crate::__private::push_lifetime_spanned(&mut $tokens, $span, stringify!($lifetime));
+    };
+
+    ($tokens:ident $span:ident _) => {
+        $crate::__private::push_underscore_spanned(&mut $tokens, $span);
+    };
+
     ($tokens:ident $span:ident $other:tt) => {
         $crate::__private::parse_spanned(&mut $tokens, $span, stringify!($other));
     };
diff --git a/src/runtime.rs b/src/runtime.rs
index db3b6a9..52955cb 100644
--- a/src/runtime.rs
+++ b/src/runtime.rs
@@ -1,5 +1,6 @@
 use crate::{IdentFragment, ToTokens, TokenStreamExt};
 use std::fmt;
+use std::iter;
 use std::ops::BitOr;
 
 pub use proc_macro2::*;
@@ -123,25 +124,6 @@
         }
     }
 
-    macro_rules! array_rep_slice {
-        ($($l:tt)*) => {
-            $(
-                impl<'q, T: 'q> RepAsIteratorExt<'q> for [T; $l] {
-                    type Iter = slice::Iter<'q, T>;
-
-                    fn quote_into_iter(&'q self) -> (Self::Iter, HasIter) {
-                        (self.iter(), HasIter)
-                    }
-                }
-            )*
-        }
-    }
-
-    array_rep_slice!(
-        0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
-        17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32
-    );
-
     impl<'q, T: RepAsIteratorExt<'q>> RepAsIteratorExt<'q> for RepInterp<T> {
         type Iter = T::Iter;
 
@@ -197,15 +179,29 @@
 
 pub fn parse(tokens: &mut TokenStream, s: &str) {
     let s: TokenStream = s.parse().expect("invalid token stream");
-    tokens.extend(s);
+    tokens.extend(iter::once(s));
 }
 
 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
-    }));
+    tokens.extend(s.into_iter().map(|t| respan_token_tree(t, span)));
+}
+
+// Token tree with every span replaced by the given one.
+fn respan_token_tree(mut token: TokenTree, span: Span) -> TokenTree {
+    match &mut token {
+        TokenTree::Group(g) => {
+            let stream = g
+                .stream()
+                .into_iter()
+                .map(|token| respan_token_tree(token, span))
+                .collect();
+            *g = Group::new(g.delimiter(), stream);
+            g.set_span(span);
+        }
+        other => other.set_span(span),
+    }
+    token
 }
 
 pub fn push_ident(tokens: &mut TokenStream, s: &str) {
@@ -232,6 +228,70 @@
     }
 }
 
+pub fn push_lifetime(tokens: &mut TokenStream, lifetime: &str) {
+    struct Lifetime<'a> {
+        name: &'a str,
+        state: u8,
+    }
+
+    impl<'a> Iterator for Lifetime<'a> {
+        type Item = TokenTree;
+
+        fn next(&mut self) -> Option<Self::Item> {
+            match self.state {
+                0 => {
+                    self.state = 1;
+                    Some(TokenTree::Punct(Punct::new('\'', Spacing::Joint)))
+                }
+                1 => {
+                    self.state = 2;
+                    Some(TokenTree::Ident(Ident::new(self.name, Span::call_site())))
+                }
+                _ => None,
+            }
+        }
+    }
+
+    tokens.extend(Lifetime {
+        name: &lifetime[1..],
+        state: 0,
+    });
+}
+
+pub fn push_lifetime_spanned(tokens: &mut TokenStream, span: Span, lifetime: &str) {
+    struct Lifetime<'a> {
+        name: &'a str,
+        span: Span,
+        state: u8,
+    }
+
+    impl<'a> Iterator for Lifetime<'a> {
+        type Item = TokenTree;
+
+        fn next(&mut self) -> Option<Self::Item> {
+            match self.state {
+                0 => {
+                    self.state = 1;
+                    let mut apostrophe = Punct::new('\'', Spacing::Joint);
+                    apostrophe.set_span(self.span);
+                    Some(TokenTree::Punct(apostrophe))
+                }
+                1 => {
+                    self.state = 2;
+                    Some(TokenTree::Ident(Ident::new(self.name, self.span)))
+                }
+                _ => None,
+            }
+        }
+    }
+
+    tokens.extend(Lifetime {
+        name: &lifetime[1..],
+        span,
+        state: 0,
+    });
+}
+
 macro_rules! push_punct {
     ($name:ident $spanned:ident $char1:tt) => {
         pub fn $name(tokens: &mut TokenStream) {
@@ -322,6 +382,14 @@
 push_punct!(push_sub push_sub_spanned '-');
 push_punct!(push_sub_eq push_sub_eq_spanned '-' '=');
 
+pub fn push_underscore(tokens: &mut TokenStream) {
+    push_underscore_spanned(tokens, Span::call_site());
+}
+
+pub fn push_underscore_spanned(tokens: &mut TokenStream, span: Span) {
+    tokens.append(Ident::new("_", span));
+}
+
 // Helper method for constructing identifiers from the `format_ident!` macro,
 // handling `r#` prefixes.
 //
diff --git a/src/to_tokens.rs b/src/to_tokens.rs
index 7f98083..dbb8dfc 100644
--- a/src/to_tokens.rs
+++ b/src/to_tokens.rs
@@ -127,13 +127,15 @@
 }
 
 macro_rules! primitive {
-    ($($t:ident => $name:ident)*) => ($(
-        impl ToTokens for $t {
-            fn to_tokens(&self, tokens: &mut TokenStream) {
-                tokens.append(Literal::$name(*self));
+    ($($t:ident => $name:ident)*) => {
+        $(
+            impl ToTokens for $t {
+                fn to_tokens(&self, tokens: &mut TokenStream) {
+                    tokens.append(Literal::$name(*self));
+                }
             }
-        }
-    )*)
+        )*
+    };
 }
 
 primitive! {
diff --git a/tests/test.rs b/tests/test.rs
index d5a3490..11f8a31 100644
--- a/tests/test.rs
+++ b/tests/test.rs
@@ -1,4 +1,10 @@
-#![cfg_attr(feature = "cargo-clippy", allow(blacklisted_name))]
+#![allow(
+    clippy::blacklisted_name,
+    clippy::let_underscore_drop,
+    clippy::shadow_unrelated,
+    clippy::unseparated_literal_suffix,
+    clippy::used_underscore_binding
+)]
 
 use std::borrow::Cow;
 use std::collections::BTreeSet;
@@ -79,6 +85,27 @@
 }
 
 #[test]
+fn test_array() {
+    let array: [u8; 40] = [0; 40];
+    let _ = quote!(#(#array #array)*);
+
+    let ref_array: &[u8; 40] = &[0; 40];
+    let _ = quote!(#(#ref_array #ref_array)*);
+
+    let ref_slice: &[u8] = &[0; 40];
+    let _ = quote!(#(#ref_slice #ref_slice)*);
+
+    let array: [X; 2] = [X, X]; // !Copy
+    let _ = quote!(#(#array #array)*);
+
+    let ref_array: &[X; 2] = &[X, X];
+    let _ = quote!(#(#ref_array #ref_array)*);
+
+    let ref_slice: &[X] = &[X, X];
+    let _ = quote!(#(#ref_slice #ref_slice)*);
+}
+
+#[test]
 fn test_advanced() {
     let generics = quote!( <'a, T> );
 
@@ -149,10 +176,11 @@
     let uusize = 1usize;
 
     let tokens = quote! {
+        1 1i32 1u256
         #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 = "1 1i32 1u256 - 1i8 - 1i16 - 1i32 - 1i64 - 1i128 - 1isize 1u8 1u16 1u32 1u64 1u128 1usize";
     assert_eq!(expected, tokens.to_string());
 }
 
@@ -203,6 +231,31 @@
 }
 
 #[test]
+fn test_interpolated_literal() {
+    macro_rules! m {
+        ($literal:literal) => {
+            quote!($literal)
+        };
+    }
+
+    let tokens = m!(1);
+    let expected = "1";
+    assert_eq!(expected, tokens.to_string());
+
+    let tokens = m!(-1);
+    let expected = "- 1";
+    assert_eq!(expected, tokens.to_string());
+
+    let tokens = m!(true);
+    let expected = "true";
+    assert_eq!(expected, tokens.to_string());
+
+    let tokens = m!(-true);
+    let expected = "- true";
+    assert_eq!(expected, tokens.to_string());
+}
+
+#[test]
 fn test_ident() {
     let foo = Ident::new("Foo", Span::call_site());
     let bar = Ident::new(&format!("Bar{}", 7), Span::call_site());
@@ -212,6 +265,13 @@
 }
 
 #[test]
+fn test_underscore() {
+    let tokens = quote!(let _;);
+    let expected = "let _ ;";
+    assert_eq!(expected, tokens.to_string());
+}
+
+#[test]
 fn test_duplicate() {
     let ch = 'x';
 
diff --git a/tests/ui/does-not-have-iter-interpolated-dup.stderr b/tests/ui/does-not-have-iter-interpolated-dup.stderr
new file mode 100644
index 0000000..bcd631d
--- /dev/null
+++ b/tests/ui/does-not-have-iter-interpolated-dup.stderr
@@ -0,0 +1,10 @@
+error[E0308]: mismatched types
+ --> tests/ui/does-not-have-iter-interpolated-dup.rs:8:5
+  |
+8 |     quote!(#(#nonrep #nonrep)*);
+  |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^
+  |     |
+  |     expected struct `HasIterator`, found struct `ThereIsNoIteratorInRepetition`
+  |     expected due to this
+  |
+  = note: this error originates in the macro `$crate::quote_token_with_context` (in Nightly builds, run with -Z macro-backtrace for more info)
diff --git a/tests/ui/does-not-have-iter-interpolated.stderr b/tests/ui/does-not-have-iter-interpolated.stderr
new file mode 100644
index 0000000..799837b
--- /dev/null
+++ b/tests/ui/does-not-have-iter-interpolated.stderr
@@ -0,0 +1,10 @@
+error[E0308]: mismatched types
+ --> tests/ui/does-not-have-iter-interpolated.rs:8:5
+  |
+8 |     quote!(#(#nonrep)*);
+  |     ^^^^^^^^^^^^^^^^^^^
+  |     |
+  |     expected struct `HasIterator`, found struct `ThereIsNoIteratorInRepetition`
+  |     expected due to this
+  |
+  = note: this error originates in the macro `$crate::quote_token_with_context` (in Nightly builds, run with -Z macro-backtrace for more info)
diff --git a/tests/ui/does-not-have-iter-separated.stderr b/tests/ui/does-not-have-iter-separated.stderr
new file mode 100644
index 0000000..aa2e693
--- /dev/null
+++ b/tests/ui/does-not-have-iter-separated.stderr
@@ -0,0 +1,10 @@
+error[E0308]: mismatched types
+ --> tests/ui/does-not-have-iter-separated.rs:4:5
+  |
+4 |     quote!(#(a b),*);
+  |     ^^^^^^^^^^^^^^^^
+  |     |
+  |     expected struct `HasIterator`, found struct `ThereIsNoIteratorInRepetition`
+  |     expected due to this
+  |
+  = note: this error originates in the macro `$crate::quote_token_with_context` (in Nightly builds, run with -Z macro-backtrace for more info)
diff --git a/tests/ui/does-not-have-iter.stderr b/tests/ui/does-not-have-iter.stderr
new file mode 100644
index 0000000..c2692fe
--- /dev/null
+++ b/tests/ui/does-not-have-iter.stderr
@@ -0,0 +1,10 @@
+error[E0308]: mismatched types
+ --> tests/ui/does-not-have-iter.rs:4:5
+  |
+4 |     quote!(#(a b)*);
+  |     ^^^^^^^^^^^^^^^
+  |     |
+  |     expected struct `HasIterator`, found struct `ThereIsNoIteratorInRepetition`
+  |     expected due to this
+  |
+  = note: this error originates in the macro `$crate::quote_token_with_context` (in Nightly builds, run with -Z macro-backtrace for more info)
diff --git a/tests/ui/not-quotable.stderr b/tests/ui/not-quotable.stderr
new file mode 100644
index 0000000..5dd13bf
--- /dev/null
+++ b/tests/ui/not-quotable.stderr
@@ -0,0 +1,7 @@
+error[E0277]: the trait bound `Ipv4Addr: ToTokens` is not satisfied
+ --> tests/ui/not-quotable.rs:6:13
+  |
+6 |     let _ = quote! { #ip };
+  |             ^^^^^^^^^^^^^^ the trait `ToTokens` is not implemented for `Ipv4Addr`
+  |
+  = note: this error originates in the macro `$crate::quote_token_with_context` (in Nightly builds, run with -Z macro-backtrace for more info)
diff --git a/tests/ui/not-repeatable.stderr b/tests/ui/not-repeatable.stderr
new file mode 100644
index 0000000..cd5a1e4
--- /dev/null
+++ b/tests/ui/not-repeatable.stderr
@@ -0,0 +1,47 @@
+error[E0599]: the method `quote_into_iter` exists for struct `Ipv4Addr`, but its trait bounds were not satisfied
+    --> tests/ui/not-repeatable.rs:7:13
+     |
+3    | struct Ipv4Addr;
+     | ----------------
+     | |
+     | method `quote_into_iter` not found for this
+     | doesn't satisfy `Ipv4Addr: Iterator`
+     | doesn't satisfy `Ipv4Addr: ToTokens`
+     | doesn't satisfy `Ipv4Addr: quote::__private::ext::RepIteratorExt`
+     | doesn't satisfy `Ipv4Addr: quote::__private::ext::RepToTokensExt`
+...
+7    |     let _ = quote! { #(#ip)* };
+     |             ^^^^^^^^^^^^^^^^^^ method cannot be called on `Ipv4Addr` due to unsatisfied trait bounds
+     |
+     = note: the following trait bounds were not satisfied:
+             `Ipv4Addr: Iterator`
+             which is required by `Ipv4Addr: quote::__private::ext::RepIteratorExt`
+             `&Ipv4Addr: Iterator`
+             which is required by `&Ipv4Addr: quote::__private::ext::RepIteratorExt`
+             `Ipv4Addr: ToTokens`
+             which is required by `Ipv4Addr: quote::__private::ext::RepToTokensExt`
+             `&mut Ipv4Addr: Iterator`
+             which is required by `&mut Ipv4Addr: quote::__private::ext::RepIteratorExt`
+note: the following traits must be implemented
+    --> $RUST/core/src/iter/traits/iterator.rs
+     |
+     | /  pub trait Iterator {
+     | |      /// The type of the elements being iterated over.
+     | |      #[stable(feature = "rust1", since = "1.0.0")]
+     | |      type Item;
+...    |
+     | |      }
+     | |  }
+     | |__^
+     |
+    ::: src/to_tokens.rs
+     |
+     |  / pub trait ToTokens {
+     |  |     /// Write `self` to the given `TokenStream`.
+     |  |     ///
+     |  |     /// The token append methods provided by the [`TokenStreamExt`] extension
+...     |
+     |  |     }
+     |  | }
+     |  |_^
+     = note: this error originates in the macro `$crate::quote_bind_into_iter` (in Nightly builds, run with -Z macro-backtrace for more info)
diff --git a/tests/ui/wrong-type-span.rs b/tests/ui/wrong-type-span.rs
index 1ce391c..d5601c8 100644
--- a/tests/ui/wrong-type-span.rs
+++ b/tests/ui/wrong-type-span.rs
@@ -2,6 +2,6 @@
 
 fn main() {
     let span = "";
-    let x = 0;
+    let x = 0i32;
     quote_spanned!(span=> #x);
 }
diff --git a/tests/ui/wrong-type-span.stderr b/tests/ui/wrong-type-span.stderr
new file mode 100644
index 0000000..c774a4c
--- /dev/null
+++ b/tests/ui/wrong-type-span.stderr
@@ -0,0 +1,8 @@
+error[E0308]: mismatched types
+ --> tests/ui/wrong-type-span.rs:6:20
+  |
+6 |     quote_spanned!(span=> #x);
+  |     ---------------^^^^------
+  |     |              |
+  |     |              expected struct `Span`, found `&str`
+  |     expected due to this