aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAndroid Build Coastguard Worker <android-build-coastguard-worker@google.com>2024-05-14 23:10:48 +0000
committerAndroid Build Coastguard Worker <android-build-coastguard-worker@google.com>2024-05-14 23:10:48 +0000
commite8e7c0abc28c264468273be6c7436128d6246dc8 (patch)
tree75328ee3cb7d029dbb75c8474485e7308f4527a8
parent6cf2fcd748ba2e7c178af9d8282bd93fc5d2f1ce (diff)
parent90eb1bfec0aae0b628ff680f31003b3234189c2d (diff)
downloadquote-sdk-release.tar.gz
Snap for 11841552 from 90eb1bfec0aae0b628ff680f31003b3234189c2d to sdk-releasesdk-release
Change-Id: Ib5f7ba967bb4336012686fee0c5ad6bf39c72ae0
-rw-r--r--.cargo_vcs_info.json2
-rw-r--r--.clippy.toml1
-rw-r--r--.github/workflows/ci.yml39
-rw-r--r--Android.bp6
-rw-r--r--Cargo.toml4
-rw-r--r--Cargo.toml.orig7
-rw-r--r--METADATA25
-rw-r--r--build.rs38
-rw-r--r--src/lib.rs1080
-rw-r--r--tests/ui/not-quotable.stderr16
-rw-r--r--tests/ui/not-repeatable.stderr15
11 files changed, 613 insertions, 620 deletions
diff --git a/.cargo_vcs_info.json b/.cargo_vcs_info.json
index d3000ae..4afd3a9 100644
--- a/.cargo_vcs_info.json
+++ b/.cargo_vcs_info.json
@@ -1,6 +1,6 @@
{
"git": {
- "sha1": "ca98b6594a0bee362a431481ba9ba64e502cc757"
+ "sha1": "5d4880c4255b5c7f5ea0a9ac3cf9f985c418a1e7"
},
"path_in_vcs": ""
} \ No newline at end of file
diff --git a/.clippy.toml b/.clippy.toml
deleted file mode 100644
index 3d30690..0000000
--- a/.clippy.toml
+++ /dev/null
@@ -1 +0,0 @@
-msrv = "1.31.0"
diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
index ed9b799..7bc6003 100644
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -27,7 +27,7 @@ jobs:
rust: [nightly, stable, beta, 1.56.0]
timeout-minutes: 45
steps:
- - uses: actions/checkout@v3
+ - uses: actions/checkout@v4
- uses: dtolnay/rust-toolchain@master
with:
toolchain: ${{matrix.rust}}
@@ -37,23 +37,34 @@ jobs:
if: matrix.rust == 'nightly'
- run: cargo test
- run: cargo run --manifest-path benches/Cargo.toml
- - run: cargo update -Z minimal-versions
- if: matrix.rust == 'nightly'
- - run: cargo build
- if: matrix.rust == 'nightly'
- msrv:
- name: Rust 1.31.0
+ minimal:
+ name: Minimal versions
+ needs: pre_ci
+ if: needs.pre_ci.outputs.continue
+ runs-on: ubuntu-latest
+ timeout-minutes: 45
+ steps:
+ - uses: actions/checkout@v4
+ - uses: dtolnay/rust-toolchain@nightly
+ - run: cargo generate-lockfile -Z minimal-versions
+ - run: cargo check --locked
+
+ doc:
+ name: Documentation
needs: pre_ci
if: needs.pre_ci.outputs.continue
runs-on: ubuntu-latest
timeout-minutes: 45
+ env:
+ RUSTDOCFLAGS: -Dwarnings
steps:
- - uses: actions/checkout@v3
- - uses: dtolnay/rust-toolchain@1.31.0
+ - uses: actions/checkout@v4
+ - uses: dtolnay/rust-toolchain@nightly
with:
components: rust-src
- - run: cargo check
+ - uses: dtolnay/install@cargo-docs-rs
+ - run: cargo docs-rs
clippy:
name: Clippy
@@ -61,7 +72,7 @@ jobs:
if: github.event_name != 'pull_request'
timeout-minutes: 45
steps:
- - uses: actions/checkout@v3
+ - uses: actions/checkout@v4
- uses: dtolnay/rust-toolchain@nightly
with:
components: clippy, rust-src
@@ -74,8 +85,9 @@ jobs:
runs-on: ubuntu-latest
timeout-minutes: 45
steps:
- - uses: actions/checkout@v3
+ - uses: actions/checkout@v4
- uses: dtolnay/rust-toolchain@miri
+ - run: cargo miri setup
- run: cargo miri test
env:
MIRIFLAGS: -Zmiri-strict-provenance
@@ -86,6 +98,7 @@ jobs:
if: github.event_name != 'pull_request'
timeout-minutes: 45
steps:
- - uses: actions/checkout@v3
+ - uses: actions/checkout@v4
+ - uses: dtolnay/rust-toolchain@stable
- uses: dtolnay/install@cargo-outdated
- run: cargo outdated --workspace --exit-code 1
diff --git a/Android.bp b/Android.bp
index e21d65d..c032838 100644
--- a/Android.bp
+++ b/Android.bp
@@ -1,5 +1,7 @@
// This file is generated by cargo_embargo.
-// Do not modify this file as changes will be overridden on upgrade.
+// Do not modify this file after the first "rust_*" or "genrule" module
+// because the changes will be overridden on upgrade.
+// Content before the first "rust_*" or "genrule" module is preserved.
package {
default_applicable_licenses: ["external_rust_crates_quote_license"],
@@ -41,7 +43,7 @@ rust_library_host {
name: "libquote",
crate_name: "quote",
cargo_env_compat: true,
- cargo_pkg_version: "1.0.33",
+ cargo_pkg_version: "1.0.36",
srcs: ["src/lib.rs"],
edition: "2018",
features: [
diff --git a/Cargo.toml b/Cargo.toml
index 4dbf7ab..5b52176 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -13,7 +13,7 @@
edition = "2018"
rust-version = "1.56"
name = "quote"
-version = "1.0.33"
+version = "1.0.36"
authors = ["David Tolnay <dtolnay@gmail.com>"]
autobenches = false
description = "Quasi-quoting macro quote!(...)"
@@ -35,7 +35,7 @@ targets = ["x86_64-unknown-linux-gnu"]
doc-scrape-examples = false
[dependencies.proc-macro2]
-version = "1.0.66"
+version = "1.0.74"
default-features = false
[dev-dependencies.rustversion]
diff --git a/Cargo.toml.orig b/Cargo.toml.orig
index d8b4fe1..d7a8593 100644
--- a/Cargo.toml.orig
+++ b/Cargo.toml.orig
@@ -1,6 +1,6 @@
[package]
name = "quote"
-version = "1.0.26" # don't forget to update html_root_url, version in readme for breaking changes
+version = "1.0.36" # don't forget to update html_root_url, version in readme for breaking changes
authors = ["David Tolnay <dtolnay@gmail.com>"]
autobenches = false
categories = ["development-tools::procedural-macro-helpers"]
@@ -10,10 +10,10 @@ edition = "2018"
keywords = ["macros", "syn"]
license = "MIT OR Apache-2.0"
repository = "https://github.com/dtolnay/quote"
-rust-version = "1.31"
+rust-version = "1.56"
[dependencies]
-proc-macro2 = { version = "1.0.52", default-features = false }
+proc-macro2 = { version = "1.0.74", default-features = false }
[dev-dependencies]
rustversion = "1.0"
@@ -33,3 +33,4 @@ members = ["benches"]
[package.metadata.docs.rs]
targets = ["x86_64-unknown-linux-gnu"]
+rustdoc-args = ["--generate-link-to-definition"]
diff --git a/METADATA b/METADATA
index 38220d6..54a2234 100644
--- a/METADATA
+++ b/METADATA
@@ -1,23 +1,20 @@
# This project was upgraded with external_updater.
-# Usage: tools/external_updater/updater.sh update rust/crates/quote
-# For more info, check https://cs.android.com/android/platform/superproject/+/master:tools/external_updater/README.md
+# Usage: tools/external_updater/updater.sh update external/rust/crates/quote
+# For more info, check https://cs.android.com/android/platform/superproject/+/main:tools/external_updater/README.md
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.26.crate"
- }
- version: "1.0.26"
license_type: NOTICE
last_upgrade_date {
- year: 2023
- month: 3
- day: 20
+ year: 2024
+ month: 5
+ day: 13
+ }
+ homepage: "https://crates.io/crates/quote"
+ identifier {
+ type: "Archive"
+ value: "https://static.crates.io/crates/quote/quote-1.0.36.crate"
+ version: "1.0.36"
}
}
diff --git a/build.rs b/build.rs
deleted file mode 100644
index a7e6b2c..0000000
--- a/build.rs
+++ /dev/null
@@ -1,38 +0,0 @@
-use std::env;
-use std::process::{self, Command};
-use std::str;
-
-fn main() {
- println!("cargo:rerun-if-changed=build.rs");
-
- let version = match rustc_version() {
- Some(version) => version,
- None => return,
- };
-
- if version.minor < 31 {
- eprintln!("Minimum supported rustc version is 1.31");
- process::exit(1);
- }
-
- if version.minor < 53 {
- // https://github.com/rust-lang/rust/issues/43081
- println!("cargo:rustc-cfg=needs_invalid_span_workaround");
- }
-}
-
-struct RustcVersion {
- minor: u32,
-}
-
-fn rustc_version() -> Option<RustcVersion> {
- let rustc = env::var_os("RUSTC")?;
- let output = Command::new(rustc).arg("--version").output().ok()?;
- let version = str::from_utf8(&output.stdout).ok()?;
- let mut pieces = version.split('.');
- if pieces.next() != Some("rustc 1") {
- return None;
- }
- let minor = pieces.next()?.parse().ok()?;
- Some(RustcVersion { minor })
-}
diff --git a/src/lib.rs b/src/lib.rs
index 47167d3..4d198cb 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -92,7 +92,7 @@
//! [prettyplease]: https://github.com/dtolnay/prettyplease
// Quote types in rustdoc of other crates get linked to here.
-#![doc(html_root_url = "https://docs.rs/quote/1.0.33")]
+#![doc(html_root_url = "https://docs.rs/quote/1.0.36")]
#![allow(
clippy::doc_markdown,
clippy::missing_errors_doc,
@@ -125,545 +125,565 @@ pub use crate::to_tokens::ToTokens;
#[doc(hidden)]
pub mod spanned;
-/// The whole point.
-///
-/// Performs variable interpolation against the input and produces it as
-/// [`proc_macro2::TokenStream`].
-///
-/// Note: for returning tokens to the compiler in a procedural macro, use
-/// `.into()` on the result to convert to [`proc_macro::TokenStream`].
-///
-/// [`TokenStream`]: https://docs.rs/proc-macro2/1.0/proc_macro2/struct.TokenStream.html
-///
-/// <br>
-///
-/// # Interpolation
-///
-/// Variable interpolation is done with `#var` (similar to `$var` in
-/// `macro_rules!` macros). This grabs the `var` variable that is currently in
-/// scope and inserts it in that location in the output tokens. Any type
-/// implementing the [`ToTokens`] trait can be interpolated. This includes most
-/// Rust primitive types as well as most of the syntax tree types from the [Syn]
-/// crate.
-///
-/// [`ToTokens`]: trait.ToTokens.html
-/// [Syn]: https://github.com/dtolnay/syn
-///
-/// Repetition is done using `#(...)*` or `#(...),*` again similar to
-/// `macro_rules!`. This iterates through the elements of any variable
-/// interpolated within the repetition and inserts a copy of the repetition body
-/// for each one. The variables in an interpolation may be a `Vec`, slice,
-/// `BTreeSet`, or any `Iterator`.
-///
-/// - `#(#var)*` — no separators
-/// - `#(#var),*` — the character before the asterisk is used as a separator
-/// - `#( struct #var; )*` — the repetition can contain other tokens
-/// - `#( #k => println!("{}", #v), )*` — even multiple interpolations
-///
-/// <br>
-///
-/// # Hygiene
-///
-/// Any interpolated tokens preserve the `Span` information provided by their
-/// `ToTokens` implementation. Tokens that originate within the `quote!`
-/// invocation are spanned with [`Span::call_site()`].
-///
-/// [`Span::call_site()`]: https://docs.rs/proc-macro2/1.0/proc_macro2/struct.Span.html#method.call_site
-///
-/// A different span can be provided through the [`quote_spanned!`] macro.
-///
-/// [`quote_spanned!`]: macro.quote_spanned.html
-///
-/// <br>
-///
-/// # Return type
-///
-/// The macro evaluates to an expression of type `proc_macro2::TokenStream`.
-/// Meanwhile Rust procedural macros are expected to return the type
-/// `proc_macro::TokenStream`.
-///
-/// The difference between the two types is that `proc_macro` types are entirely
-/// specific to procedural macros and cannot ever exist in code outside of a
-/// procedural macro, while `proc_macro2` types may exist anywhere including
-/// tests and non-macro code like main.rs and build.rs. This is why even the
-/// procedural macro ecosystem is largely built around `proc_macro2`, because
-/// that ensures the libraries are unit testable and accessible in non-macro
-/// contexts.
-///
-/// There is a [`From`]-conversion in both directions so returning the output of
-/// `quote!` from a procedural macro usually looks like `tokens.into()` or
-/// `proc_macro::TokenStream::from(tokens)`.
-///
-/// [`From`]: https://doc.rust-lang.org/std/convert/trait.From.html
-///
-/// <br>
-///
-/// # Examples
-///
-/// ### Procedural macro
-///
-/// The structure of a basic procedural macro is as follows. Refer to the [Syn]
-/// crate for further useful guidance on using `quote!` as part of a procedural
-/// macro.
-///
-/// [Syn]: https://github.com/dtolnay/syn
-///
-/// ```
-/// # #[cfg(any())]
-/// extern crate proc_macro;
-/// # extern crate proc_macro2;
-///
-/// # #[cfg(any())]
-/// use proc_macro::TokenStream;
-/// # use proc_macro2::TokenStream;
-/// use quote::quote;
-///
-/// # const IGNORE_TOKENS: &'static str = stringify! {
-/// #[proc_macro_derive(HeapSize)]
-/// # };
-/// pub fn derive_heap_size(input: TokenStream) -> TokenStream {
-/// // Parse the input and figure out what implementation to generate...
-/// # const IGNORE_TOKENS: &'static str = stringify! {
-/// let name = /* ... */;
-/// let expr = /* ... */;
-/// # };
-/// #
-/// # let name = 0;
-/// # let expr = 0;
-///
-/// let expanded = quote! {
-/// // The generated impl.
-/// impl heapsize::HeapSize for #name {
-/// fn heap_size_of_children(&self) -> usize {
-/// #expr
-/// }
-/// }
-/// };
-///
-/// // Hand the output tokens back to the compiler.
-/// TokenStream::from(expanded)
-/// }
-/// ```
-///
-/// <p><br></p>
-///
-/// ### Combining quoted fragments
-///
-/// Usually you don't end up constructing an entire final `TokenStream` in one
-/// piece. Different parts may come from different helper functions. The tokens
-/// produced by `quote!` themselves implement `ToTokens` and so can be
-/// interpolated into later `quote!` invocations to build up a final result.
-///
-/// ```
-/// # use quote::quote;
-/// #
-/// let type_definition = quote! {...};
-/// let methods = quote! {...};
-///
-/// let tokens = quote! {
-/// #type_definition
-/// #methods
-/// };
-/// ```
-///
-/// <p><br></p>
-///
-/// ### Constructing identifiers
-///
-/// Suppose we have an identifier `ident` which came from somewhere in a macro
-/// input and we need to modify it in some way for the macro output. Let's
-/// consider prepending the identifier with an underscore.
-///
-/// Simply interpolating the identifier next to an underscore will not have the
-/// behavior of concatenating them. The underscore and the identifier will
-/// continue to be two separate tokens as if you had written `_ x`.
-///
-/// ```
-/// # use proc_macro2::{self as syn, Span};
-/// # use quote::quote;
-/// #
-/// # let ident = syn::Ident::new("i", Span::call_site());
-/// #
-/// // incorrect
-/// quote! {
-/// let mut _#ident = 0;
-/// }
-/// # ;
-/// ```
-///
-/// The solution is to build a new identifier token with the correct value. As
-/// this is such a common case, the [`format_ident!`] macro provides a
-/// convenient utility for doing so correctly.
-///
-/// ```
-/// # use proc_macro2::{Ident, Span};
-/// # use quote::{format_ident, quote};
-/// #
-/// # let ident = Ident::new("i", Span::call_site());
-/// #
-/// let varname = format_ident!("_{}", ident);
-/// quote! {
-/// let mut #varname = 0;
-/// }
-/// # ;
-/// ```
-///
-/// Alternatively, the APIs provided by Syn and proc-macro2 can be used to
-/// directly build the identifier. This is roughly equivalent to the above, but
-/// will not handle `ident` being a raw identifier.
-///
-/// ```
-/// # use proc_macro2::{self as syn, Span};
-/// # use quote::quote;
-/// #
-/// # let ident = syn::Ident::new("i", Span::call_site());
-/// #
-/// let concatenated = format!("_{}", ident);
-/// let varname = syn::Ident::new(&concatenated, ident.span());
-/// quote! {
-/// let mut #varname = 0;
-/// }
-/// # ;
-/// ```
-///
-/// <p><br></p>
-///
-/// ### Making method calls
-///
-/// Let's say our macro requires some type specified in the macro input to have
-/// a constructor called `new`. We have the type in a variable called
-/// `field_type` of type `syn::Type` and want to invoke the constructor.
-///
-/// ```
-/// # use quote::quote;
-/// #
-/// # let field_type = quote!(...);
-/// #
-/// // incorrect
-/// quote! {
-/// let value = #field_type::new();
-/// }
-/// # ;
-/// ```
-///
-/// This works only sometimes. If `field_type` is `String`, the expanded code
-/// contains `String::new()` which is fine. But if `field_type` is something
-/// like `Vec<i32>` then the expanded code is `Vec<i32>::new()` which is invalid
-/// syntax. Ordinarily in handwritten Rust we would write `Vec::<i32>::new()`
-/// but for macros often the following is more convenient.
-///
-/// ```
-/// # use quote::quote;
-/// #
-/// # let field_type = quote!(...);
-/// #
-/// quote! {
-/// let value = <#field_type>::new();
-/// }
-/// # ;
-/// ```
-///
-/// This expands to `<Vec<i32>>::new()` which behaves correctly.
-///
-/// A similar pattern is appropriate for trait methods.
-///
-/// ```
-/// # use quote::quote;
-/// #
-/// # let field_type = quote!(...);
-/// #
-/// quote! {
-/// let value = <#field_type as core::default::Default>::default();
-/// }
-/// # ;
-/// ```
-///
-/// <p><br></p>
-///
-/// ### Interpolating text inside of doc comments
-///
-/// Neither doc comments nor string literals get interpolation behavior in
-/// quote:
-///
-/// ```compile_fail
-/// quote! {
-/// /// try to interpolate: #ident
-/// ///
-/// /// ...
-/// }
-/// ```
-///
-/// ```compile_fail
-/// quote! {
-/// #[doc = "try to interpolate: #ident"]
-/// }
-/// ```
-///
-/// Instead the best way to build doc comments that involve variables is by
-/// formatting the doc string literal outside of quote.
-///
-/// ```rust
-/// # use proc_macro2::{Ident, Span};
-/// # use quote::quote;
-/// #
-/// # const IGNORE: &str = stringify! {
-/// let msg = format!(...);
-/// # };
-/// #
-/// # let ident = Ident::new("var", Span::call_site());
-/// # let msg = format!("try to interpolate: {}", ident);
-/// quote! {
-/// #[doc = #msg]
-/// ///
-/// /// ...
-/// }
-/// # ;
-/// ```
-///
-/// <p><br></p>
-///
-/// ### Indexing into a tuple struct
-///
-/// When interpolating indices of a tuple or tuple struct, we need them not to
-/// appears suffixed as integer literals by interpolating them as [`syn::Index`]
-/// instead.
-///
-/// [`syn::Index`]: https://docs.rs/syn/1.0/syn/struct.Index.html
-///
-/// ```compile_fail
-/// let i = 0usize..self.fields.len();
-///
-/// // expands to 0 + self.0usize.heap_size() + self.1usize.heap_size() + ...
-/// // which is not valid syntax
-/// quote! {
-/// 0 #( + self.#i.heap_size() )*
-/// }
-/// ```
-///
-/// ```
-/// # use proc_macro2::{Ident, TokenStream};
-/// # use quote::quote;
-/// #
-/// # mod syn {
-/// # use proc_macro2::{Literal, TokenStream};
-/// # use quote::{ToTokens, TokenStreamExt};
-/// #
-/// # pub struct Index(usize);
-/// #
-/// # impl From<usize> for Index {
-/// # fn from(i: usize) -> Self {
-/// # Index(i)
-/// # }
-/// # }
-/// #
-/// # impl ToTokens for Index {
-/// # fn to_tokens(&self, tokens: &mut TokenStream) {
-/// # tokens.append(Literal::usize_unsuffixed(self.0));
-/// # }
-/// # }
-/// # }
-/// #
-/// # struct Struct {
-/// # fields: Vec<Ident>,
-/// # }
-/// #
-/// # impl Struct {
-/// # fn example(&self) -> TokenStream {
-/// let i = (0..self.fields.len()).map(syn::Index::from);
-///
-/// // expands to 0 + self.0.heap_size() + self.1.heap_size() + ...
-/// quote! {
-/// 0 #( + self.#i.heap_size() )*
-/// }
-/// # }
-/// # }
-/// ```
-#[cfg(doc)]
-#[macro_export]
-macro_rules! quote {
- ($($tt:tt)*) => {
- ...
+macro_rules! __quote {
+ ($quote:item) => {
+ /// The whole point.
+ ///
+ /// Performs variable interpolation against the input and produces it as
+ /// [`proc_macro2::TokenStream`].
+ ///
+ /// Note: for returning tokens to the compiler in a procedural macro, use
+ /// `.into()` on the result to convert to [`proc_macro::TokenStream`].
+ ///
+ /// [`TokenStream`]: https://docs.rs/proc-macro2/1.0/proc_macro2/struct.TokenStream.html
+ ///
+ /// <br>
+ ///
+ /// # Interpolation
+ ///
+ /// Variable interpolation is done with `#var` (similar to `$var` in
+ /// `macro_rules!` macros). This grabs the `var` variable that is currently in
+ /// scope and inserts it in that location in the output tokens. Any type
+ /// implementing the [`ToTokens`] trait can be interpolated. This includes most
+ /// Rust primitive types as well as most of the syntax tree types from the [Syn]
+ /// crate.
+ ///
+ /// [`ToTokens`]: trait.ToTokens.html
+ /// [Syn]: https://github.com/dtolnay/syn
+ ///
+ /// Repetition is done using `#(...)*` or `#(...),*` again similar to
+ /// `macro_rules!`. This iterates through the elements of any variable
+ /// interpolated within the repetition and inserts a copy of the repetition body
+ /// for each one. The variables in an interpolation may be a `Vec`, slice,
+ /// `BTreeSet`, or any `Iterator`.
+ ///
+ /// - `#(#var)*` — no separators
+ /// - `#(#var),*` — the character before the asterisk is used as a separator
+ /// - `#( struct #var; )*` — the repetition can contain other tokens
+ /// - `#( #k => println!("{}", #v), )*` — even multiple interpolations
+ ///
+ /// <br>
+ ///
+ /// # Hygiene
+ ///
+ /// Any interpolated tokens preserve the `Span` information provided by their
+ /// `ToTokens` implementation. Tokens that originate within the `quote!`
+ /// invocation are spanned with [`Span::call_site()`].
+ ///
+ /// [`Span::call_site()`]: https://docs.rs/proc-macro2/1.0/proc_macro2/struct.Span.html#method.call_site
+ ///
+ /// A different span can be provided through the [`quote_spanned!`] macro.
+ ///
+ /// [`quote_spanned!`]: macro.quote_spanned.html
+ ///
+ /// <br>
+ ///
+ /// # Return type
+ ///
+ /// The macro evaluates to an expression of type `proc_macro2::TokenStream`.
+ /// Meanwhile Rust procedural macros are expected to return the type
+ /// `proc_macro::TokenStream`.
+ ///
+ /// The difference between the two types is that `proc_macro` types are entirely
+ /// specific to procedural macros and cannot ever exist in code outside of a
+ /// procedural macro, while `proc_macro2` types may exist anywhere including
+ /// tests and non-macro code like main.rs and build.rs. This is why even the
+ /// procedural macro ecosystem is largely built around `proc_macro2`, because
+ /// that ensures the libraries are unit testable and accessible in non-macro
+ /// contexts.
+ ///
+ /// There is a [`From`]-conversion in both directions so returning the output of
+ /// `quote!` from a procedural macro usually looks like `tokens.into()` or
+ /// `proc_macro::TokenStream::from(tokens)`.
+ ///
+ /// [`From`]: https://doc.rust-lang.org/std/convert/trait.From.html
+ ///
+ /// <br>
+ ///
+ /// # Examples
+ ///
+ /// ### Procedural macro
+ ///
+ /// The structure of a basic procedural macro is as follows. Refer to the [Syn]
+ /// crate for further useful guidance on using `quote!` as part of a procedural
+ /// macro.
+ ///
+ /// [Syn]: https://github.com/dtolnay/syn
+ ///
+ /// ```
+ /// # #[cfg(any())]
+ /// extern crate proc_macro;
+ /// # extern crate proc_macro2;
+ ///
+ /// # #[cfg(any())]
+ /// use proc_macro::TokenStream;
+ /// # use proc_macro2::TokenStream;
+ /// use quote::quote;
+ ///
+ /// # const IGNORE_TOKENS: &'static str = stringify! {
+ /// #[proc_macro_derive(HeapSize)]
+ /// # };
+ /// pub fn derive_heap_size(input: TokenStream) -> TokenStream {
+ /// // Parse the input and figure out what implementation to generate...
+ /// # const IGNORE_TOKENS: &'static str = stringify! {
+ /// let name = /* ... */;
+ /// let expr = /* ... */;
+ /// # };
+ /// #
+ /// # let name = 0;
+ /// # let expr = 0;
+ ///
+ /// let expanded = quote! {
+ /// // The generated impl.
+ /// impl heapsize::HeapSize for #name {
+ /// fn heap_size_of_children(&self) -> usize {
+ /// #expr
+ /// }
+ /// }
+ /// };
+ ///
+ /// // Hand the output tokens back to the compiler.
+ /// TokenStream::from(expanded)
+ /// }
+ /// ```
+ ///
+ /// <p><br></p>
+ ///
+ /// ### Combining quoted fragments
+ ///
+ /// Usually you don't end up constructing an entire final `TokenStream` in one
+ /// piece. Different parts may come from different helper functions. The tokens
+ /// produced by `quote!` themselves implement `ToTokens` and so can be
+ /// interpolated into later `quote!` invocations to build up a final result.
+ ///
+ /// ```
+ /// # use quote::quote;
+ /// #
+ /// let type_definition = quote! {...};
+ /// let methods = quote! {...};
+ ///
+ /// let tokens = quote! {
+ /// #type_definition
+ /// #methods
+ /// };
+ /// ```
+ ///
+ /// <p><br></p>
+ ///
+ /// ### Constructing identifiers
+ ///
+ /// Suppose we have an identifier `ident` which came from somewhere in a macro
+ /// input and we need to modify it in some way for the macro output. Let's
+ /// consider prepending the identifier with an underscore.
+ ///
+ /// Simply interpolating the identifier next to an underscore will not have the
+ /// behavior of concatenating them. The underscore and the identifier will
+ /// continue to be two separate tokens as if you had written `_ x`.
+ ///
+ /// ```
+ /// # use proc_macro2::{self as syn, Span};
+ /// # use quote::quote;
+ /// #
+ /// # let ident = syn::Ident::new("i", Span::call_site());
+ /// #
+ /// // incorrect
+ /// quote! {
+ /// let mut _#ident = 0;
+ /// }
+ /// # ;
+ /// ```
+ ///
+ /// The solution is to build a new identifier token with the correct value. As
+ /// this is such a common case, the [`format_ident!`] macro provides a
+ /// convenient utility for doing so correctly.
+ ///
+ /// ```
+ /// # use proc_macro2::{Ident, Span};
+ /// # use quote::{format_ident, quote};
+ /// #
+ /// # let ident = Ident::new("i", Span::call_site());
+ /// #
+ /// let varname = format_ident!("_{}", ident);
+ /// quote! {
+ /// let mut #varname = 0;
+ /// }
+ /// # ;
+ /// ```
+ ///
+ /// Alternatively, the APIs provided by Syn and proc-macro2 can be used to
+ /// directly build the identifier. This is roughly equivalent to the above, but
+ /// will not handle `ident` being a raw identifier.
+ ///
+ /// ```
+ /// # use proc_macro2::{self as syn, Span};
+ /// # use quote::quote;
+ /// #
+ /// # let ident = syn::Ident::new("i", Span::call_site());
+ /// #
+ /// let concatenated = format!("_{}", ident);
+ /// let varname = syn::Ident::new(&concatenated, ident.span());
+ /// quote! {
+ /// let mut #varname = 0;
+ /// }
+ /// # ;
+ /// ```
+ ///
+ /// <p><br></p>
+ ///
+ /// ### Making method calls
+ ///
+ /// Let's say our macro requires some type specified in the macro input to have
+ /// a constructor called `new`. We have the type in a variable called
+ /// `field_type` of type `syn::Type` and want to invoke the constructor.
+ ///
+ /// ```
+ /// # use quote::quote;
+ /// #
+ /// # let field_type = quote!(...);
+ /// #
+ /// // incorrect
+ /// quote! {
+ /// let value = #field_type::new();
+ /// }
+ /// # ;
+ /// ```
+ ///
+ /// This works only sometimes. If `field_type` is `String`, the expanded code
+ /// contains `String::new()` which is fine. But if `field_type` is something
+ /// like `Vec<i32>` then the expanded code is `Vec<i32>::new()` which is invalid
+ /// syntax. Ordinarily in handwritten Rust we would write `Vec::<i32>::new()`
+ /// but for macros often the following is more convenient.
+ ///
+ /// ```
+ /// # use quote::quote;
+ /// #
+ /// # let field_type = quote!(...);
+ /// #
+ /// quote! {
+ /// let value = <#field_type>::new();
+ /// }
+ /// # ;
+ /// ```
+ ///
+ /// This expands to `<Vec<i32>>::new()` which behaves correctly.
+ ///
+ /// A similar pattern is appropriate for trait methods.
+ ///
+ /// ```
+ /// # use quote::quote;
+ /// #
+ /// # let field_type = quote!(...);
+ /// #
+ /// quote! {
+ /// let value = <#field_type as core::default::Default>::default();
+ /// }
+ /// # ;
+ /// ```
+ ///
+ /// <p><br></p>
+ ///
+ /// ### Interpolating text inside of doc comments
+ ///
+ /// Neither doc comments nor string literals get interpolation behavior in
+ /// quote:
+ ///
+ /// ```compile_fail
+ /// quote! {
+ /// /// try to interpolate: #ident
+ /// ///
+ /// /// ...
+ /// }
+ /// ```
+ ///
+ /// ```compile_fail
+ /// quote! {
+ /// #[doc = "try to interpolate: #ident"]
+ /// }
+ /// ```
+ ///
+ /// Instead the best way to build doc comments that involve variables is by
+ /// formatting the doc string literal outside of quote.
+ ///
+ /// ```rust
+ /// # use proc_macro2::{Ident, Span};
+ /// # use quote::quote;
+ /// #
+ /// # const IGNORE: &str = stringify! {
+ /// let msg = format!(...);
+ /// # };
+ /// #
+ /// # let ident = Ident::new("var", Span::call_site());
+ /// # let msg = format!("try to interpolate: {}", ident);
+ /// quote! {
+ /// #[doc = #msg]
+ /// ///
+ /// /// ...
+ /// }
+ /// # ;
+ /// ```
+ ///
+ /// <p><br></p>
+ ///
+ /// ### Indexing into a tuple struct
+ ///
+ /// When interpolating indices of a tuple or tuple struct, we need them not to
+ /// appears suffixed as integer literals by interpolating them as [`syn::Index`]
+ /// instead.
+ ///
+ /// [`syn::Index`]: https://docs.rs/syn/2.0/syn/struct.Index.html
+ ///
+ /// ```compile_fail
+ /// let i = 0usize..self.fields.len();
+ ///
+ /// // expands to 0 + self.0usize.heap_size() + self.1usize.heap_size() + ...
+ /// // which is not valid syntax
+ /// quote! {
+ /// 0 #( + self.#i.heap_size() )*
+ /// }
+ /// ```
+ ///
+ /// ```
+ /// # use proc_macro2::{Ident, TokenStream};
+ /// # use quote::quote;
+ /// #
+ /// # mod syn {
+ /// # use proc_macro2::{Literal, TokenStream};
+ /// # use quote::{ToTokens, TokenStreamExt};
+ /// #
+ /// # pub struct Index(usize);
+ /// #
+ /// # impl From<usize> for Index {
+ /// # fn from(i: usize) -> Self {
+ /// # Index(i)
+ /// # }
+ /// # }
+ /// #
+ /// # impl ToTokens for Index {
+ /// # fn to_tokens(&self, tokens: &mut TokenStream) {
+ /// # tokens.append(Literal::usize_unsuffixed(self.0));
+ /// # }
+ /// # }
+ /// # }
+ /// #
+ /// # struct Struct {
+ /// # fields: Vec<Ident>,
+ /// # }
+ /// #
+ /// # impl Struct {
+ /// # fn example(&self) -> TokenStream {
+ /// let i = (0..self.fields.len()).map(syn::Index::from);
+ ///
+ /// // expands to 0 + self.0.heap_size() + self.1.heap_size() + ...
+ /// quote! {
+ /// 0 #( + self.#i.heap_size() )*
+ /// }
+ /// # }
+ /// # }
+ /// ```
+ $quote
};
}
-#[cfg(not(doc))]
-#[macro_export]
-macro_rules! quote {
- () => {
- $crate::__private::TokenStream::new()
- };
-
- // Special case rule for a single tt, for performance.
- ($tt:tt) => {{
- let mut _s = $crate::__private::TokenStream::new();
- $crate::quote_token!{$tt _s}
- _s
- }};
+#[cfg(doc)]
+__quote![
+ #[macro_export]
+ macro_rules! quote {
+ ($($tt:tt)*) => {
+ ...
+ };
+ }
+];
- // Special case rules for two tts, for performance.
- (# $var:ident) => {{
- let mut _s = $crate::__private::TokenStream::new();
- $crate::ToTokens::to_tokens(&$var, &mut _s);
- _s
- }};
- ($tt1:tt $tt2:tt) => {{
- let mut _s = $crate::__private::TokenStream::new();
- $crate::quote_token!{$tt1 _s}
- $crate::quote_token!{$tt2 _s}
- _s
- }};
+#[cfg(not(doc))]
+__quote![
+ #[macro_export]
+ macro_rules! quote {
+ () => {
+ $crate::__private::TokenStream::new()
+ };
- // Rule for any other number of tokens.
- ($($tt:tt)*) => {{
- let mut _s = $crate::__private::TokenStream::new();
- $crate::quote_each_token!{_s $($tt)*}
- _s
- }};
+ // Special case rule for a single tt, for performance.
+ ($tt:tt) => {{
+ let mut _s = $crate::__private::TokenStream::new();
+ $crate::quote_token!{$tt _s}
+ _s
+ }};
+
+ // Special case rules for two tts, for performance.
+ (# $var:ident) => {{
+ let mut _s = $crate::__private::TokenStream::new();
+ $crate::ToTokens::to_tokens(&$var, &mut _s);
+ _s
+ }};
+ ($tt1:tt $tt2:tt) => {{
+ let mut _s = $crate::__private::TokenStream::new();
+ $crate::quote_token!{$tt1 _s}
+ $crate::quote_token!{$tt2 _s}
+ _s
+ }};
+
+ // Rule for any other number of tokens.
+ ($($tt:tt)*) => {{
+ let mut _s = $crate::__private::TokenStream::new();
+ $crate::quote_each_token!{_s $($tt)*}
+ _s
+ }};
+ }
+];
+
+macro_rules! __quote_spanned {
+ ($quote_spanned:item) => {
+ /// Same as `quote!`, but applies a given span to all tokens originating within
+ /// the macro invocation.
+ ///
+ /// <br>
+ ///
+ /// # Syntax
+ ///
+ /// A span expression of type [`Span`], followed by `=>`, followed by the tokens
+ /// to quote. The span expression should be brief &mdash; use a variable for
+ /// anything more than a few characters. There should be no space before the
+ /// `=>` token.
+ ///
+ /// [`Span`]: https://docs.rs/proc-macro2/1.0/proc_macro2/struct.Span.html
+ ///
+ /// ```
+ /// # use proc_macro2::Span;
+ /// # use quote::quote_spanned;
+ /// #
+ /// # const IGNORE_TOKENS: &'static str = stringify! {
+ /// let span = /* ... */;
+ /// # };
+ /// # let span = Span::call_site();
+ /// # let init = 0;
+ ///
+ /// // On one line, use parentheses.
+ /// let tokens = quote_spanned!(span=> Box::into_raw(Box::new(#init)));
+ ///
+ /// // On multiple lines, place the span at the top and use braces.
+ /// let tokens = quote_spanned! {span=>
+ /// Box::into_raw(Box::new(#init))
+ /// };
+ /// ```
+ ///
+ /// The lack of space before the `=>` should look jarring to Rust programmers
+ /// and this is intentional. The formatting is designed to be visibly
+ /// off-balance and draw the eye a particular way, due to the span expression
+ /// being evaluated in the context of the procedural macro and the remaining
+ /// tokens being evaluated in the generated code.
+ ///
+ /// <br>
+ ///
+ /// # Hygiene
+ ///
+ /// Any interpolated tokens preserve the `Span` information provided by their
+ /// `ToTokens` implementation. Tokens that originate within the `quote_spanned!`
+ /// invocation are spanned with the given span argument.
+ ///
+ /// <br>
+ ///
+ /// # Example
+ ///
+ /// The following procedural macro code uses `quote_spanned!` to assert that a
+ /// particular Rust type implements the [`Sync`] trait so that references can be
+ /// safely shared between threads.
+ ///
+ /// [`Sync`]: https://doc.rust-lang.org/std/marker/trait.Sync.html
+ ///
+ /// ```
+ /// # use quote::{quote_spanned, TokenStreamExt, ToTokens};
+ /// # use proc_macro2::{Span, TokenStream};
+ /// #
+ /// # struct Type;
+ /// #
+ /// # impl Type {
+ /// # fn span(&self) -> Span {
+ /// # Span::call_site()
+ /// # }
+ /// # }
+ /// #
+ /// # impl ToTokens for Type {
+ /// # fn to_tokens(&self, _tokens: &mut TokenStream) {}
+ /// # }
+ /// #
+ /// # let ty = Type;
+ /// # let call_site = Span::call_site();
+ /// #
+ /// let ty_span = ty.span();
+ /// let assert_sync = quote_spanned! {ty_span=>
+ /// struct _AssertSync where #ty: Sync;
+ /// };
+ /// ```
+ ///
+ /// If the assertion fails, the user will see an error like the following. The
+ /// input span of their type is highlighted in the error.
+ ///
+ /// ```text
+ /// error[E0277]: the trait bound `*const (): std::marker::Sync` is not satisfied
+ /// --> src/main.rs:10:21
+ /// |
+ /// 10 | static ref PTR: *const () = &();
+ /// | ^^^^^^^^^ `*const ()` cannot be shared between threads safely
+ /// ```
+ ///
+ /// In this example it is important for the where-clause to be spanned with the
+ /// line/column information of the user's input type so that error messages are
+ /// placed appropriately by the compiler.
+ $quote_spanned
+ };
}
-/// Same as `quote!`, but applies a given span to all tokens originating within
-/// the macro invocation.
-///
-/// <br>
-///
-/// # Syntax
-///
-/// A span expression of type [`Span`], followed by `=>`, followed by the tokens
-/// to quote. The span expression should be brief &mdash; use a variable for
-/// anything more than a few characters. There should be no space before the
-/// `=>` token.
-///
-/// [`Span`]: https://docs.rs/proc-macro2/1.0/proc_macro2/struct.Span.html
-///
-/// ```
-/// # use proc_macro2::Span;
-/// # use quote::quote_spanned;
-/// #
-/// # const IGNORE_TOKENS: &'static str = stringify! {
-/// let span = /* ... */;
-/// # };
-/// # let span = Span::call_site();
-/// # let init = 0;
-///
-/// // On one line, use parentheses.
-/// let tokens = quote_spanned!(span=> Box::into_raw(Box::new(#init)));
-///
-/// // On multiple lines, place the span at the top and use braces.
-/// let tokens = quote_spanned! {span=>
-/// Box::into_raw(Box::new(#init))
-/// };
-/// ```
-///
-/// The lack of space before the `=>` should look jarring to Rust programmers
-/// and this is intentional. The formatting is designed to be visibly
-/// off-balance and draw the eye a particular way, due to the span expression
-/// being evaluated in the context of the procedural macro and the remaining
-/// tokens being evaluated in the generated code.
-///
-/// <br>
-///
-/// # Hygiene
-///
-/// Any interpolated tokens preserve the `Span` information provided by their
-/// `ToTokens` implementation. Tokens that originate within the `quote_spanned!`
-/// invocation are spanned with the given span argument.
-///
-/// <br>
-///
-/// # Example
-///
-/// The following procedural macro code uses `quote_spanned!` to assert that a
-/// particular Rust type implements the [`Sync`] trait so that references can be
-/// safely shared between threads.
-///
-/// [`Sync`]: https://doc.rust-lang.org/std/marker/trait.Sync.html
-///
-/// ```
-/// # use quote::{quote_spanned, TokenStreamExt, ToTokens};
-/// # use proc_macro2::{Span, TokenStream};
-/// #
-/// # struct Type;
-/// #
-/// # impl Type {
-/// # fn span(&self) -> Span {
-/// # Span::call_site()
-/// # }
-/// # }
-/// #
-/// # impl ToTokens for Type {
-/// # fn to_tokens(&self, _tokens: &mut TokenStream) {}
-/// # }
-/// #
-/// # let ty = Type;
-/// # let call_site = Span::call_site();
-/// #
-/// let ty_span = ty.span();
-/// let assert_sync = quote_spanned! {ty_span=>
-/// struct _AssertSync where #ty: Sync;
-/// };
-/// ```
-///
-/// If the assertion fails, the user will see an error like the following. The
-/// input span of their type is highlighted in the error.
-///
-/// ```text
-/// error[E0277]: the trait bound `*const (): std::marker::Sync` is not satisfied
-/// --> src/main.rs:10:21
-/// |
-/// 10 | static ref PTR: *const () = &();
-/// | ^^^^^^^^^ `*const ()` cannot be shared between threads safely
-/// ```
-///
-/// In this example it is important for the where-clause to be spanned with the
-/// line/column information of the user's input type so that error messages are
-/// placed appropriately by the compiler.
#[cfg(doc)]
-#[macro_export]
-macro_rules! quote_spanned {
- ($span:expr=> $($tt:tt)*) => {
- ...
- };
-}
+__quote_spanned![
+ #[macro_export]
+ macro_rules! quote_spanned {
+ ($span:expr=> $($tt:tt)*) => {
+ ...
+ };
+ }
+];
#[cfg(not(doc))]
-#[macro_export]
-macro_rules! quote_spanned {
- ($span:expr=>) => {{
- let _: $crate::__private::Span = $crate::__private::get_span($span).__into_span();
- $crate::__private::TokenStream::new()
- }};
-
- // Special case rule for a single tt, for performance.
- ($span:expr=> $tt:tt) => {{
- let mut _s = $crate::__private::TokenStream::new();
- let _span: $crate::__private::Span = $crate::__private::get_span($span).__into_span();
- $crate::quote_token_spanned!{$tt _s _span}
- _s
- }};
-
- // Special case rules for two tts, for performance.
- ($span:expr=> # $var:ident) => {{
- let mut _s = $crate::__private::TokenStream::new();
- let _: $crate::__private::Span = $crate::__private::get_span($span).__into_span();
- $crate::ToTokens::to_tokens(&$var, &mut _s);
- _s
- }};
- ($span:expr=> $tt1:tt $tt2:tt) => {{
- let mut _s = $crate::__private::TokenStream::new();
- let _span: $crate::__private::Span = $crate::__private::get_span($span).__into_span();
- $crate::quote_token_spanned!{$tt1 _s _span}
- $crate::quote_token_spanned!{$tt2 _s _span}
- _s
- }};
-
- // Rule for any other number of tokens.
- ($span:expr=> $($tt:tt)*) => {{
- let mut _s = $crate::__private::TokenStream::new();
- let _span: $crate::__private::Span = $crate::__private::get_span($span).__into_span();
- $crate::quote_each_token_spanned!{_s _span $($tt)*}
- _s
- }};
-}
+__quote_spanned![
+ #[macro_export]
+ macro_rules! quote_spanned {
+ ($span:expr=>) => {{
+ let _: $crate::__private::Span = $crate::__private::get_span($span).__into_span();
+ $crate::__private::TokenStream::new()
+ }};
+
+ // Special case rule for a single tt, for performance.
+ ($span:expr=> $tt:tt) => {{
+ let mut _s = $crate::__private::TokenStream::new();
+ let _span: $crate::__private::Span = $crate::__private::get_span($span).__into_span();
+ $crate::quote_token_spanned!{$tt _s _span}
+ _s
+ }};
+
+ // Special case rules for two tts, for performance.
+ ($span:expr=> # $var:ident) => {{
+ let mut _s = $crate::__private::TokenStream::new();
+ let _: $crate::__private::Span = $crate::__private::get_span($span).__into_span();
+ $crate::ToTokens::to_tokens(&$var, &mut _s);
+ _s
+ }};
+ ($span:expr=> $tt1:tt $tt2:tt) => {{
+ let mut _s = $crate::__private::TokenStream::new();
+ let _span: $crate::__private::Span = $crate::__private::get_span($span).__into_span();
+ $crate::quote_token_spanned!{$tt1 _s _span}
+ $crate::quote_token_spanned!{$tt2 _s _span}
+ _s
+ }};
+
+ // Rule for any other number of tokens.
+ ($span:expr=> $($tt:tt)*) => {{
+ let mut _s = $crate::__private::TokenStream::new();
+ let _span: $crate::__private::Span = $crate::__private::get_span($span).__into_span();
+ $crate::quote_each_token_spanned!{_s _span $($tt)*}
+ _s
+ }};
+ }
+];
// Extract the names of all #metavariables and pass them to the $call macro.
//
diff --git a/tests/ui/not-quotable.stderr b/tests/ui/not-quotable.stderr
index 35cb6f2..7bd2070 100644
--- a/tests/ui/not-quotable.stderr
+++ b/tests/ui/not-quotable.stderr
@@ -8,13 +8,13 @@ error[E0277]: the trait bound `Ipv4Addr: ToTokens` is not satisfied
| required by a bound introduced by this call
|
= help: the following other types implement trait `ToTokens`:
- bool
- char
- isize
- i8
- i16
- i32
- i64
- i128
+ &'a T
+ &'a mut T
+ Box<T>
+ Cow<'a, T>
+ Option<T>
+ Rc<T>
+ RepInterp<T>
+ String
and $N others
= note: this error originates in the macro `quote` (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
index 2ed1da0..26932bb 100644
--- a/tests/ui/not-repeatable.stderr
+++ b/tests/ui/not-repeatable.stderr
@@ -2,13 +2,7 @@ error[E0599]: the method `quote_into_iter` exists for struct `Ipv4Addr`, but its
--> tests/ui/not-repeatable.rs:7:13
|
3 | struct Ipv4Addr;
- | ---------------
- | |
- | method `quote_into_iter` not found for this struct
- | doesn't satisfy `Ipv4Addr: Iterator`
- | doesn't satisfy `Ipv4Addr: ToTokens`
- | doesn't satisfy `Ipv4Addr: ext::RepIteratorExt`
- | doesn't satisfy `Ipv4Addr: ext::RepToTokensExt`
+ | --------------- method `quote_into_iter` not found for this struct because it doesn't satisfy `Ipv4Addr: Iterator`, `Ipv4Addr: ToTokens`, `Ipv4Addr: ext::RepIteratorExt` or `Ipv4Addr: ext::RepToTokensExt`
...
7 | let _ = quote! { #(#ip)* };
| ^^^^^^^^^^^^^^^^^^ method cannot be called on `Ipv4Addr` due to unsatisfied trait bounds
@@ -22,7 +16,7 @@ error[E0599]: the method `quote_into_iter` exists for struct `Ipv4Addr`, but its
which is required by `Ipv4Addr: ext::RepToTokensExt`
`&mut Ipv4Addr: Iterator`
which is required by `&mut Ipv4Addr: ext::RepIteratorExt`
-note: the traits `ToTokens` and `Iterator` must be implemented
+note: the traits `Iterator` and `ToTokens` must be implemented
--> src/to_tokens.rs
|
| pub trait ToTokens {
@@ -32,4 +26,9 @@ note: the traits `ToTokens` and `Iterator` must be implemented
|
| pub trait Iterator {
| ^^^^^^^^^^^^^^^^^^
+ = help: items from traits can only be used if the trait is implemented and in scope
+ = note: the following traits define an item `quote_into_iter`, perhaps you need to implement one of them:
+ candidate #1: `ext::RepAsIteratorExt`
+ candidate #2: `ext::RepIteratorExt`
+ candidate #3: `ext::RepToTokensExt`
= note: this error originates in the macro `$crate::quote_bind_into_iter` which comes from the expansion of the macro `quote` (in Nightly builds, run with -Z macro-backtrace for more info)