Make a struct for loop labels
diff --git a/src/expr.rs b/src/expr.rs
index 55c2e4f..4cef442 100644
--- a/src/expr.rs
+++ b/src/expr.rs
@@ -132,8 +132,7 @@
         /// E.g., `'label: while expr { block }`
         pub While(ExprWhile #full {
             pub attrs: Vec<Attribute>,
-            pub label: Option<Lifetime>,
-            pub colon_token: Option<Token![:]>,
+            pub label: Option<Label>,
             pub while_token: Token![while],
             pub cond: Box<Expr>,
             pub body: Block,
@@ -146,8 +145,7 @@
         /// This is desugared to a combination of `loop` and `match` expressions.
         pub WhileLet(ExprWhileLet #full {
             pub attrs: Vec<Attribute>,
-            pub label: Option<Lifetime>,
-            pub colon_token: Option<Token![:]>,
+            pub label: Option<Label>,
             pub while_token: Token![while],
             pub let_token: Token![let],
             pub pat: Box<Pat>,
@@ -163,8 +161,7 @@
         /// This is desugared to a combination of `loop` and `match` expressions.
         pub ForLoop(ExprForLoop #full {
             pub attrs: Vec<Attribute>,
-            pub label: Option<Lifetime>,
-            pub colon_token: Option<Token![:]>,
+            pub label: Option<Label>,
             pub for_token: Token![for],
             pub pat: Box<Pat>,
             pub in_token: Token![in],
@@ -177,8 +174,7 @@
         /// E.g. `'label: loop { block }`
         pub Loop(ExprLoop #full {
             pub attrs: Vec<Attribute>,
-            pub label: Option<Lifetime>,
-            pub colon_token: Option<Token![:]>,
+            pub label: Option<Label>,
             pub loop_token: Token![loop],
             pub body: Block,
         }),
@@ -547,6 +543,14 @@
 
 #[cfg(feature = "full")]
 ast_struct! {
+    pub struct Label {
+        pub name: Lifetime,
+        pub colon_token: Token![:],
+    }
+}
+
+#[cfg(feature = "full")]
+ast_struct! {
     /// A Block (`{ .. }`).
     ///
     /// E.g. `{ .. }` as in `fn foo() { .. }`
@@ -1576,7 +1580,7 @@
     #[cfg(feature = "full")]
     impl Synom for ExprForLoop {
         named!(parse -> Self, do_parse!(
-            lbl: option!(tuple!(syn!(Lifetime), punct!(:))) >>
+            label: option!(syn!(Label)) >>
             for_: keyword!(for) >>
             pat: syn!(Pat) >>
             in_: keyword!(in) >>
@@ -1589,8 +1593,7 @@
                 pat: Box::new(pat),
                 expr: Box::new(expr),
                 body: loop_block,
-                colon_token: lbl.as_ref().map(|p| Token![:]((p.1).0)),
-                label: lbl.map(|p| p.0),
+                label: label,
             })
         ));
     }
@@ -1598,15 +1601,14 @@
     #[cfg(feature = "full")]
     impl Synom for ExprLoop {
         named!(parse -> Self, do_parse!(
-            lbl: option!(tuple!(syn!(Lifetime), punct!(:))) >>
+            label: option!(syn!(Label)) >>
             loop_: keyword!(loop) >>
             loop_block: syn!(Block) >>
             (ExprLoop {
                 attrs: Vec::new(),
                 loop_token: loop_,
                 body: loop_block,
-                colon_token: lbl.as_ref().map(|p| Token![:]((p.1).0)),
-                label: lbl.map(|p| p.0),
+                label: label,
             })
         ));
     }
@@ -1738,17 +1740,16 @@
     #[cfg(feature = "full")]
     impl Synom for ExprWhile {
         named!(parse -> Self, do_parse!(
-            lbl: option!(tuple!(syn!(Lifetime), punct!(:))) >>
+            label: option!(syn!(Label)) >>
             while_: keyword!(while) >>
             cond: expr_no_struct >>
             while_block: syn!(Block) >>
             (ExprWhile {
                 attrs: Vec::new(),
                 while_token: while_,
-                colon_token: lbl.as_ref().map(|p| Token![:]((p.1).0)),
                 cond: Box::new(cond),
                 body: while_block,
-                label: lbl.map(|p| p.0),
+                label: label,
             })
         ));
     }
@@ -1756,7 +1757,7 @@
     #[cfg(feature = "full")]
     impl Synom for ExprWhileLet {
         named!(parse -> Self, do_parse!(
-            lbl: option!(tuple!(syn!(Lifetime), punct!(:))) >>
+            label: option!(syn!(Label)) >>
             while_: keyword!(while) >>
             let_: keyword!(let) >>
             pat: syn!(Pat) >>
@@ -1768,11 +1769,22 @@
                 eq_token: eq,
                 let_token: let_,
                 while_token: while_,
-                colon_token: lbl.as_ref().map(|p| Token![:]((p.1).0)),
                 pat: Box::new(pat),
                 expr: Box::new(value),
                 body: while_block,
-                label: lbl.map(|p| p.0),
+                label: label,
+            })
+        ));
+    }
+
+    #[cfg(feature = "full")]
+    impl Synom for Label {
+        named!(parse -> Self, do_parse!(
+            name: syn!(Lifetime) >>
+            colon: punct!(:) >>
+            (Label {
+                name: name,
+                colon_token: colon,
             })
         ));
     }
@@ -1781,11 +1793,11 @@
     impl Synom for ExprContinue {
         named!(parse -> Self, do_parse!(
             cont: keyword!(continue) >>
-            lbl: option!(syn!(Lifetime)) >>
+            label: option!(syn!(Lifetime)) >>
             (ExprContinue {
                 attrs: Vec::new(),
                 continue_token: cont,
-                label: lbl,
+                label: label,
             })
         ));
     }
@@ -1793,13 +1805,13 @@
     #[cfg(feature = "full")]
     named!(expr_break(allow_struct: bool) -> Expr, do_parse!(
         break_: keyword!(break) >>
-        lbl: option!(syn!(Lifetime)) >>
+        label: option!(syn!(Lifetime)) >>
         // We can't allow blocks after a `break` expression when we wouldn't
         // allow structs, as this expression is ambiguous.
         val: opt_ambiguous_expr!(allow_struct) >>
         (ExprBreak {
             attrs: Vec::new(),
-            label: lbl,
+            label: label,
             expr: val.map(Box::new),
             break_token: break_,
         }.into())
@@ -2636,10 +2648,7 @@
     impl ToTokens for ExprWhile {
         fn to_tokens(&self, tokens: &mut Tokens) {
             tokens.append_all(self.attrs.outer());
-            if self.label.is_some() {
-                self.label.to_tokens(tokens);
-                TokensOrDefault(&self.colon_token).to_tokens(tokens);
-            }
+            self.label.to_tokens(tokens);
             self.while_token.to_tokens(tokens);
             wrap_bare_struct(tokens, &self.cond);
             self.body.to_tokens(tokens);
@@ -2650,10 +2659,7 @@
     impl ToTokens for ExprWhileLet {
         fn to_tokens(&self, tokens: &mut Tokens) {
             tokens.append_all(self.attrs.outer());
-            if self.label.is_some() {
-                self.label.to_tokens(tokens);
-                TokensOrDefault(&self.colon_token).to_tokens(tokens);
-            }
+            self.label.to_tokens(tokens);
             self.while_token.to_tokens(tokens);
             self.let_token.to_tokens(tokens);
             self.pat.to_tokens(tokens);
@@ -2667,10 +2673,7 @@
     impl ToTokens for ExprForLoop {
         fn to_tokens(&self, tokens: &mut Tokens) {
             tokens.append_all(self.attrs.outer());
-            if self.label.is_some() {
-                self.label.to_tokens(tokens);
-                TokensOrDefault(&self.colon_token).to_tokens(tokens);
-            }
+            self.label.to_tokens(tokens);
             self.for_token.to_tokens(tokens);
             self.pat.to_tokens(tokens);
             self.in_token.to_tokens(tokens);
@@ -2683,10 +2686,7 @@
     impl ToTokens for ExprLoop {
         fn to_tokens(&self, tokens: &mut Tokens) {
             tokens.append_all(self.attrs.outer());
-            if self.label.is_some() {
-                self.label.to_tokens(tokens);
-                TokensOrDefault(&self.colon_token).to_tokens(tokens);
-            }
+            self.label.to_tokens(tokens);
             self.loop_token.to_tokens(tokens);
             self.body.to_tokens(tokens);
         }
@@ -2962,6 +2962,14 @@
     }
 
     #[cfg(feature = "full")]
+    impl ToTokens for Label {
+        fn to_tokens(&self, tokens: &mut Tokens) {
+            self.name.to_tokens(tokens);
+            self.colon_token.to_tokens(tokens);
+        }
+    }
+
+    #[cfg(feature = "full")]
     impl ToTokens for FieldValue {
         fn to_tokens(&self, tokens: &mut Tokens) {
             self.member.to_tokens(tokens);
diff --git a/src/gen/fold.rs b/src/gen/fold.rs
index a33d1d6..1f60d88 100644
--- a/src/gen/fold.rs
+++ b/src/gen/fold.rs
@@ -239,6 +239,8 @@
 fn fold_item_use(&mut self, i: ItemUse) -> ItemUse { fold_item_use(self, i) }
 # [ cfg ( feature = "full" ) ]
 fn fold_item_verbatim(&mut self, i: ItemVerbatim) -> ItemVerbatim { fold_item_verbatim(self, i) }
+# [ cfg ( feature = "full" ) ]
+fn fold_label(&mut self, i: Label) -> Label { fold_label(self, i) }
 
 fn fold_lifetime(&mut self, i: Lifetime) -> Lifetime { fold_lifetime(self, i) }
 
@@ -1065,8 +1067,7 @@
 pub fn fold_expr_for_loop<V: Folder + ?Sized>(_visitor: &mut V, _i: ExprForLoop) -> ExprForLoop {
     ExprForLoop {
         attrs: FoldHelper::lift(_i . attrs, |it| { _visitor.fold_attribute(it) }),
-        label: (_i . label).map(|it| { _visitor.fold_lifetime(it) }),
-        colon_token: (_i . colon_token).map(|it| { Token ! [ : ](tokens_helper(_visitor, &(it).0)) }),
+        label: (_i . label).map(|it| { _visitor.fold_label(it) }),
         for_token: Token ! [ for ](tokens_helper(_visitor, &(_i . for_token).0)),
         pat: Box::new(_visitor.fold_pat(* _i . pat)),
         in_token: Token ! [ in ](tokens_helper(_visitor, &(_i . in_token).0)),
@@ -1140,8 +1141,7 @@
 pub fn fold_expr_loop<V: Folder + ?Sized>(_visitor: &mut V, _i: ExprLoop) -> ExprLoop {
     ExprLoop {
         attrs: FoldHelper::lift(_i . attrs, |it| { _visitor.fold_attribute(it) }),
-        label: (_i . label).map(|it| { _visitor.fold_lifetime(it) }),
-        colon_token: (_i . colon_token).map(|it| { Token ! [ : ](tokens_helper(_visitor, &(it).0)) }),
+        label: (_i . label).map(|it| { _visitor.fold_label(it) }),
         loop_token: Token ! [ loop ](tokens_helper(_visitor, &(_i . loop_token).0)),
         body: _visitor.fold_block(_i . body),
     }
@@ -1280,8 +1280,7 @@
 pub fn fold_expr_while<V: Folder + ?Sized>(_visitor: &mut V, _i: ExprWhile) -> ExprWhile {
     ExprWhile {
         attrs: FoldHelper::lift(_i . attrs, |it| { _visitor.fold_attribute(it) }),
-        label: (_i . label).map(|it| { _visitor.fold_lifetime(it) }),
-        colon_token: (_i . colon_token).map(|it| { Token ! [ : ](tokens_helper(_visitor, &(it).0)) }),
+        label: (_i . label).map(|it| { _visitor.fold_label(it) }),
         while_token: Token ! [ while ](tokens_helper(_visitor, &(_i . while_token).0)),
         cond: Box::new(_visitor.fold_expr(* _i . cond)),
         body: _visitor.fold_block(_i . body),
@@ -1291,8 +1290,7 @@
 pub fn fold_expr_while_let<V: Folder + ?Sized>(_visitor: &mut V, _i: ExprWhileLet) -> ExprWhileLet {
     ExprWhileLet {
         attrs: FoldHelper::lift(_i . attrs, |it| { _visitor.fold_attribute(it) }),
-        label: (_i . label).map(|it| { _visitor.fold_lifetime(it) }),
-        colon_token: (_i . colon_token).map(|it| { Token ! [ : ](tokens_helper(_visitor, &(it).0)) }),
+        label: (_i . label).map(|it| { _visitor.fold_label(it) }),
         while_token: Token ! [ while ](tokens_helper(_visitor, &(_i . while_token).0)),
         let_token: Token ! [ let ](tokens_helper(_visitor, &(_i . let_token).0)),
         pat: Box::new(_visitor.fold_pat(* _i . pat)),
@@ -1901,6 +1899,13 @@
         tts: _i . tts,
     }
 }
+# [ cfg ( feature = "full" ) ]
+pub fn fold_label<V: Folder + ?Sized>(_visitor: &mut V, _i: Label) -> Label {
+    Label {
+        name: _visitor.fold_lifetime(_i . name),
+        colon_token: Token ! [ : ](tokens_helper(_visitor, &(_i . colon_token).0)),
+    }
+}
 
 pub fn fold_lifetime_def<V: Folder + ?Sized>(_visitor: &mut V, _i: LifetimeDef) -> LifetimeDef {
     LifetimeDef {
diff --git a/src/gen/visit.rs b/src/gen/visit.rs
index d5b63ae..df1f9d6 100644
--- a/src/gen/visit.rs
+++ b/src/gen/visit.rs
@@ -235,6 +235,8 @@
 fn visit_item_use(&mut self, i: &'ast ItemUse) { visit_item_use(self, i) }
 # [ cfg ( feature = "full" ) ]
 fn visit_item_verbatim(&mut self, i: &'ast ItemVerbatim) { visit_item_verbatim(self, i) }
+# [ cfg ( feature = "full" ) ]
+fn visit_label(&mut self, i: &'ast Label) { visit_label(self, i) }
 
 fn visit_lifetime(&mut self, i: &'ast Lifetime) { visit_lifetime(self, i) }
 
@@ -846,8 +848,7 @@
 # [ cfg ( feature = "full" ) ]
 pub fn visit_expr_for_loop<'ast, V: Visitor<'ast> + ?Sized>(_visitor: &mut V, _i: &'ast ExprForLoop) {
     for it in & _i . attrs { _visitor.visit_attribute(it) };
-    if let Some(ref it) = _i . label { _visitor.visit_lifetime(it) };
-    if let Some(ref it) = _i . colon_token { tokens_helper(_visitor, &(it).0) };
+    if let Some(ref it) = _i . label { _visitor.visit_label(it) };
     tokens_helper(_visitor, &(& _i . for_token).0);
     _visitor.visit_pat(& * _i . pat);
     tokens_helper(_visitor, &(& _i . in_token).0);
@@ -907,8 +908,7 @@
 # [ cfg ( feature = "full" ) ]
 pub fn visit_expr_loop<'ast, V: Visitor<'ast> + ?Sized>(_visitor: &mut V, _i: &'ast ExprLoop) {
     for it in & _i . attrs { _visitor.visit_attribute(it) };
-    if let Some(ref it) = _i . label { _visitor.visit_lifetime(it) };
-    if let Some(ref it) = _i . colon_token { tokens_helper(_visitor, &(it).0) };
+    if let Some(ref it) = _i . label { _visitor.visit_label(it) };
     tokens_helper(_visitor, &(& _i . loop_token).0);
     _visitor.visit_block(& _i . body);
 }
@@ -1015,8 +1015,7 @@
 # [ cfg ( feature = "full" ) ]
 pub fn visit_expr_while<'ast, V: Visitor<'ast> + ?Sized>(_visitor: &mut V, _i: &'ast ExprWhile) {
     for it in & _i . attrs { _visitor.visit_attribute(it) };
-    if let Some(ref it) = _i . label { _visitor.visit_lifetime(it) };
-    if let Some(ref it) = _i . colon_token { tokens_helper(_visitor, &(it).0) };
+    if let Some(ref it) = _i . label { _visitor.visit_label(it) };
     tokens_helper(_visitor, &(& _i . while_token).0);
     _visitor.visit_expr(& * _i . cond);
     _visitor.visit_block(& _i . body);
@@ -1024,8 +1023,7 @@
 # [ cfg ( feature = "full" ) ]
 pub fn visit_expr_while_let<'ast, V: Visitor<'ast> + ?Sized>(_visitor: &mut V, _i: &'ast ExprWhileLet) {
     for it in & _i . attrs { _visitor.visit_attribute(it) };
-    if let Some(ref it) = _i . label { _visitor.visit_lifetime(it) };
-    if let Some(ref it) = _i . colon_token { tokens_helper(_visitor, &(it).0) };
+    if let Some(ref it) = _i . label { _visitor.visit_label(it) };
     tokens_helper(_visitor, &(& _i . while_token).0);
     tokens_helper(_visitor, &(& _i . let_token).0);
     _visitor.visit_pat(& * _i . pat);
@@ -1494,6 +1492,11 @@
 pub fn visit_item_verbatim<'ast, V: Visitor<'ast> + ?Sized>(_visitor: &mut V, _i: &'ast ItemVerbatim) {
     // Skipped field _i . tts;
 }
+# [ cfg ( feature = "full" ) ]
+pub fn visit_label<'ast, V: Visitor<'ast> + ?Sized>(_visitor: &mut V, _i: &'ast Label) {
+    _visitor.visit_lifetime(& _i . name);
+    tokens_helper(_visitor, &(& _i . colon_token).0);
+}
 
 pub fn visit_lifetime<'ast, V: Visitor<'ast> + ?Sized>(_visitor: &mut V, _i: &'ast Lifetime) {
     // Skipped field _i . sym;
diff --git a/src/gen/visit_mut.rs b/src/gen/visit_mut.rs
index d48e04f..d8f10fa 100644
--- a/src/gen/visit_mut.rs
+++ b/src/gen/visit_mut.rs
@@ -235,6 +235,8 @@
 fn visit_item_use_mut(&mut self, i: &mut ItemUse) { visit_item_use_mut(self, i) }
 # [ cfg ( feature = "full" ) ]
 fn visit_item_verbatim_mut(&mut self, i: &mut ItemVerbatim) { visit_item_verbatim_mut(self, i) }
+# [ cfg ( feature = "full" ) ]
+fn visit_label_mut(&mut self, i: &mut Label) { visit_label_mut(self, i) }
 
 fn visit_lifetime_mut(&mut self, i: &mut Lifetime) { visit_lifetime_mut(self, i) }
 
@@ -846,8 +848,7 @@
 # [ cfg ( feature = "full" ) ]
 pub fn visit_expr_for_loop_mut<V: VisitorMut + ?Sized>(_visitor: &mut V, _i: &mut ExprForLoop) {
     for it in & mut _i . attrs { _visitor.visit_attribute_mut(it) };
-    if let Some(ref mut it) = _i . label { _visitor.visit_lifetime_mut(it) };
-    if let Some(ref mut it) = _i . colon_token { tokens_helper(_visitor, &mut (it).0) };
+    if let Some(ref mut it) = _i . label { _visitor.visit_label_mut(it) };
     tokens_helper(_visitor, &mut (& mut _i . for_token).0);
     _visitor.visit_pat_mut(& mut * _i . pat);
     tokens_helper(_visitor, &mut (& mut _i . in_token).0);
@@ -907,8 +908,7 @@
 # [ cfg ( feature = "full" ) ]
 pub fn visit_expr_loop_mut<V: VisitorMut + ?Sized>(_visitor: &mut V, _i: &mut ExprLoop) {
     for it in & mut _i . attrs { _visitor.visit_attribute_mut(it) };
-    if let Some(ref mut it) = _i . label { _visitor.visit_lifetime_mut(it) };
-    if let Some(ref mut it) = _i . colon_token { tokens_helper(_visitor, &mut (it).0) };
+    if let Some(ref mut it) = _i . label { _visitor.visit_label_mut(it) };
     tokens_helper(_visitor, &mut (& mut _i . loop_token).0);
     _visitor.visit_block_mut(& mut _i . body);
 }
@@ -1015,8 +1015,7 @@
 # [ cfg ( feature = "full" ) ]
 pub fn visit_expr_while_mut<V: VisitorMut + ?Sized>(_visitor: &mut V, _i: &mut ExprWhile) {
     for it in & mut _i . attrs { _visitor.visit_attribute_mut(it) };
-    if let Some(ref mut it) = _i . label { _visitor.visit_lifetime_mut(it) };
-    if let Some(ref mut it) = _i . colon_token { tokens_helper(_visitor, &mut (it).0) };
+    if let Some(ref mut it) = _i . label { _visitor.visit_label_mut(it) };
     tokens_helper(_visitor, &mut (& mut _i . while_token).0);
     _visitor.visit_expr_mut(& mut * _i . cond);
     _visitor.visit_block_mut(& mut _i . body);
@@ -1024,8 +1023,7 @@
 # [ cfg ( feature = "full" ) ]
 pub fn visit_expr_while_let_mut<V: VisitorMut + ?Sized>(_visitor: &mut V, _i: &mut ExprWhileLet) {
     for it in & mut _i . attrs { _visitor.visit_attribute_mut(it) };
-    if let Some(ref mut it) = _i . label { _visitor.visit_lifetime_mut(it) };
-    if let Some(ref mut it) = _i . colon_token { tokens_helper(_visitor, &mut (it).0) };
+    if let Some(ref mut it) = _i . label { _visitor.visit_label_mut(it) };
     tokens_helper(_visitor, &mut (& mut _i . while_token).0);
     tokens_helper(_visitor, &mut (& mut _i . let_token).0);
     _visitor.visit_pat_mut(& mut * _i . pat);
@@ -1494,6 +1492,11 @@
 pub fn visit_item_verbatim_mut<V: VisitorMut + ?Sized>(_visitor: &mut V, _i: &mut ItemVerbatim) {
     // Skipped field _i . tts;
 }
+# [ cfg ( feature = "full" ) ]
+pub fn visit_label_mut<V: VisitorMut + ?Sized>(_visitor: &mut V, _i: &mut Label) {
+    _visitor.visit_lifetime_mut(& mut _i . name);
+    tokens_helper(_visitor, &mut (& mut _i . colon_token).0);
+}
 
 pub fn visit_lifetime_mut<V: VisitorMut + ?Sized>(_visitor: &mut V, _i: &mut Lifetime) {
     // Skipped field _i . sym;
diff --git a/src/lib.rs b/src/lib.rs
index 4847af5..65183a1 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -41,7 +41,7 @@
                ExprUnary, ExprUnsafe, ExprVerbatim, ExprWhile, ExprWhileLet, ExprYield, Index, Member};
 
 #[cfg(feature = "full")]
-pub use expr::{Arm, Block, FieldPat, FieldValue, GenericMethodArgument, Local,
+pub use expr::{Arm, Block, FieldPat, FieldValue, GenericMethodArgument, Label, Local,
                MethodTurbofish, Pat, PatBox, PatIdent, PatLit, PatMacro, PatPath, PatRange, PatRef, PatSlice,
                PatStruct, PatTuple, PatTupleStruct, PatVerbatim, PatWild, RangeLimits, Stmt};