Detect unparsed tokens
diff --git a/src/group.rs b/src/group.rs
index 9e53757..1490d89 100644
--- a/src/group.rs
+++ b/src/group.rs
@@ -23,7 +23,8 @@
     fn parse_group(&self, delimiter: Delimiter) -> Result<(Span, ParseBuffer<'a>)> {
         self.step_cursor(|cursor| {
             if let Some((content, span, rest)) = cursor.group(delimiter) {
-                let content = ParseBuffer::new(span, cursor.advance(content));
+                let content =
+                    ParseBuffer::new(span, cursor.advance(content), self.get_unexpected());
                 Ok(((span, content), rest))
             } else {
                 let message = match delimiter {
diff --git a/src/next.rs b/src/next.rs
index c8022bf..e5b902c 100644
--- a/src/next.rs
+++ b/src/next.rs
@@ -1,3 +1,5 @@
+use std::cell::Cell;
+use std::rc::Rc;
 use std::str::FromStr;
 
 use buffer::TokenBuffer;
@@ -17,8 +19,11 @@
 /// Parse a proc-macro2 token stream into the chosen syntax tree node.
 pub fn parse2<T: Parse>(input: proc_macro2::TokenStream) -> Result<T> {
     let buf = TokenBuffer::new2(input);
-    let state = ParseBuffer::new(Span::call_site(), buf.begin());
-    T::parse(&state)
+    let unexpected = Rc::new(Cell::new(None));
+    let state = ParseBuffer::new(Span::call_site(), buf.begin(), unexpected);
+    let node = T::parse(&state)?;
+    state.check_unexpected()?;
+    Ok(node)
 }
 
 /// Parse a string of Rust code into the chosen syntax tree node.
diff --git a/src/parse.rs b/src/parse.rs
index cb4eec0..efd7726 100644
--- a/src/parse.rs
+++ b/src/parse.rs
@@ -5,10 +5,12 @@
 use std::marker::PhantomData;
 use std::mem;
 use std::ops::Deref;
+use std::rc::Rc;
+
+use proc_macro2::{Ident, Span};
 
 use buffer::Cursor;
 use error;
-use proc_macro2::{Ident, Span};
 
 pub use error::{Error, Result};
 pub use lookahead::{Lookahead1, Peek};
@@ -28,6 +30,15 @@
     scope: Span,
     cell: Cell<Cursor<'static>>,
     marker: PhantomData<Cursor<'a>>,
+    unexpected: Rc<Cell<Option<Span>>>,
+}
+
+impl<'a> Drop for ParseBuffer<'a> {
+    fn drop(&mut self) {
+        if !self.is_empty() && self.unexpected.get().is_none() {
+            self.unexpected.set(Some(self.cursor().span()));
+        }
+    }
 }
 
 // Not public API.
@@ -64,12 +75,13 @@
 impl<'a> ParseBuffer<'a> {
     // Not public API.
     #[doc(hidden)]
-    pub fn new(scope: Span, cursor: Cursor<'a>) -> Self {
+    pub fn new(scope: Span, cursor: Cursor<'a>, unexpected: Rc<Cell<Option<Span>>>) -> Self {
         let extend = unsafe { mem::transmute::<Cursor<'a>, Cursor<'static>>(cursor) };
         ParseBuffer {
             scope: scope,
             cell: Cell::new(extend),
             marker: PhantomData,
+            unexpected: unexpected,
         }
     }
 
@@ -86,6 +98,7 @@
     }
 
     pub fn parse<T: Parse>(&self) -> Result<T> {
+        self.check_unexpected()?;
         T::parse(self)
     }
 
@@ -95,6 +108,7 @@
     where
         F: for<'c> FnOnce(StepCursor<'c, 'a>) -> Result<(R, Cursor<'c>)>,
     {
+        self.check_unexpected()?;
         match function(StepCursor {
             scope: self.scope,
             cursor: self.cell.get(),
@@ -107,6 +121,21 @@
             Err(err) => Err(err),
         }
     }
+
+    // Not public API.
+    #[doc(hidden)]
+    pub fn get_unexpected(&self) -> Rc<Cell<Option<Span>>> {
+        self.unexpected.clone()
+    }
+
+    // Not public API.
+    #[doc(hidden)]
+    pub fn check_unexpected(&self) -> Result<()> {
+        match self.unexpected.get() {
+            Some(span) => Err(Error::new(span, "unexpected token")),
+            None => Ok(()),
+        }
+    }
 }
 
 impl Parse for Ident {
diff --git a/src/synom.rs b/src/synom.rs
index dbe8444..9c2eb28 100644
--- a/src/synom.rs
+++ b/src/synom.rs
@@ -150,6 +150,9 @@
 //!
 //! *This module is available if Syn is built with the `"parsing"` feature.*
 
+use std::cell::Cell;
+use std::rc::Rc;
+
 #[cfg(all(
     not(all(target_arch = "wasm32", target_os = "unknown")),
     feature = "proc-macro"
@@ -210,11 +213,11 @@
 
 impl<T: Parse> Synom for T {
     fn parse(input: Cursor) -> PResult<Self> {
-        let state = ParseBuffer::new(Span::call_site(), input);
-        match <T as Parse>::parse(&state) {
-            Ok(node) => Ok((node, state.cursor())),
-            Err(err) => Err(err),
-        }
+        let unexpected = Rc::new(Cell::new(None));
+        let state = ParseBuffer::new(Span::call_site(), input, unexpected);
+        let node = <T as Parse>::parse(&state)?;
+        state.check_unexpected()?;
+        Ok((node, state.cursor()))
     }
 }