Remove parse_synom shim
diff --git a/src/expr.rs b/src/expr.rs
index d03d63f..a4d58ed 100644
--- a/src/expr.rs
+++ b/src/expr.rs
@@ -2812,11 +2812,16 @@
             front.push_punct(punct);
         }
 
-        let back = if comma_token.is_some() {
-            content.parse_synom(Punctuated::parse_terminated)?
-        } else {
-            Punctuated::new()
-        };
+        let mut back = Punctuated::new();
+        while !content.is_empty() {
+            let value: Pat = content.parse()?;
+            back.push_value(value);
+            if content.is_empty() {
+                break;
+            }
+            let punct = content.parse()?;
+            back.push_punct(punct);
+        }
 
         Ok(PatTuple {
             paren_token: paren_token,
diff --git a/src/generics.rs b/src/generics.rs
index 2751ef4..5476192 100644
--- a/src/generics.rs
+++ b/src/generics.rs
@@ -608,7 +608,17 @@
             Ok(BoundLifetimes {
                 for_token: input.parse()?,
                 lt_token: input.parse()?,
-                lifetimes: input.parse_synom(Punctuated::parse_terminated)?,
+                lifetimes: {
+                    let mut lifetimes = Punctuated::new();
+                    while !input.peek(Token![>]) {
+                        lifetimes.push_value(input.parse()?);
+                        if input.peek(Token![>]) {
+                            break;
+                        }
+                        lifetimes.push_punct(input.parse()?);
+                    }
+                    lifetimes
+                },
                 gt_token: input.parse()?,
             })
         }
diff --git a/src/item.rs b/src/item.rs
index 325710a..1be9033 100644
--- a/src/item.rs
+++ b/src/item.rs
@@ -1230,7 +1230,14 @@
 
             let content;
             let paren_token = parenthesized!(content in input);
-            let inputs = content.parse_synom(Punctuated::parse_terminated)?;
+            let mut inputs = Punctuated::new();
+            while !content.is_empty() && !content.peek(Token![...]) {
+                inputs.push_value(content.parse()?);
+                if content.is_empty() {
+                    break;
+                }
+                inputs.push_punct(content.parse()?);
+            }
             let variadic: Option<Token![...]> = if inputs.empty_or_trailing() {
                 content.parse()?
             } else {
@@ -1338,7 +1345,16 @@
                     generics
                 },
                 colon_token: Some(input.parse()?),
-                bounds: input.parse_synom(Punctuated::parse_separated_nonempty)?,
+                bounds: {
+                    let mut bounds = Punctuated::new();
+                    while !input.peek(Token![;]) {
+                        if !bounds.is_empty() {
+                            bounds.push_punct(input.parse()?);
+                        }
+                        bounds.push_value(input.parse()?);
+                    }
+                    bounds
+                },
                 semi_token: input.parse()?,
             })
         }
@@ -1422,11 +1438,17 @@
             let ident: Ident = input.parse()?;
             let mut generics: Generics = input.parse()?;
             let colon_token: Option<Token![:]> = input.parse()?;
-            let supertraits = if colon_token.is_some() {
-                input.parse_synom(Punctuated::parse_separated_nonempty)?
-            } else {
-                Punctuated::new()
-            };
+
+            let mut supertraits = Punctuated::new();
+            if colon_token.is_some() {
+                while !input.peek(Token![where]) && !input.peek(token::Brace) {
+                    if !supertraits.is_empty() {
+                        supertraits.push_punct(input.parse()?);
+                    }
+                    supertraits.push_value(input.parse()?);
+                }
+            }
+
             generics.where_clause = input.parse()?;
 
             let content;
@@ -1585,11 +1607,17 @@
             let ident: Ident = input.parse()?;
             let mut generics: Generics = input.parse()?;
             let colon_token: Option<Token![:]> = input.parse()?;
-            let bounds = if colon_token.is_some() {
-                input.parse_synom(Punctuated::parse_separated_nonempty)?
-            } else {
-                Punctuated::new()
-            };
+
+            let mut bounds = Punctuated::new();
+            if colon_token.is_some() {
+                while !input.peek(Token![where]) && !input.peek(Token![=]) && !input.peek(Token![;]) {
+                    if !bounds.is_empty() {
+                        bounds.push_punct(input.parse()?);
+                    }
+                    bounds.push_value(input.parse()?);
+                }
+            }
+
             generics.where_clause = input.parse()?;
             let default = if input.peek(Token![=]) {
                 let eq_token: Token![=] = input.parse()?;
diff --git a/src/parse.rs b/src/parse.rs
index 64f972d..8d0f6d4 100644
--- a/src/parse.rs
+++ b/src/parse.rs
@@ -12,7 +12,6 @@
 use buffer::Cursor;
 use error;
 use punctuated::Punctuated;
-use synom::PResult;
 use token::Token;
 
 pub use error::{Error, Result};
@@ -179,12 +178,6 @@
 
     // Not public API.
     #[doc(hidden)]
-    pub fn parse_synom<T>(&self, parse: fn(Cursor) -> PResult<T>) -> Result<T> {
-        self.step_cursor(|step| parse(step.cursor))
-    }
-
-    // Not public API.
-    #[doc(hidden)]
     pub fn get_unexpected(&self) -> Rc<Cell<Option<Span>>> {
         self.unexpected.clone()
     }
diff --git a/src/path.rs b/src/path.rs
index 6baf35a..4cdf2de 100644
--- a/src/path.rs
+++ b/src/path.rs
@@ -296,7 +296,7 @@
             let content;
             Ok(ParenthesizedGenericArguments {
                 paren_token: parenthesized!(content in input),
-                inputs: content.parse_synom(Punctuated::parse_terminated)?,
+                inputs: content.parse_terminated(Type::parse)?,
                 output: input.call(ReturnType::without_plus)?,
             })
         }
diff --git a/src/ty.rs b/src/ty.rs
index 2ca5e57..443e27d 100644
--- a/src/ty.rs
+++ b/src/ty.rs
@@ -395,11 +395,11 @@
                     lifetimes: lifetimes,
                     path: ty.path,
                 }));
-                if allow_plus && input.peek(Token![+]) {
-                    bounds.push_punct(input.parse()?);
-                    let rest: Punctuated<TypeParamBound, Token![+]> =
-                        input.parse_synom(Punctuated::parse_terminated_nonempty)?;
-                    bounds.extend(rest);
+                if allow_plus {
+                    while input.peek(Token![+]) {
+                        bounds.push_punct(input.parse()?);
+                        bounds.push_value(input.parse()?);
+                    }
                 }
                 return Ok(Type::TraitObject(TypeTraitObject {
                     dyn_token: None,
@@ -509,7 +509,14 @@
                 fn_token: input.parse()?,
                 paren_token: parenthesized!(args in input),
                 inputs: {
-                    let inputs = args.parse_synom(Punctuated::parse_terminated)?;
+                    let mut inputs = Punctuated::new();
+                    while !args.is_empty() && !args.peek(Token![...]) {
+                        inputs.push_value(args.parse()?);
+                        if args.is_empty() {
+                            break;
+                        }
+                        inputs.push_punct(args.parse()?);
+                    }
                     allow_variadic = inputs.empty_or_trailing();
                     inputs
                 },
@@ -625,13 +632,18 @@
             Ok(TypeTraitObject {
                 dyn_token: input.parse()?,
                 bounds: {
-                    let bounds = if allow_plus {
-                        input.parse_synom(Punctuated::parse_terminated_nonempty)?
+                    let mut bounds = Punctuated::new();
+                    if allow_plus {
+                        loop {
+                            bounds.push_value(input.parse()?);
+                            if !input.peek(Token![+]) {
+                                break;
+                            }
+                            bounds.push_punct(input.parse()?);
+                        }
                     } else {
-                        let mut bounds = Punctuated::new();
                         bounds.push_value(input.parse()?);
-                        bounds
-                    };
+                    }
                     // Just lifetimes like `'a + 'b` is not a TraitObject.
                     if !at_least_one_type(&bounds) {
                         return Err(input.error("expected at least one type"));
@@ -648,7 +660,17 @@
                 impl_token: input.parse()?,
                 // NOTE: rust-lang/rust#34511 includes discussion about whether
                 // or not + should be allowed in ImplTrait directly without ().
-                bounds: input.parse_synom(Punctuated::parse_terminated_nonempty)?,
+                bounds: {
+                    let mut bounds = Punctuated::new();
+                    loop {
+                        bounds.push_value(input.parse()?);
+                        if !input.peek(Token![+]) {
+                            break;
+                        }
+                        bounds.push_punct(input.parse()?);
+                    }
+                    bounds
+                },
             })
         }
     }