Repository: dtolnay/syn
Pull request #629 (2019-04-30 23:05:04)

Tentative beginning to implementing Parse for Expr types
For the various syn::ExprFoo types, some of them implement Parse (e.g. ExprMatch) but most don't. For people writing parsers with syn, it seems to be nice to allow people to write e.g. `let range = syn::parse_macro_input!(item as syn::ExprRange);`, which bypasses the need to parse as Expr and manually match on the variant. The intended use case here is the new feature in Rust 1.34 that allows the argument to proc macros to be any token tree, which will lead to defining trivial parsers for custom syntaxes like `#[foo(1..5, 10..15)]`. The most straightforward way to implement Parse for these types is by simply parsing the input as an Expr and manually returning the data stored in the variant (which is already of the proper type), and returning an Err when encountering an unexpected variant. I wasn't sure if this kind of trivial implementation would be considered "too easy" (as opposed to breaking up the logic in `parse_expr` into each individual type's Parse impl and having `parse_expr` call each impl as needed, but I wasn't sure if this might lead to dangerously deep call trees), so I've only done this for one type (ExprRange) and added a new test. If this looks good then I can do the remainder easily.


Patch:
diff --git a/Cargo.toml b/Cargo.toml
index 6658cc8c..e1a3e428 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -1,6 +1,6 @@
 [package]
 name = "syn"
-version = "0.15.33" # don't forget to update html_root_url and syn.json
+version = "0.15.31" # don't forget to update html_root_url and syn.json
 authors = ["David Tolnay <dtolnay@gmail.com>"]
 license = "MIT/Apache-2.0"
 description = "Parser for Rust source code"
diff --git a/build.rs b/build.rs
index 2b2a4196..644bf75f 100644
--- a/build.rs
+++ b/build.rs
@@ -15,10 +15,6 @@ fn main() {
         println!("cargo:rustc-cfg=syn_can_use_thread_id");
     }
 
-    if compiler.minor >= 20 {
-        println!("cargo:rustc-cfg=syn_can_use_associated_constants");
-    }
-
     // Macro modularization allows re-exporting the `quote!` macro in 1.30+.
     if compiler.minor >= 30 {
         println!("cargo:rustc-cfg=syn_can_call_macro_by_path");
diff --git a/dev/README.md b/dev/README.md
deleted file mode 100644
index 91b98460..00000000
--- a/dev/README.md
+++ /dev/null
@@ -1,6 +0,0 @@
-A little project skeleton for troubleshooting Syn's parsers during development,
-especially when adding support for new Rust syntax.
-
-Place a sample of the syntax you are working on into main.rs and then run `cargo
-check` to try parsing it, revealing the resulting syntax tree or else showing
-the position and error message if the input fails to parse.
diff --git a/examples/heapsize/README.md b/examples/heapsize/README.md
index a1f32d96..1e36baf6 100644
--- a/examples/heapsize/README.md
+++ b/examples/heapsize/README.md
@@ -31,12 +31,12 @@ struct Demo<'a, T: ?Sized> {
 The trait impl generated by the custom derive here would look like:
 
 ```rust
-impl<'a, T: ?Sized + heapsize::HeapSize> heapsize::HeapSize for Demo<'a, T> {
+impl<'a, T: ?Sized + ::heapsize::HeapSize> ::heapsize::HeapSize for Demo<'a, T> {
     fn heap_size_of_children(&self) -> usize {
-        0 + heapsize::HeapSize::heap_size_of_children(&self.a)
-            + heapsize::HeapSize::heap_size_of_children(&self.b)
-            + heapsize::HeapSize::heap_size_of_children(&self.c)
-            + heapsize::HeapSize::heap_size_of_children(&self.d)
+        0 + ::heapsize::HeapSize::heap_size_of_children(&self.a)
+            + ::heapsize::HeapSize::heap_size_of_children(&self.b)
+            + ::heapsize::HeapSize::heap_size_of_children(&self.c)
+            + ::heapsize::HeapSize::heap_size_of_children(&self.d)
     }
 }
 ```
diff --git a/examples/heapsize/heapsize_derive/src/lib.rs b/examples/heapsize/heapsize_derive/src/lib.rs
index 9176b29a..ad9bb489 100644
--- a/examples/heapsize/heapsize_derive/src/lib.rs
+++ b/examples/heapsize/heapsize_derive/src/lib.rs
@@ -22,7 +22,7 @@ pub fn derive_heap_size(input: proc_macro::TokenStream) -> proc_macro::TokenStre
 
     let expanded = quote! {
         // The generated impl.
-        impl #impl_generics heapsize::HeapSize for #name #ty_generics #where_clause {
+        impl #impl_generics ::heapsize::HeapSize for #name #ty_generics #where_clause {
             fn heap_size_of_children(&self) -> usize {
                 #sum
             }
@@ -37,7 +37,7 @@ pub fn derive_heap_size(input: proc_macro::TokenStream) -> proc_macro::TokenStre
 fn add_trait_bounds(mut generics: Generics) -> Generics {
     for param in &mut generics.params {
         if let GenericParam::Type(ref mut type_param) = *param {
-            type_param.bounds.push(parse_quote!(heapsize::HeapSize));
+            type_param.bounds.push(parse_quote!(::heapsize::HeapSize));
         }
     }
     generics
@@ -64,7 +64,7 @@ fn heap_size_sum(data: &Data) -> TokenStream {
                     let recurse = fields.named.iter().map(|f| {
                         let name = &f.ident;
                         quote_spanned! {f.span()=>
-                            heapsize::HeapSize::heap_size_of_children(&self.#name)
+                            ::heapsize::HeapSize::heap_size_of_children(&self.#name)
                         }
                     });
                     quote! {
@@ -78,7 +78,7 @@ fn heap_size_sum(data: &Data) -> TokenStream {
                     let recurse = fields.unnamed.iter().enumerate().map(|(i, f)| {
                         let index = Index::from(i);
                         quote_spanned! {f.span()=>
-                            heapsize::HeapSize::heap_size_of_children(&self.#index)
+                            ::heapsize::HeapSize::heap_size_of_children(&self.#index)
                         }
                     });
                     quote! {
diff --git a/examples/lazy-static/lazy-static/src/lib.rs b/examples/lazy-static/lazy-static/src/lib.rs
index 5481a30a..f90ea8be 100644
--- a/examples/lazy-static/lazy-static/src/lib.rs
+++ b/examples/lazy-static/lazy-static/src/lib.rs
@@ -98,7 +98,7 @@ pub fn lazy_static(input: TokenStream) -> TokenStream {
     //     10 |     static ref PTR: *const () = &();
     //        |                     ^^^^^^^^^ `*const ()` cannot be shared between threads safely
     let assert_sync = quote_spanned! {ty.span()=>
-        struct _AssertSync where #ty: std::marker::Sync;
+        struct _AssertSync where #ty: ::std::marker::Sync;
     };
 
     // Check for Sized. Not vital to check here, but the error message is less
@@ -111,7 +111,7 @@ pub fn lazy_static(input: TokenStream) -> TokenStream {
     //     10 |     static ref A: str = "";
     //        |                   ^^^ `str` does not have a constant size known at compile-time
     let assert_sized = quote_spanned! {ty.span()=>
-        struct _AssertSized where #ty: std::marker::Sized;
+        struct _AssertSized where #ty: ::std::marker::Sized;
     };
 
     let init_ptr = quote_spanned! {init.span()=>
@@ -121,14 +121,14 @@ pub fn lazy_static(input: TokenStream) -> TokenStream {
     let expanded = quote! {
         #visibility struct #name;
 
-        impl std::ops::Deref for #name {
+        impl ::std::ops::Deref for #name {
             type Target = #ty;
 
             fn deref(&self) -> &#ty {
                 #assert_sync
                 #assert_sized
 
-                static ONCE: std::sync::Once = std::sync::ONCE_INIT;
+                static ONCE: ::std::sync::Once = ::std::sync::ONCE_INIT;
                 static mut VALUE: *mut #ty = 0 as *mut #ty;
 
                 unsafe {
diff --git a/src/attr.rs b/src/attr.rs
index ae90eaa3..d1e7dca7 100644
--- a/src/attr.rs
+++ b/src/attr.rs
@@ -133,8 +133,8 @@ impl Hash for Attribute {
 }
 
 impl Attribute {
-    /// Parses the content of the attribute, consisting of the path and tts, as
-    /// a [`Meta`](enum.Meta.html) if possible.
+    /// Parses the tokens after the path as a [`Meta`](enum.Meta.html) if
+    /// possible.
     ///
     /// Deprecated; use `parse_meta` instead.
     #[doc(hidden)]
@@ -174,8 +174,8 @@ impl Attribute {
         }
     }
 
-    /// Parses the content of the attribute, consisting of the path and tts, as
-    /// a [`Meta`](enum.Meta.html) if possible.
+    /// Parses the tokens after the path as a [`Meta`](enum.Meta.html) if
+    /// possible.
     #[cfg(feature = "parsing")]
     pub fn parse_meta(&self) -> Result<Meta> {
         if let Some(ref colon) = self.path.leading_colon {
diff --git a/src/error.rs b/src/error.rs
index 097a6b84..e07051d6 100644
--- a/src/error.rs
+++ b/src/error.rs
@@ -1,5 +1,5 @@
 use std;
-use std::fmt::{self, Debug, Display};
+use std::fmt::{self, Display};
 use std::iter::FromIterator;
 
 use proc_macro2::{
@@ -24,6 +24,7 @@ pub type Result<T> = std::result::Result<T, Error>;
 /// [module documentation]: index.html
 ///
 /// *This type is available if Syn is built with the `"parsing"` feature.*
+#[derive(Debug)]
 pub struct Error {
     // Span is implemented as an index into a thread-local interner to keep the
     // size small. It is not safe to access from a different thread. We want
@@ -180,12 +181,6 @@ pub fn new_at<T: Display>(scope: Span, cursor: Cursor, message: T) -> Error {
     }
 }
 
-impl Debug for Error {
-    fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
-        formatter.debug_tuple("Error").field(&self.message).finish()
-    }
-}
-
 impl Display for Error {
     fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
         formatter.write_str(&self.message)
diff --git a/src/expr.rs b/src/expr.rs
index ce12cea6..b050e59d 100644
--- a/src/expr.rs
+++ b/src/expr.rs
@@ -36,10 +36,9 @@ ast_enum_of_structs! {
     ///     Expr::If(expr) => {
     ///         /* ... */
     ///     }
-    ///
     ///     /* ... */
     ///     # _ => {}
-    /// # }
+    /// }
     /// # }
     /// ```
     ///
@@ -51,15 +50,28 @@ ast_enum_of_structs! {
     /// `expr.receiver`, `expr.args` etc; if we ended up in the `If` case we get
     /// to use `expr.cond`, `expr.then_branch`, `expr.else_branch`.
     ///
+    /// The pattern is similar if the input expression is borrowed:
+    ///
+    /// ```edition2018
+    /// # use syn::Expr;
+    /// #
+    /// # fn example(expr: &Expr) {
+    /// match *expr {
+    ///     Expr::MethodCall(ref expr) => {
+    /// #   }
+    /// #   _ => {}
+    /// # }
+    /// # }
+    /// ```
+    ///
     /// This approach avoids repeating the variant names twice on every line.
     ///
     /// ```edition2018
     /// # use syn::{Expr, ExprMethodCall};
     /// #
     /// # fn example(expr: Expr) {
-    /// // Repetitive; recommend not doing this.
-    /// match expr {
-    ///     Expr::MethodCall(ExprMethodCall { method, args, .. }) => {
+    /// # match expr {
+    /// Expr::MethodCall(ExprMethodCall { method, args, .. }) => { // repetitive
     /// # }
     /// # _ => {}
     /// # }
@@ -72,10 +84,10 @@ ast_enum_of_structs! {
     /// ```edition2018
     /// # use syn::{Expr, ExprField};
     /// #
-    /// # fn example(discriminant: ExprField) {
+    /// # fn example(discriminant: &ExprField) {
     /// // Binding is called `base` which is the name I would use if I were
     /// // assigning `*discriminant.base` without an `if let`.
-    /// if let Expr::Tuple(base) = *discriminant.base {
+    /// if let Expr::Tuple(ref base) = *discriminant.base {
     /// # }
     /// # }
     /// ```
@@ -1897,6 +1909,56 @@ pub mod parsing {
         }
     }
 
+    macro_rules! impl_by_parsing_expr {
+        ($expr_type:ty, $variant:ident, $msg:expr) => (
+            #[cfg(all(feature = "full", feature = "printing"))]
+            impl Parse for $expr_type {
+                fn parse(input: ParseStream) -> Result<Self> {
+                    let mut expr: Expr = input.parse()?;
+                    loop {
+                        match expr {
+                            Expr::$variant(inner) => return Ok(inner),
+                            Expr::Group(ExprGroup { expr: next, .. }) => expr = *next,
+                            _ => return Err(Error::new_spanned(expr, $msg))
+                        }
+                    }
+                }
+            }
+        )
+    }
+
+    impl_by_parsing_expr!(ExprBox, Box, "expected box expression");
+    impl_by_parsing_expr!(ExprInPlace, InPlace, "expected placement expression");
+    impl_by_parsing_expr!(ExprArray, Array, "expected slice literal expression");
+    impl_by_parsing_expr!(ExprCall, Call, "expected function call expression");
+    impl_by_parsing_expr!(ExprMethodCall, MethodCall, "expected method call expression");
+    impl_by_parsing_expr!(ExprTuple, Tuple, "expected tuple expression");
+    impl_by_parsing_expr!(ExprBinary, Binary, "expected binary operation");
+    impl_by_parsing_expr!(ExprUnary, Unary, "expected unary operation");
+    impl_by_parsing_expr!(ExprCast, Cast, "expected cast expression");
+    impl_by_parsing_expr!(ExprType, Type, "expected type ascription expression");
+    impl_by_parsing_expr!(ExprLet, Let, "expected let guard");
+    impl_by_parsing_expr!(ExprClosure, Closure, "expected closure expression");
+    impl_by_parsing_expr!(ExprUnsafe, Unsafe, "expected unsafe block");
+    impl_by_parsing_expr!(ExprBlock, Block, "expected blocked scope");
+    impl_by_parsing_expr!(ExprAssign, Assign, "expected assignment expression");
+    impl_by_parsing_expr!(ExprAssignOp, AssignOp, "expected compound assignment expression");
+    impl_by_parsing_expr!(ExprField, Field, "expected struct field access");
+    impl_by_parsing_expr!(ExprIndex, Index, "expected indexing expression");
+    impl_by_parsing_expr!(ExprRange, Range, "expected range expression");
+    impl_by_parsing_expr!(ExprReference, Reference, "expected referencing operation");
+    impl_by_parsing_expr!(ExprBreak, Break, "expected break expression");
+    impl_by_parsing_expr!(ExprContinue, Continue, "expected continue expression");
+    impl_by_parsing_expr!(ExprReturn, Return, "expected return expression");
+    impl_by_parsing_expr!(ExprMacro, Macro, "expected macro invocation expression");
+    impl_by_parsing_expr!(ExprStruct, Struct, "expected struct literal expression");
+    impl_by_parsing_expr!(ExprRepeat, Repeat, "expected array literal constructed from one repeated element");
+    impl_by_parsing_expr!(ExprParen, Paren, "expected parenthesized expression");
+    impl_by_parsing_expr!(ExprTry, Try, "expected try expression");
+    impl_by_parsing_expr!(ExprAsync, Async, "expected async block");
+    impl_by_parsing_expr!(ExprTryBlock, TryBlock, "expected try block");
+    impl_by_parsing_expr!(ExprYield, Yield, "expected yield expression");
+
     #[cfg(feature = "full")]
     fn expr_try_block(input: ParseStream) -> Result<ExprTryBlock> {
         Ok(ExprTryBlock {
diff --git a/src/ext.rs b/src/ext.rs
index 17721d56..ca6d70d2 100644
--- a/src/ext.rs
+++ b/src/ext.rs
@@ -6,38 +6,22 @@ use proc_macro2::Ident;
 
 use parse::{ParseStream, Result};
 
-#[cfg(syn_can_use_associated_constants)]
-use buffer::Cursor;
-#[cfg(syn_can_use_associated_constants)]
-use parse::Peek;
-#[cfg(syn_can_use_associated_constants)]
-use sealed::lookahead;
-#[cfg(syn_can_use_associated_constants)]
-use token::CustomToken;
-
-/// Additional methods for `Ident` not provided by proc-macro2 or libproc_macro.
+/// Additional parsing methods for `Ident`.
 ///
-/// This trait is sealed and cannot be implemented for types outside of Syn. It
-/// is implemented only for `proc_macro2::Ident`.
+/// This trait is sealed and cannot be implemented for types outside of Syn.
 ///
 /// *This trait is available if Syn is built with the `"parsing"` feature.*
 pub trait IdentExt: Sized + private::Sealed {
     /// Parses any identifier including keywords.
     ///
-    /// This is useful when parsing macro input which allows Rust keywords as
+    /// This is useful when parsing a DSL which allows Rust keywords as
     /// identifiers.
     ///
-    /// # Example
-    ///
     /// ```edition2018
     /// use syn::{Error, Ident, Result, Token};
     /// use syn::ext::IdentExt;
     /// use syn::parse::ParseStream;
     ///
-    /// mod kw {
-    ///     syn::custom_keyword!(name);
-    /// }
-    ///
     /// // Parses input that looks like `name = NAME` where `NAME` can be
     /// // any identifier.
     /// //
@@ -46,51 +30,16 @@ pub trait IdentExt: Sized + private::Sealed {
     /// //     name = anything
     /// //     name = impl
     /// fn parse_dsl(input: ParseStream) -> Result<Ident> {
-    ///     input.parse::<kw::name>()?;
+    ///     let name_token: Ident = input.parse()?;
+    ///     if name_token != "name" {
+    ///         return Err(Error::new(name_token.span(), "expected `name`"));
+    ///     }
     ///     input.parse::<Token![=]>()?;
     ///     let name = input.call(Ident::parse_any)?;
     ///     Ok(name)
     /// }
     /// ```
     fn parse_any(input: ParseStream) -> Result<Self>;
-
-    /// Peeks any identifier including keywords. Usage:
-    /// `input.peek(Ident::peek_any)`
-    ///
-    /// This is different from `input.peek(Ident)` which only returns true in
-    /// the case of an ident which is not a Rust keyword.
-    #[cfg(syn_can_use_associated_constants)]
-    #[allow(non_upper_case_globals)]
-    const peek_any: private::PeekFn = private::PeekFn;
-
-    /// Strips the raw marker `r#`, if any, from the beginning of an ident.
-    ///
-    ///   - unraw(`x`) = `x`
-    ///   - unraw(`move`) = `move`
-    ///   - unraw(`r#move`) = `move`
-    ///
-    /// # Example
-    ///
-    /// In the case of interop with other languages like Python that have a
-    /// different set of keywords than Rust, we might come across macro input
-    /// that involves raw identifiers to refer to ordinary variables in the
-    /// other language with a name that happens to be a Rust keyword.
-    ///
-    /// The function below appends an identifier from the caller's input onto a
-    /// fixed prefix. Without using `unraw()`, this would tend to produce
-    /// invalid identifiers like `__pyo3_get_r#move`.
-    ///
-    /// ```edition2018
-    /// use proc_macro2::Span;
-    /// use syn::Ident;
-    /// use syn::ext::IdentExt;
-    ///
-    /// fn ident_for_getter(variable: &Ident) -> Ident {
-    ///     let getter = format!("__pyo3_get_{}", variable.unraw());
-    ///     Ident::new(&getter, Span::call_site())
-    /// }
-    /// ```
-    fn unraw(&self) -> Ident;
 }
 
 impl IdentExt for Ident {
@@ -100,46 +49,12 @@ impl IdentExt for Ident {
             None => Err(cursor.error("expected ident")),
         })
     }
-
-    fn unraw(&self) -> Ident {
-        let string = self.to_string();
-        if string.starts_with("r#") {
-            Ident::new(&string[2..], self.span())
-        } else {
-            self.clone()
-        }
-    }
-}
-
-#[cfg(syn_can_use_associated_constants)]
-impl Peek for private::PeekFn {
-    type Token = private::IdentAny;
-}
-
-#[cfg(syn_can_use_associated_constants)]
-impl CustomToken for private::IdentAny {
-    fn peek(cursor: Cursor) -> bool {
-        cursor.ident().is_some()
-    }
-
-    fn display() -> &'static str {
-        "identifier"
-    }
 }
 
-#[cfg(syn_can_use_associated_constants)]
-impl lookahead::Sealed for private::PeekFn {}
-
 mod private {
     use proc_macro2::Ident;
 
     pub trait Sealed {}
 
     impl Sealed for Ident {}
-
-    #[cfg(syn_can_use_associated_constants)]
-    #[derive(Copy, Clone)]
-    pub struct PeekFn;
-    #[cfg(syn_can_use_associated_constants)]
-    pub struct IdentAny;
 }
diff --git a/src/item.rs b/src/item.rs
index 118ed4e1..9b5b7eaa 100644
--- a/src/item.rs
+++ b/src/item.rs
@@ -1190,7 +1190,7 @@ pub mod parsing {
             colon_token: input.parse()?,
             ty: match input.parse::<Token![...]>() {
                 Ok(dot3) => {
-                    let args = vec![
+                    let mut args = vec![
                         TokenTree::Punct(Punct::new('.', Spacing::Joint)),
                         TokenTree::Punct(Punct::new('.', Spacing::Joint)),
                         TokenTree::Punct(Punct::new('.', Spacing::Alone)),
diff --git a/src/lib.rs b/src/lib.rs
index 49d06c24..ee867bea 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -222,7 +222,7 @@
 //!   dynamic library libproc_macro from rustc toolchain.
 
 // Syn types in rustdoc of other crates get linked to here.
-#![doc(html_root_url = "https://docs.rs/syn/0.15.33")]
+#![doc(html_root_url = "https://docs.rs/syn/0.15.31")]
 #![cfg_attr(feature = "cargo-clippy", allow(renamed_and_removed_lints))]
 #![cfg_attr(feature = "cargo-clippy", deny(clippy, clippy_pedantic))]
 // Ignored clippy lints.
@@ -540,7 +540,6 @@ pub mod export;
 
 mod custom_keyword;
 mod custom_punctuation;
-mod sealed;
 
 #[cfg(feature = "parsing")]
 mod lookahead;
diff --git a/src/lookahead.rs b/src/lookahead.rs
index 0f5afe18..8ee1554b 100644
--- a/src/lookahead.rs
+++ b/src/lookahead.rs
@@ -4,7 +4,6 @@ use proc_macro2::{Delimiter, Span};
 
 use buffer::Cursor;
 use error::{self, Error};
-use sealed::lookahead::Sealed;
 use span::IntoSpans;
 use token::Token;
 
@@ -95,8 +94,7 @@ impl<'a> Lookahead1<'a> {
     ///
     /// - `input.peek(Token![struct])`
     /// - `input.peek(Token![==])`
-    /// - `input.peek(Ident)`&emsp;*(does not accept keywords)*
-    /// - `input.peek(Ident::peek_any)`
+    /// - `input.peek(Ident)`
     /// - `input.peek(Lifetime)`
     /// - `input.peek(token::Brace)`
     pub fn peek<T: Peek>(&self, token: T) -> bool {
@@ -143,7 +141,7 @@ impl<'a> Lookahead1<'a> {
 /// This trait is sealed and cannot be implemented for types outside of Syn.
 ///
 /// [`ParseStream::peek`]: struct.ParseBuffer.html#method.peek
-pub trait Peek: Sealed {
+pub trait Peek: private::Sealed {
     // Not public API.
     #[doc(hidden)]
     type Token: Token;
@@ -165,4 +163,8 @@ pub fn is_delimiter(cursor: Cursor, delimiter: Delimiter) -> bool {
     cursor.group(delimiter).is_some()
 }
 
-impl<F: Copy + FnOnce(TokenMarker) -> T, T: Token> Sealed for F {}
+mod private {
+    use super::{Token, TokenMarker};
+    pub trait Sealed: Copy {}
+    impl<F: Copy + FnOnce(TokenMarker) -> T, T: Token> Sealed for F {}
+}
diff --git a/src/parse.rs b/src/parse.rs
index c5786e74..36f1caf3 100644
--- a/src/parse.rs
+++ b/src/parse.rs
@@ -305,8 +305,8 @@ impl<'a> Debug for ParseBuffer<'a> {
 ///     input.step(|cursor| {
 ///         let mut rest = *cursor;
 ///         while let Some((tt, next)) = rest.token_tree() {
-///             match &tt {
-///                 TokenTree::Punct(punct) if punct.as_char() == '@' => {
+///             match tt {
+///                 TokenTree::Punct(ref punct) if punct.as_char() == '@' => {
 ///                     return Ok(((), next));
 ///                 }
 ///                 _ => rest = next,
@@ -469,8 +469,7 @@ impl<'a> ParseBuffer<'a> {
     ///
     /// - `input.peek(Token![struct])`
     /// - `input.peek(Token![==])`
-    /// - `input.peek(Ident)`&emsp;*(does not accept keywords)*
-    /// - `input.peek(Ident::peek_any)`
+    /// - `input.peek(Ident)`
     /// - `input.peek(Lifetime)`
     /// - `input.peek(token::Brace)`
     ///
@@ -902,8 +901,8 @@ impl<'a> ParseBuffer<'a> {
     ///     input.step(|cursor| {
     ///         let mut rest = *cursor;
     ///         while let Some((tt, next)) = rest.token_tree() {
-    ///             match &tt {
-    ///                 TokenTree::Punct(punct) if punct.as_char() == '@' => {
+    ///             match tt {
+    ///                 TokenTree::Punct(ref punct) if punct.as_char() == '@' => {
     ///                     return Ok(((), next));
     ///                 }
     ///                 _ => rest = next,
diff --git a/src/parse_quote.rs b/src/parse_quote.rs
index 08012f5e..0b9d4d45 100644
--- a/src/parse_quote.rs
+++ b/src/parse_quote.rs
@@ -39,7 +39,7 @@
 /// // Add a bound `T: HeapSize` to every type parameter T.
 /// fn add_trait_bounds(mut generics: Generics) -> Generics {
 ///     for param in &mut generics.params {
-///         if let GenericParam::Type(type_param) = param {
+///         if let GenericParam::Type(ref mut type_param) = *param {
 ///             type_param.bounds.push(parse_quote!(HeapSize));
 ///         }
 ///     }
diff --git a/src/punctuated.rs b/src/punctuated.rs
index 5aa519ff..6b29176b 100644
--- a/src/punctuated.rs
+++ b/src/punctuated.rs
@@ -25,7 +25,6 @@ use std::fmt::{self, Debug};
 #[cfg(any(feature = "full", feature = "derive"))]
 use std::iter;
 use std::iter::FromIterator;
-use std::marker::PhantomData;
 use std::ops::{Index, IndexMut};
 use std::option;
 use std::slice;
@@ -414,13 +413,9 @@ impl<T, P> IntoIterator for Punctuated<T, P> {
     type IntoIter = IntoIter<T, P>;
 
     fn into_iter(self) -> Self::IntoIter {
-        let mut elements = Vec::with_capacity(self.len());
-        elements.extend(self.inner.into_iter().map(|pair| pair.0));
-        elements.extend(self.last.map(|t| *t));
-
         IntoIter {
-            inner: elements.into_iter(),
-            marker: PhantomData,
+            inner: self.inner.into_iter(),
+            last: self.last.map(|t| *t).into_iter(),
         }
     }
 }
@@ -476,16 +471,6 @@ impl<'a, T, P> ExactSizeIterator for Pairs<'a, T, P> {
     }
 }
 
-// No Clone bound on T or P.
-impl<'a, T, P> Clone for Pairs<'a, T, P> {
-    fn clone(&self) -> Self {
-        Pairs {
-            inner: self.inner.clone(),
-            last: self.last.clone(),
-        }
-    }
-}
-
 /// An iterator over mutably borrowed pairs of type `Pair<&mut T, &mut P>`.
 ///
 /// Refer to the [module documentation] for details about punctuated sequences.
@@ -518,7 +503,6 @@ impl<'a, T, P> ExactSizeIterator for PairsMut<'a, T, P> {
 /// Refer to the [module documentation] for details about punctuated sequences.
 ///
 /// [module documentation]: index.html
-#[derive(Clone)]
 pub struct IntoPairs<T, P> {
     inner: vec::IntoIter<(T, P)>,
     last: option::IntoIter<T>,
@@ -546,25 +530,25 @@ impl<T, P> ExactSizeIterator for IntoPairs<T, P> {
 /// Refer to the [module documentation] for details about punctuated sequences.
 ///
 /// [module documentation]: index.html
-#[derive(Clone)]
 pub struct IntoIter<T, P> {
-    inner: vec::IntoIter<T>,
-
-    // TODO: remove P type parameter in the next breaking change
-    marker: PhantomData<P>,
+    inner: vec::IntoIter<(T, P)>,
+    last: option::IntoIter<T>,
 }
 
 impl<T, P> Iterator for IntoIter<T, P> {
     type Item = T;
 
     fn next(&mut self) -> Option<Self::Item> {
-        self.inner.next()
+        self.inner
+            .next()
+            .map(|pair| pair.0)
+            .or_else(|| self.last.next())
     }
 }
 
 impl<T, P> ExactSizeIterator for IntoIter<T, P> {
     fn len(&self) -> usize {
-        self.inner.len()
+        self.inner.len() + self.last.len()
     }
 }
 
@@ -574,14 +558,7 @@ impl<T, P> ExactSizeIterator for IntoIter<T, P> {
 ///
 /// [module documentation]: index.html
 pub struct Iter<'a, T: 'a> {
-    // The `Item = &'a T` needs to be specified to support rustc 1.31 and older.
-    // On modern compilers we would be able to write just IterTrait<'a, T> where
-    // Item can be inferred unambiguously from the supertrait.
-    inner: Box<IterTrait<'a, T, Item = &'a T> + 'a>,
-}
-
-trait IterTrait<'a, T: 'a>: ExactSizeIterator<Item = &'a T> {
-    fn clone_box(&self) -> Box<IterTrait<'a, T, Item = &'a T> + 'a>;
+    inner: Box<ExactSizeIterator<Item = &'a T> + 'a>,
 }
 
 struct PrivateIter<'a, T: 'a, P: 'a> {
@@ -598,15 +575,6 @@ impl private {
     }
 }
 
-// No Clone bound on T.
-impl<'a, T> Clone for Iter<'a, T> {
-    fn clone(&self) -> Self {
-        Iter {
-            inner: self.inner.clone_box(),
-        }
-    }
-}
-
 impl<'a, T> Iterator for Iter<'a, T> {
     type Item = &'a T;
 
@@ -638,25 +606,6 @@ impl<'a, T, P> ExactSizeIterator for PrivateIter<'a, T, P> {
     }
 }
 
-// No Clone bound on T or P.
-impl<'a, T, P> Clone for PrivateIter<'a, T, P> {
-    fn clone(&self) -> Self {
-        PrivateIter {
-            inner: self.inner.clone(),
-            last: self.last.clone(),
-        }
-    }
-}
-
-impl<'a, T: 'a, I: 'a> IterTrait<'a, T> for I
-where
-    I: ExactSizeIterator<Item = &'a T> + Clone,
-{
-    fn clone_box(&self) -> Box<IterTrait<'a, T, Item = &'a T> + 'a> {
-        Box::new(self.clone())
-    }
-}
-
 /// An iterator over mutably borrowed values of type `&mut T`.
 ///
 /// Refer to the [module documentation] for details about punctuated sequences.
@@ -717,7 +666,6 @@ impl<'a, T, P> ExactSizeIterator for PrivateIterMut<'a, T, P> {
 /// Refer to the [module documentation] for details about punctuated sequences.
 ///
 /// [module documentation]: index.html
-#[cfg_attr(feature = "clone-impls", derive(Clone))]
 pub enum Pair<T, P> {
     Punctuated(T, P),
     End(T),
diff --git a/src/sealed.rs b/src/sealed.rs
deleted file mode 100644
index 0b11bc99..00000000
--- a/src/sealed.rs
+++ /dev/null
@@ -1,4 +0,0 @@
-#[cfg(feature = "parsing")]
-pub mod lookahead {
-    pub trait Sealed: Copy {}
-}
diff --git a/syn.json b/syn.json
index 13fcc1b2..8a023e5b 100644
--- a/syn.json
+++ b/syn.json
@@ -1,5 +1,5 @@
 {
-  "version": "0.15.33",
+  "version": "0.15.31",
   "types": [
     {
       "ident": "Abi",


Test patch:
diff --git a/tests/common/eq.rs b/tests/common/eq.rs
index fc69decf..33699c71 100644
--- a/tests/common/eq.rs
+++ b/tests/common/eq.rs
@@ -10,19 +10,19 @@ use self::rustc_data_structures::thin_vec::ThinVec;
 use self::rustc_target::abi::FloatTy;
 use self::rustc_target::spec::abi::Abi;
 use self::syntax::ast::{
-    AngleBracketedArgs, AnonConst, Arg, ArgSource, Arm, AsmDialect, AsyncArgument, AttrId,
-    AttrStyle, Attribute, BareFnTy, BinOpKind, BindingMode, Block, BlockCheckMode, CaptureBy,
-    Constness, Crate, CrateSugar, Defaultness, EnumDef, Expr, ExprKind, Field, FieldPat, FnDecl,
-    FnHeader, ForeignItem, ForeignItemKind, ForeignMod, FunctionRetTy, GenericArg, GenericArgs,
-    GenericBound, GenericParam, GenericParamKind, Generics, GlobalAsm, Guard, Ident, ImplItem,
-    ImplItemKind, ImplPolarity, InlineAsm, InlineAsmOutput, IntTy, IsAsync, IsAuto, Item, ItemKind,
-    Label, Lifetime, LitIntType, LitKind, Local, LocalSource, MacDelimiter, MacStmtStyle, Mac_,
-    MacroDef, MethodSig, Mod, Movability, MutTy, Mutability, NodeId, ParenthesizedArgs, Pat,
-    PatKind, Path, PathSegment, PolyTraitRef, QSelf, RangeEnd, RangeLimits, RangeSyntax, Stmt,
-    StmtKind, StrStyle, StructField, TraitBoundModifier, TraitItem, TraitItemKind,
-    TraitObjectSyntax, TraitRef, Ty, TyKind, TypeBinding, UintTy, UnOp, UnsafeSource, Unsafety,
-    UseTree, UseTreeKind, VariantData, Variant_, VisibilityKind, WhereBoundPredicate, WhereClause,
-    WhereEqPredicate, WherePredicate, WhereRegionPredicate,
+    AngleBracketedArgs, AnonConst, Arg, Arm, AsmDialect, AttrId, AttrStyle, Attribute, BareFnTy,
+    BinOpKind, BindingMode, Block, BlockCheckMode, CaptureBy, Constness, Crate, CrateSugar,
+    Defaultness, EnumDef, Expr, ExprKind, Field, FieldPat, FnDecl, FnHeader, ForeignItem,
+    ForeignItemKind, ForeignMod, FunctionRetTy, GenericArg, GenericArgs, GenericBound,
+    GenericParam, GenericParamKind, Generics, GlobalAsm, Guard, Ident, ImplItem, ImplItemKind,
+    ImplPolarity, InlineAsm, InlineAsmOutput, IntTy, IsAsync, IsAuto, Item, ItemKind, Label,
+    Lifetime, LitIntType, LitKind, Local, MacDelimiter, MacStmtStyle, Mac_, MacroDef, MethodSig,
+    Mod, Movability, MutTy, Mutability, NodeId, ParenthesizedArgs, Pat, PatKind, Path, PathSegment,
+    PolyTraitRef, QSelf, RangeEnd, RangeLimits, RangeSyntax, Stmt, StmtKind, StrStyle, StructField,
+    TraitBoundModifier, TraitItem, TraitItemKind, TraitObjectSyntax, TraitRef, Ty, TyKind,
+    TypeBinding, UintTy, UnOp, UnsafeSource, Unsafety, UseTree, UseTreeKind, VariantData, Variant_,
+    VisibilityKind, WhereBoundPredicate, WhereClause, WhereEqPredicate, WherePredicate,
+    WhereRegionPredicate,
 };
 use self::syntax::parse::lexer::comments;
 use self::syntax::parse::token::{DelimToken, Lit, Token};
@@ -265,9 +265,8 @@ macro_rules! spanless_eq_enum {
 
 spanless_eq_struct!(AngleBracketedArgs; span args bindings);
 spanless_eq_struct!(AnonConst; id value);
-spanless_eq_struct!(Arg; ty pat id source);
+spanless_eq_struct!(Arg; ty pat id);
 spanless_eq_struct!(Arm; attrs pats guard body);
-spanless_eq_struct!(AsyncArgument; ident arg stmt);
 spanless_eq_struct!(Attribute; id style path tokens span !is_sugared_doc);
 spanless_eq_struct!(BareFnTy; unsafety abi generic_params decl);
 spanless_eq_struct!(Block; stmts id rules span);
@@ -289,7 +288,7 @@ spanless_eq_struct!(InlineAsmOutput; constraint expr is_rw is_indirect);
 spanless_eq_struct!(Item; ident attrs id node vis span !tokens);
 spanless_eq_struct!(Label; ident);
 spanless_eq_struct!(Lifetime; id ident);
-spanless_eq_struct!(Local; pat ty init id span attrs source);
+spanless_eq_struct!(Local; pat ty init id span attrs);
 spanless_eq_struct!(Mac_; path delim tts);
 spanless_eq_struct!(MacroDef; tokens legacy);
 spanless_eq_struct!(MethodSig; header decl);
@@ -313,7 +312,6 @@ spanless_eq_struct!(WhereBoundPredicate; span bound_generic_params bounded_ty bo
 spanless_eq_struct!(WhereClause; id predicates span);
 spanless_eq_struct!(WhereEqPredicate; id span lhs_ty rhs_ty);
 spanless_eq_struct!(WhereRegionPredicate; span lifetime bounds);
-spanless_eq_enum!(ArgSource; Normal AsyncFn(0));
 spanless_eq_enum!(AsmDialect; Att Intel);
 spanless_eq_enum!(AttrStyle; Outer Inner);
 spanless_eq_enum!(BinOpKind; Add Sub Mul Div Rem And Or BitXor BitAnd BitOr Shl Shr Eq Lt Le Ne Ge Gt);
@@ -334,10 +332,9 @@ spanless_eq_enum!(Guard; If(0));
 spanless_eq_enum!(ImplItemKind; Const(0 1) Method(0 1) Type(0) Existential(0) Macro(0));
 spanless_eq_enum!(ImplPolarity; Positive Negative);
 spanless_eq_enum!(IntTy; Isize I8 I16 I32 I64 I128);
-spanless_eq_enum!(IsAsync; Async(closure_id return_impl_trait_id arguments) NotAsync);
+spanless_eq_enum!(IsAsync; Async(closure_id return_impl_trait_id) NotAsync);
 spanless_eq_enum!(IsAuto; Yes No);
 spanless_eq_enum!(LitIntType; Signed(0) Unsigned(0) Unsuffixed);
-spanless_eq_enum!(LocalSource; Normal AsyncFn);
 spanless_eq_enum!(MacDelimiter; Parenthesis Bracket Brace);
 spanless_eq_enum!(MacStmtStyle; Semicolon Braces NoBraces);
 spanless_eq_enum!(Movability; Static Movable);
@@ -436,7 +433,7 @@ fn expand_tts(tts: &TokenStream) -> Vec<TokenTree> {
             tokens.push(TokenTree::Token(DUMMY_SP, Token::Not));
         }
         let lit = Lit::Str_(Symbol::intern(&contents));
-        let tts = vec![
+        let mut tts = vec![
             TokenTree::Token(DUMMY_SP, Token::Ident(Ident::from_str("doc"), false)),
             TokenTree::Token(DUMMY_SP, Token::Eq),
             TokenTree::Token(DUMMY_SP, Token::Literal(lit, None)),
diff --git a/tests/test_expr.rs b/tests/test_expr.rs
new file mode 100644
index 00000000..666bfbfb
--- /dev/null
+++ b/tests/test_expr.rs
@@ -0,0 +1,16 @@
+extern crate proc_macro2;
+extern crate syn;
+
+use std::str::FromStr;
+
+use proc_macro2::TokenStream;
+use syn::{Expr, parse2};
+
+#[test]
+fn test_expr_parse() {
+    let code = "..100u32";
+    let tt = TokenStream::from_str(code).unwrap();
+    let ast1: Expr = parse2(tt.clone()).unwrap();
+    let ast2: syn::ExprRange = parse2(tt).unwrap();
+    assert_eq!(ast1, Expr::Range(ast2));
+}