about summary refs log tree commit diff
path: root/src
diff options
context:
space:
mode:
authorAlex Crichton <alex@alexcrichton.com>2018-01-25 12:48:49 -0600
committerGitHub <noreply@github.com>2018-01-25 12:48:49 -0600
commit98b375483c44c68009d699a4cd4b7b0a3d5d97a3 (patch)
tree1cba42b1aa98db0d012cbecfb36d7d2dea428232 /src
parent304885d959cae6b1fd6cb9aa64b70df6269d04b4 (diff)
parent2d56abfbebdc905dafc9cf9edc0a6f58e4de7cbd (diff)
downloadrust-98b375483c44c68009d699a4cd4b7b0a3d5d97a3.tar.gz
rust-98b375483c44c68009d699a4cd4b7b0a3d5d97a3.zip
Rollup merge of #47502 - petrochenkov:label, r=eddyb
AST/HIR: Add a separate structure for labels
Diffstat (limited to 'src')
-rw-r--r--src/librustc/hir/intravisit.rs52
-rw-r--r--src/librustc/hir/lowering.rs48
-rw-r--r--src/librustc/hir/mod.rs20
-rw-r--r--src/librustc/hir/print.rs24
-rw-r--r--src/librustc/ich/impls_hir.rs7
-rw-r--r--src/librustc/middle/resolve_lifetime.rs2
-rw-r--r--src/librustc_passes/ast_validation.rs13
-rw-r--r--src/librustc_resolve/lib.rs14
-rw-r--r--src/libsyntax/ast.rs24
-rw-r--r--src/libsyntax/fold.rs43
-rw-r--r--src/libsyntax/parse/parser.rs64
-rw-r--r--src/libsyntax/print/pprust.rs36
-rw-r--r--src/libsyntax/visit.rs58
13 files changed, 203 insertions, 202 deletions
diff --git a/src/librustc/hir/intravisit.rs b/src/librustc/hir/intravisit.rs
index ce35e6552ca..97cf9b01410 100644
--- a/src/librustc/hir/intravisit.rs
+++ b/src/librustc/hir/intravisit.rs
@@ -43,7 +43,6 @@
 
 use syntax::abi::Abi;
 use syntax::ast::{NodeId, CRATE_NODE_ID, Name, Attribute};
-use syntax::codemap::Spanned;
 use syntax_pos::Span;
 use hir::*;
 use hir::def::Def;
@@ -336,6 +335,9 @@ pub trait Visitor<'v> : Sized {
     fn visit_variant(&mut self, v: &'v Variant, g: &'v Generics, item_id: NodeId) {
         walk_variant(self, v, g, item_id)
     }
+    fn visit_label(&mut self, label: &'v Label) {
+        walk_label(self, label)
+    }
     fn visit_lifetime(&mut self, lifetime: &'v Lifetime) {
         walk_lifetime(self, lifetime)
     }
@@ -370,18 +372,6 @@ pub trait Visitor<'v> : Sized {
     }
 }
 
-pub fn walk_opt_name<'v, V: Visitor<'v>>(visitor: &mut V, span: Span, opt_name: Option<Name>) {
-    if let Some(name) = opt_name {
-        visitor.visit_name(span, name);
-    }
-}
-
-pub fn walk_opt_sp_name<'v, V: Visitor<'v>>(visitor: &mut V, opt_sp_name: &Option<Spanned<Name>>) {
-    if let Some(ref sp_name) = *opt_sp_name {
-        visitor.visit_name(sp_name.span, sp_name.node);
-    }
-}
-
 /// Walks the contents of a crate. See also `Crate::visit_all_items`.
 pub fn walk_crate<'v, V: Visitor<'v>>(visitor: &mut V, krate: &'v Crate) {
     visitor.visit_mod(&krate.module, krate.span, CRATE_NODE_ID);
@@ -420,6 +410,10 @@ pub fn walk_local<'v, V: Visitor<'v>>(visitor: &mut V, local: &'v Local) {
     walk_list!(visitor, visit_ty, &local.ty);
 }
 
+pub fn walk_label<'v, V: Visitor<'v>>(visitor: &mut V, label: &'v Label) {
+    visitor.visit_name(label.span, label.name);
+}
+
 pub fn walk_lifetime<'v, V: Visitor<'v>>(visitor: &mut V, lifetime: &'v Lifetime) {
     visitor.visit_id(lifetime.id);
     match lifetime.name {
@@ -452,7 +446,9 @@ pub fn walk_item<'v, V: Visitor<'v>>(visitor: &mut V, item: &'v Item) {
     match item.node {
         ItemExternCrate(opt_name) => {
             visitor.visit_id(item.id);
-            walk_opt_name(visitor, item.span, opt_name)
+            if let Some(name) = opt_name {
+                visitor.visit_name(item.span, name);
+            }
         }
         ItemUse(ref path, _) => {
             visitor.visit_id(item.id);
@@ -993,14 +989,14 @@ pub fn walk_expr<'v, V: Visitor<'v>>(visitor: &mut V, expression: &'v Expr) {
             visitor.visit_expr(if_block);
             walk_list!(visitor, visit_expr, optional_else);
         }
-        ExprWhile(ref subexpression, ref block, ref opt_sp_name) => {
+        ExprWhile(ref subexpression, ref block, ref opt_label) => {
+            walk_list!(visitor, visit_label, opt_label);
             visitor.visit_expr(subexpression);
             visitor.visit_block(block);
-            walk_opt_sp_name(visitor, opt_sp_name);
         }
-        ExprLoop(ref block, ref opt_sp_name, _) => {
+        ExprLoop(ref block, ref opt_label, _) => {
+            walk_list!(visitor, visit_label, opt_label);
             visitor.visit_block(block);
-            walk_opt_sp_name(visitor, opt_sp_name);
         }
         ExprMatch(ref subexpression, ref arms, _) => {
             visitor.visit_expr(subexpression);
@@ -1036,28 +1032,28 @@ pub fn walk_expr<'v, V: Visitor<'v>>(visitor: &mut V, expression: &'v Expr) {
         ExprPath(ref qpath) => {
             visitor.visit_qpath(qpath, expression.id, expression.span);
         }
-        ExprBreak(label, ref opt_expr) => {
-            label.ident.map(|ident| {
-                match label.target_id {
+        ExprBreak(ref destination, ref opt_expr) => {
+            if let Some(ref label) = destination.label {
+                visitor.visit_label(label);
+                match destination.target_id {
                     ScopeTarget::Block(node_id) |
                     ScopeTarget::Loop(LoopIdResult::Ok(node_id)) =>
                         visitor.visit_def_mention(Def::Label(node_id)),
                     ScopeTarget::Loop(LoopIdResult::Err(_)) => {},
                 };
-                visitor.visit_name(ident.span, ident.node.name);
-            });
+            }
             walk_list!(visitor, visit_expr, opt_expr);
         }
-        ExprAgain(label) => {
-            label.ident.map(|ident| {
-                match label.target_id {
+        ExprAgain(ref destination) => {
+            if let Some(ref label) = destination.label {
+                visitor.visit_label(label);
+                match destination.target_id {
                     ScopeTarget::Block(_) => bug!("can't `continue` to a non-loop block"),
                     ScopeTarget::Loop(LoopIdResult::Ok(node_id)) =>
                         visitor.visit_def_mention(Def::Label(node_id)),
                     ScopeTarget::Loop(LoopIdResult::Err(_)) => {},
                 };
-                visitor.visit_name(ident.span, ident.node.name);
-            });
+            }
         }
         ExprRet(ref optional_expression) => {
             walk_list!(visitor, visit_expr, optional_expression);
diff --git a/src/librustc/hir/lowering.rs b/src/librustc/hir/lowering.rs
index e76f39a8fb1..dc2f2583c01 100644
--- a/src/librustc/hir/lowering.rs
+++ b/src/librustc/hir/lowering.rs
@@ -773,22 +773,22 @@ impl<'a> LoweringContext<'a> {
         *self.name_map.entry(ident).or_insert_with(|| Symbol::from_ident(ident))
     }
 
-    fn lower_opt_sp_ident(&mut self, o_id: Option<Spanned<Ident>>) -> Option<Spanned<Name>> {
-        o_id.map(|sp_ident| respan(sp_ident.span, sp_ident.node.name))
+    fn lower_label(&mut self, label: Option<Label>) -> Option<hir::Label> {
+        label.map(|label| hir::Label { name: label.ident.name, span: label.span })
     }
 
-    fn lower_loop_destination(&mut self, destination: Option<(NodeId, Spanned<Ident>)>)
+    fn lower_loop_destination(&mut self, destination: Option<(NodeId, Label)>)
         -> hir::Destination
     {
         match destination {
-            Some((id, label_ident)) => {
+            Some((id, label)) => {
                 let target = if let Def::Label(loop_id) = self.expect_full_def(id) {
                     hir::LoopIdResult::Ok(self.lower_node_id(loop_id).node_id)
                 } else {
                     hir::LoopIdResult::Err(hir::LoopIdError::UnresolvedLabel)
                 };
                 hir::Destination {
-                    ident: Some(label_ident),
+                    label: self.lower_label(Some(label)),
                     target_id: hir::ScopeTarget::Loop(target),
                 }
             },
@@ -798,7 +798,7 @@ impl<'a> LoweringContext<'a> {
                                   .map(|innermost_loop_id| *innermost_loop_id);
 
                 hir::Destination {
-                    ident: None,
+                    label: None,
                     target_id: hir::ScopeTarget::Loop(
                         loop_id.map(|id| Ok(self.lower_node_id(id).node_id))
                                .unwrap_or(Err(hir::LoopIdError::OutsideLoopScope))
@@ -2751,17 +2751,17 @@ impl<'a> LoweringContext<'a> {
 
                 hir::ExprIf(P(self.lower_expr(cond)), P(then_expr), else_opt)
             }
-            ExprKind::While(ref cond, ref body, opt_ident) => {
+            ExprKind::While(ref cond, ref body, opt_label) => {
                 self.with_loop_scope(e.id, |this|
                     hir::ExprWhile(
                         this.with_loop_condition_scope(|this| P(this.lower_expr(cond))),
                         this.lower_block(body, false),
-                        this.lower_opt_sp_ident(opt_ident)))
+                        this.lower_label(opt_label)))
             }
-            ExprKind::Loop(ref body, opt_ident) => {
+            ExprKind::Loop(ref body, opt_label) => {
                 self.with_loop_scope(e.id, |this|
                     hir::ExprLoop(this.lower_block(body, false),
-                                  this.lower_opt_sp_ident(opt_ident),
+                                  this.lower_label(opt_label),
                                   hir::LoopSource::Loop))
             }
             ExprKind::Catch(ref body) => {
@@ -2877,30 +2877,30 @@ impl<'a> LoweringContext<'a> {
                 hir::ExprPath(self.lower_qpath(e.id, qself, path, ParamMode::Optional,
                                                ImplTraitContext::Disallowed))
             }
-            ExprKind::Break(opt_ident, ref opt_expr) => {
-                let label_result = if self.is_in_loop_condition && opt_ident.is_none() {
+            ExprKind::Break(opt_label, ref opt_expr) => {
+                let destination = if self.is_in_loop_condition && opt_label.is_none() {
                     hir::Destination {
-                        ident: opt_ident,
+                        label: None,
                         target_id: hir::ScopeTarget::Loop(
                                 Err(hir::LoopIdError::UnlabeledCfInWhileCondition).into()),
                     }
                 } else {
-                    self.lower_loop_destination(opt_ident.map(|ident| (e.id, ident)))
+                    self.lower_loop_destination(opt_label.map(|label| (e.id, label)))
                 };
                 hir::ExprBreak(
-                        label_result,
+                        destination,
                         opt_expr.as_ref().map(|x| P(self.lower_expr(x))))
             }
-            ExprKind::Continue(opt_ident) =>
+            ExprKind::Continue(opt_label) =>
                 hir::ExprAgain(
-                    if self.is_in_loop_condition && opt_ident.is_none() {
+                    if self.is_in_loop_condition && opt_label.is_none() {
                         hir::Destination {
-                            ident: opt_ident,
+                            label: None,
                             target_id: hir::ScopeTarget::Loop(Err(
                                 hir::LoopIdError::UnlabeledCfInWhileCondition).into()),
                         }
                     } else {
-                        self.lower_loop_destination(opt_ident.map( |ident| (e.id, ident)))
+                        self.lower_loop_destination(opt_label.map(|label| (e.id, label)))
                     }),
             ExprKind::Ret(ref e) => hir::ExprRet(e.as_ref().map(|x| P(self.lower_expr(x)))),
             ExprKind::InlineAsm(ref asm) => {
@@ -3000,7 +3000,7 @@ impl<'a> LoweringContext<'a> {
 
             // Desugar ExprWhileLet
             // From: `[opt_ident]: while let <pat> = <sub_expr> <body>`
-            ExprKind::WhileLet(ref pat, ref sub_expr, ref body, opt_ident) => {
+            ExprKind::WhileLet(ref pat, ref sub_expr, ref body, opt_label) => {
                 // to:
                 //
                 //   [opt_ident]: loop {
@@ -3041,7 +3041,7 @@ impl<'a> LoweringContext<'a> {
 
                 // `[opt_ident]: loop { ... }`
                 let loop_block = P(self.block_expr(P(match_expr)));
-                let loop_expr = hir::ExprLoop(loop_block, self.lower_opt_sp_ident(opt_ident),
+                let loop_expr = hir::ExprLoop(loop_block, self.lower_label(opt_label),
                                               hir::LoopSource::WhileLet);
                 // add attributes to the outer returned expr node
                 loop_expr
@@ -3049,7 +3049,7 @@ impl<'a> LoweringContext<'a> {
 
             // Desugar ExprForLoop
             // From: `[opt_ident]: for <pat> in <head> <body>`
-            ExprKind::ForLoop(ref pat, ref head, ref body, opt_ident) => {
+            ExprKind::ForLoop(ref pat, ref head, ref body, opt_label) => {
                 // to:
                 //
                 //   {
@@ -3150,7 +3150,7 @@ impl<'a> LoweringContext<'a> {
                                                   None));
 
                 // `[opt_ident]: loop { ... }`
-                let loop_expr = hir::ExprLoop(loop_block, self.lower_opt_sp_ident(opt_ident),
+                let loop_expr = hir::ExprLoop(loop_block, self.lower_label(opt_label),
                                               hir::LoopSource::ForLoop);
                 let LoweredNodeId { node_id, hir_id } = self.lower_node_id(e.id);
                 let loop_expr = P(hir::Expr {
@@ -3270,7 +3270,7 @@ impl<'a> LoweringContext<'a> {
                             e.span,
                             hir::ExprBreak(
                                 hir::Destination {
-                                    ident: None,
+                                    label: None,
                                     target_id: hir::ScopeTarget::Block(catch_node),
                                 },
                                 Some(from_err_expr)
diff --git a/src/librustc/hir/mod.rs b/src/librustc/hir/mod.rs
index 8921fecf1b8..2854b9da147 100644
--- a/src/librustc/hir/mod.rs
+++ b/src/librustc/hir/mod.rs
@@ -34,7 +34,7 @@ use util::nodemap::{NodeMap, FxHashSet};
 use syntax_pos::{Span, DUMMY_SP};
 use syntax::codemap::{self, Spanned};
 use syntax::abi::Abi;
-use syntax::ast::{self, Ident, Name, NodeId, DUMMY_NODE_ID, AsmDialect};
+use syntax::ast::{self, Name, NodeId, DUMMY_NODE_ID, AsmDialect};
 use syntax::ast::{Attribute, Lit, StrStyle, FloatTy, IntTy, UintTy, MetaItem};
 use syntax::ext::hygiene::SyntaxContext;
 use syntax::ptr::P;
@@ -173,6 +173,18 @@ pub const DUMMY_HIR_ID: HirId = HirId {
 pub const DUMMY_ITEM_LOCAL_ID: ItemLocalId = ItemLocalId(!0);
 
 #[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Copy)]
+pub struct Label {
+    pub name: Name,
+    pub span: Span,
+}
+
+impl fmt::Debug for Label {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        write!(f, "label({:?})", self.name)
+    }
+}
+
+#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Copy)]
 pub struct Lifetime {
     pub id: NodeId,
     pub span: Span,
@@ -1276,11 +1288,11 @@ pub enum Expr_ {
     /// A while loop, with an optional label
     ///
     /// `'label: while expr { block }`
-    ExprWhile(P<Expr>, P<Block>, Option<Spanned<Name>>),
+    ExprWhile(P<Expr>, P<Block>, Option<Label>),
     /// Conditionless loop (can be exited with break, continue, or return)
     ///
     /// `'label: loop { block }`
-    ExprLoop(P<Block>, Option<Spanned<Name>>, LoopSource),
+    ExprLoop(P<Block>, Option<Label>, LoopSource),
     /// A `match` block, with a source that indicates whether or not it is
     /// the result of a desugaring, and if so, which kind.
     ExprMatch(P<Expr>, HirVec<Arm>, MatchSource),
@@ -1459,7 +1471,7 @@ impl ScopeTarget {
 #[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug, Copy)]
 pub struct Destination {
     // This is `Some(_)` iff there is an explicit user-specified `label
-    pub ident: Option<Spanned<Ident>>,
+    pub label: Option<Label>,
 
     // These errors are caught and then reported during the diagnostics pass in
     // librustc_passes/loops.rs
diff --git a/src/librustc/hir/print.rs b/src/librustc/hir/print.rs
index 4cfa7a470a4..30c1ad01d14 100644
--- a/src/librustc/hir/print.rs
+++ b/src/librustc/hir/print.rs
@@ -1337,9 +1337,9 @@ impl<'a> State<'a> {
             hir::ExprIf(ref test, ref blk, ref elseopt) => {
                 self.print_if(&test, &blk, elseopt.as_ref().map(|e| &**e))?;
             }
-            hir::ExprWhile(ref test, ref blk, opt_sp_name) => {
-                if let Some(sp_name) = opt_sp_name {
-                    self.print_name(sp_name.node)?;
+            hir::ExprWhile(ref test, ref blk, opt_label) => {
+                if let Some(label) = opt_label {
+                    self.print_name(label.name)?;
                     self.word_space(":")?;
                 }
                 self.head("while")?;
@@ -1347,9 +1347,9 @@ impl<'a> State<'a> {
                 self.s.space()?;
                 self.print_block(&blk)?;
             }
-            hir::ExprLoop(ref blk, opt_sp_name, _) => {
-                if let Some(sp_name) = opt_sp_name {
-                    self.print_name(sp_name.node)?;
+            hir::ExprLoop(ref blk, opt_label, _) => {
+                if let Some(label) = opt_label {
+                    self.print_name(label.name)?;
                     self.word_space(":")?;
                 }
                 self.head("loop")?;
@@ -1424,11 +1424,11 @@ impl<'a> State<'a> {
             hir::ExprPath(ref qpath) => {
                 self.print_qpath(qpath, true)?
             }
-            hir::ExprBreak(label, ref opt_expr) => {
+            hir::ExprBreak(destination, ref opt_expr) => {
                 self.s.word("break")?;
                 self.s.space()?;
-                if let Some(label_ident) = label.ident {
-                    self.print_name(label_ident.node.name)?;
+                if let Some(label) = destination.label {
+                    self.print_name(label.name)?;
                     self.s.space()?;
                 }
                 if let Some(ref expr) = *opt_expr {
@@ -1436,11 +1436,11 @@ impl<'a> State<'a> {
                     self.s.space()?;
                 }
             }
-            hir::ExprAgain(label) => {
+            hir::ExprAgain(destination) => {
                 self.s.word("continue")?;
                 self.s.space()?;
-                if let Some(label_ident) = label.ident {
-                    self.print_name(label_ident.node.name)?;
+                if let Some(label) = destination.label {
+                    self.print_name(label.name)?;
                     self.s.space()?
                 }
             }
diff --git a/src/librustc/ich/impls_hir.rs b/src/librustc/ich/impls_hir.rs
index 59d9db48bdc..7dca96f94e6 100644
--- a/src/librustc/ich/impls_hir.rs
+++ b/src/librustc/ich/impls_hir.rs
@@ -148,6 +148,11 @@ impl_stable_hash_for!(enum hir::LifetimeName {
     Name(name)
 });
 
+impl_stable_hash_for!(struct hir::Label {
+    span,
+    name
+});
+
 impl_stable_hash_for!(struct hir::Lifetime {
     id,
     span,
@@ -619,7 +624,7 @@ impl_stable_hash_for!(enum hir::CaptureClause {
 impl_stable_hash_for_spanned!(usize);
 
 impl_stable_hash_for!(struct hir::Destination {
-    ident,
+    label,
     target_id
 });
 
diff --git a/src/librustc/middle/resolve_lifetime.rs b/src/librustc/middle/resolve_lifetime.rs
index 935dfd75dd8..944d7705163 100644
--- a/src/librustc/middle/resolve_lifetime.rs
+++ b/src/librustc/middle/resolve_lifetime.rs
@@ -1018,7 +1018,7 @@ fn extract_labels(ctxt: &mut LifetimeContext<'_, '_>, body: &hir::Body) {
     fn expression_label(ex: &hir::Expr) -> Option<(ast::Name, Span)> {
         match ex.node {
             hir::ExprWhile(.., Some(label)) | hir::ExprLoop(_, Some(label), _) => {
-                Some((label.node, label.span))
+                Some((label.name, label.span))
             }
             _ => None,
         }
diff --git a/src/librustc_passes/ast_validation.rs b/src/librustc_passes/ast_validation.rs
index 3f49128d2e8..6971033c899 100644
--- a/src/librustc_passes/ast_validation.rs
+++ b/src/librustc_passes/ast_validation.rs
@@ -141,14 +141,6 @@ impl<'a> AstValidator<'a> {
 impl<'a> Visitor<'a> for AstValidator<'a> {
     fn visit_expr(&mut self, expr: &'a Expr) {
         match expr.node {
-            ExprKind::While(.., Some(ident)) |
-            ExprKind::Loop(_, Some(ident)) |
-            ExprKind::WhileLet(.., Some(ident)) |
-            ExprKind::ForLoop(.., Some(ident)) |
-            ExprKind::Break(Some(ident), _) |
-            ExprKind::Continue(Some(ident)) => {
-                self.check_label(ident.node, ident.span);
-            }
             ExprKind::InlineAsm(..) if !self.session.target.target.options.allow_asm => {
                 span_err!(self.session, expr.span, E0472, "asm! is unsupported on this target");
             }
@@ -211,6 +203,11 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
         visit::walk_use_tree(self, use_tree, id);
     }
 
+    fn visit_label(&mut self, label: &'a Label) {
+        self.check_label(label.ident, label.span);
+        visit::walk_label(self, label);
+    }
+
     fn visit_lifetime(&mut self, lifetime: &'a Lifetime) {
         self.check_lifetime(lifetime);
         visit::walk_lifetime(self, lifetime);
diff --git a/src/librustc_resolve/lib.rs b/src/librustc_resolve/lib.rs
index 55c7e5f3924..1df19b6b678 100644
--- a/src/librustc_resolve/lib.rs
+++ b/src/librustc_resolve/lib.rs
@@ -55,7 +55,7 @@ use syntax::attr;
 use syntax::ast::{Arm, BindingMode, Block, Crate, Expr, ExprKind};
 use syntax::ast::{FnDecl, ForeignItem, ForeignItemKind, GenericParam, Generics};
 use syntax::ast::{Item, ItemKind, ImplItem, ImplItemKind};
-use syntax::ast::{Local, Mutability, Pat, PatKind, Path};
+use syntax::ast::{Label, Local, Mutability, Pat, PatKind, Path};
 use syntax::ast::{QSelf, TraitItemKind, TraitRef, Ty, TyKind};
 use syntax::feature_gate::{feature_err, emit_feature_err, GateIssue};
 use syntax::parse::token;
@@ -3415,13 +3415,13 @@ impl<'a> Resolver<'a> {
         }
     }
 
-    fn with_resolved_label<F>(&mut self, label: Option<SpannedIdent>, id: NodeId, f: F)
+    fn with_resolved_label<F>(&mut self, label: Option<Label>, id: NodeId, f: F)
         where F: FnOnce(&mut Resolver)
     {
         if let Some(label) = label {
             let def = Def::Label(id);
             self.with_label_rib(|this| {
-                this.label_ribs.last_mut().unwrap().bindings.insert(label.node, def);
+                this.label_ribs.last_mut().unwrap().bindings.insert(label.ident, def);
                 f(this);
             });
         } else {
@@ -3429,7 +3429,7 @@ impl<'a> Resolver<'a> {
         }
     }
 
-    fn resolve_labeled_block(&mut self, label: Option<SpannedIdent>, id: NodeId, block: &Block) {
+    fn resolve_labeled_block(&mut self, label: Option<Label>, id: NodeId, block: &Block) {
         self.with_resolved_label(label, id, |this| this.visit_block(block));
     }
 
@@ -3452,19 +3452,19 @@ impl<'a> Resolver<'a> {
             }
 
             ExprKind::Break(Some(label), _) | ExprKind::Continue(Some(label)) => {
-                match self.search_label(label.node, |rib, id| rib.bindings.get(&id).cloned()) {
+                match self.search_label(label.ident, |rib, id| rib.bindings.get(&id).cloned()) {
                     None => {
                         // Search again for close matches...
                         // Picks the first label that is "close enough", which is not necessarily
                         // the closest match
-                        let close_match = self.search_label(label.node, |rib, ident| {
+                        let close_match = self.search_label(label.ident, |rib, ident| {
                             let names = rib.bindings.iter().map(|(id, _)| &id.name);
                             find_best_match_for_name(names, &*ident.name.as_str(), None)
                         });
                         self.record_def(expr.id, err_path_resolution());
                         resolve_error(self,
                                       label.span,
-                                      ResolutionError::UndeclaredLabel(&label.node.name.as_str(),
+                                      ResolutionError::UndeclaredLabel(&label.ident.name.as_str(),
                                                                        close_match));
                     }
                     Some(def @ Def::Label(_)) => {
diff --git a/src/libsyntax/ast.rs b/src/libsyntax/ast.rs
index d6e26057ea8..73810b3fe81 100644
--- a/src/libsyntax/ast.rs
+++ b/src/libsyntax/ast.rs
@@ -34,6 +34,18 @@ use std::rc::Rc;
 use std::u32;
 
 #[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Copy)]
+pub struct Label {
+    pub ident: Ident,
+    pub span: Span,
+}
+
+impl fmt::Debug for Label {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        write!(f, "label({:?})", self.ident)
+    }
+}
+
+#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Copy)]
 pub struct Lifetime {
     pub id: NodeId,
     pub span: Span,
@@ -1078,23 +1090,23 @@ pub enum ExprKind {
     /// A while loop, with an optional label
     ///
     /// `'label: while expr { block }`
-    While(P<Expr>, P<Block>, Option<SpannedIdent>),
+    While(P<Expr>, P<Block>, Option<Label>),
     /// A while-let loop, with an optional label
     ///
     /// `'label: while let pat = expr { block }`
     ///
     /// This is desugared to a combination of `loop` and `match` expressions.
-    WhileLet(P<Pat>, P<Expr>, P<Block>, Option<SpannedIdent>),
+    WhileLet(P<Pat>, P<Expr>, P<Block>, Option<Label>),
     /// A for loop, with an optional label
     ///
     /// `'label: for pat in expr { block }`
     ///
     /// This is desugared to a combination of `loop` and `match` expressions.
-    ForLoop(P<Pat>, P<Expr>, P<Block>, Option<SpannedIdent>),
+    ForLoop(P<Pat>, P<Expr>, P<Block>, Option<Label>),
     /// Conditionless loop (can be exited with break, continue, or return)
     ///
     /// `'label: loop { block }`
-    Loop(P<Block>, Option<SpannedIdent>),
+    Loop(P<Block>, Option<Label>),
     /// A `match` block.
     Match(P<Expr>, Vec<Arm>),
     /// A closure (for example, `move |a, b, c| a + b + c`)
@@ -1133,9 +1145,9 @@ pub enum ExprKind {
     /// A referencing operation (`&a` or `&mut a`)
     AddrOf(Mutability, P<Expr>),
     /// A `break`, with an optional label to break, and an optional expression
-    Break(Option<SpannedIdent>, Option<P<Expr>>),
+    Break(Option<Label>, Option<P<Expr>>),
     /// A `continue`, with an optional label
-    Continue(Option<SpannedIdent>),
+    Continue(Option<Label>),
     /// A `return`, with an optional value to be returned
     Ret(Option<P<Expr>>),
 
diff --git a/src/libsyntax/fold.rs b/src/libsyntax/fold.rs
index 1e605ba3ecd..0f8fe57e380 100644
--- a/src/libsyntax/fold.rs
+++ b/src/libsyntax/fold.rs
@@ -193,6 +193,10 @@ pub trait Folder : Sized {
         noop_fold_macro_def(def, self)
     }
 
+    fn fold_label(&mut self, label: Label) -> Label {
+        noop_fold_label(label, self)
+    }
+
     fn fold_lifetime(&mut self, l: Lifetime) -> Lifetime {
         noop_fold_lifetime(l, self)
     }
@@ -696,6 +700,13 @@ pub fn noop_fold_generic_params<T: Folder>(
     params.move_map(|p| fld.fold_generic_param(p))
 }
 
+pub fn noop_fold_label<T: Folder>(label: Label, fld: &mut T) -> Label {
+    Label {
+        ident: fld.fold_ident(label.ident),
+        span: fld.new_span(label.span),
+    }
+}
+
 pub fn noop_fold_lifetime<T: Folder>(l: Lifetime, fld: &mut T) -> Lifetime {
     Lifetime {
         id: fld.new_id(l.id),
@@ -1206,30 +1217,26 @@ pub fn noop_fold_expr<T: Folder>(Expr {id, node, span, attrs}: Expr, folder: &mu
                           folder.fold_block(tr),
                           fl.map(|x| folder.fold_expr(x)))
             }
-            ExprKind::While(cond, body, opt_ident) => {
+            ExprKind::While(cond, body, opt_label) => {
                 ExprKind::While(folder.fold_expr(cond),
                           folder.fold_block(body),
-                          opt_ident.map(|label| respan(folder.new_span(label.span),
-                                                       folder.fold_ident(label.node))))
+                          opt_label.map(|label| folder.fold_label(label)))
             }
-            ExprKind::WhileLet(pat, expr, body, opt_ident) => {
+            ExprKind::WhileLet(pat, expr, body, opt_label) => {
                 ExprKind::WhileLet(folder.fold_pat(pat),
                              folder.fold_expr(expr),
                              folder.fold_block(body),
-                             opt_ident.map(|label| respan(folder.new_span(label.span),
-                                                          folder.fold_ident(label.node))))
+                             opt_label.map(|label| folder.fold_label(label)))
             }
-            ExprKind::ForLoop(pat, iter, body, opt_ident) => {
+            ExprKind::ForLoop(pat, iter, body, opt_label) => {
                 ExprKind::ForLoop(folder.fold_pat(pat),
                             folder.fold_expr(iter),
                             folder.fold_block(body),
-                            opt_ident.map(|label| respan(folder.new_span(label.span),
-                                                         folder.fold_ident(label.node))))
+                            opt_label.map(|label| folder.fold_label(label)))
             }
-            ExprKind::Loop(body, opt_ident) => {
+            ExprKind::Loop(body, opt_label) => {
                 ExprKind::Loop(folder.fold_block(body),
-                               opt_ident.map(|label| respan(folder.new_span(label.span),
-                                                            folder.fold_ident(label.node))))
+                               opt_label.map(|label| folder.fold_label(label)))
             }
             ExprKind::Match(expr, arms) => {
                 ExprKind::Match(folder.fold_expr(expr),
@@ -1278,15 +1285,13 @@ pub fn noop_fold_expr<T: Folder>(Expr {id, node, span, attrs}: Expr, folder: &mu
                 });
                 ExprKind::Path(qself, folder.fold_path(path))
             }
-            ExprKind::Break(opt_ident, opt_expr) => {
-                ExprKind::Break(opt_ident.map(|label| respan(folder.new_span(label.span),
-                                                             folder.fold_ident(label.node))),
+            ExprKind::Break(opt_label, opt_expr) => {
+                ExprKind::Break(opt_label.map(|label| folder.fold_label(label)),
                                 opt_expr.map(|e| folder.fold_expr(e)))
             }
-            ExprKind::Continue(opt_ident) => ExprKind::Continue(opt_ident.map(|label|
-                respan(folder.new_span(label.span),
-                       folder.fold_ident(label.node)))
-            ),
+            ExprKind::Continue(opt_label) => {
+                ExprKind::Continue(opt_label.map(|label| folder.fold_label(label)))
+            }
             ExprKind::Ret(e) => ExprKind::Ret(e.map(|x| folder.fold_expr(x))),
             ExprKind::InlineAsm(asm) => ExprKind::InlineAsm(asm.map(|asm| {
                 InlineAsm {
diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs
index 8213d604b91..d393cab4718 100644
--- a/src/libsyntax/parse/parser.rs
+++ b/src/libsyntax/parse/parser.rs
@@ -23,7 +23,7 @@ use ast::{Field, FnDecl};
 use ast::{ForeignItem, ForeignItemKind, FunctionRetTy};
 use ast::GenericParam;
 use ast::{Ident, ImplItem, IsAuto, Item, ItemKind};
-use ast::{Lifetime, LifetimeDef, Lit, LitKind, UintTy};
+use ast::{Label, Lifetime, LifetimeDef, Lit, LitKind, UintTy};
 use ast::Local;
 use ast::MacStmtStyle;
 use ast::Mac_;
@@ -1325,15 +1325,17 @@ impl<'a> Parser<'a> {
             self.check_keyword(keywords::Extern)
     }
 
-    fn get_label(&mut self) -> ast::Ident {
-        match self.token {
+    fn eat_label(&mut self) -> Option<Label> {
+        let ident = match self.token {
             token::Lifetime(ref ident) => *ident,
             token::Interpolated(ref nt) => match nt.0 {
                 token::NtLifetime(lifetime) => lifetime.ident,
-                _ => self.bug("not a lifetime"),
+                _ => return None,
             },
-            _ => self.bug("not a lifetime"),
-        }
+            _ => return None,
+        };
+        self.bump();
+        Some(Label { ident, span: self.prev_span })
     }
 
     /// parse a TyKind::BareFn type:
@@ -2317,11 +2319,8 @@ impl<'a> Parser<'a> {
                     let lo = self.prev_span;
                     return self.parse_while_expr(None, lo, attrs);
                 }
-                if self.token.is_lifetime() {
-                    let label = Spanned { node: self.get_label(),
-                                          span: self.span };
-                    let lo = self.span;
-                    self.bump();
+                if let Some(label) = self.eat_label() {
+                    let lo = label.span;
                     self.expect(&token::Colon)?;
                     if self.eat_keyword(keywords::While) {
                         return self.parse_while_expr(Some(label), lo, attrs)
@@ -2339,16 +2338,8 @@ impl<'a> Parser<'a> {
                     return self.parse_loop_expr(None, lo, attrs);
                 }
                 if self.eat_keyword(keywords::Continue) {
-                    let ex = if self.token.is_lifetime() {
-                        let ex = ExprKind::Continue(Some(Spanned{
-                            node: self.get_label(),
-                            span: self.span
-                        }));
-                        self.bump();
-                        ex
-                    } else {
-                        ExprKind::Continue(None)
-                    };
+                    let label = self.eat_label();
+                    let ex = ExprKind::Continue(label);
                     let hi = self.prev_span;
                     return Ok(self.mk_expr(lo.to(hi), ex, attrs));
                 }
@@ -2376,16 +2367,7 @@ impl<'a> Parser<'a> {
                         ex = ExprKind::Ret(None);
                     }
                 } else if self.eat_keyword(keywords::Break) {
-                    let lt = if self.token.is_lifetime() {
-                        let spanned_lt = Spanned {
-                            node: self.get_label(),
-                            span: self.span
-                        };
-                        self.bump();
-                        Some(spanned_lt)
-                    } else {
-                        None
-                    };
+                    let label = self.eat_label();
                     let e = if self.token.can_begin_expr()
                                && !(self.token == token::OpenDelim(token::Brace)
                                     && self.restrictions.contains(
@@ -2394,7 +2376,7 @@ impl<'a> Parser<'a> {
                     } else {
                         None
                     };
-                    ex = ExprKind::Break(lt, e);
+                    ex = ExprKind::Break(label, e);
                     hi = self.prev_span;
                 } else if self.eat_keyword(keywords::Yield) {
                     if self.token.can_begin_expr() {
@@ -3291,7 +3273,7 @@ impl<'a> Parser<'a> {
     }
 
     /// Parse a 'for' .. 'in' expression ('for' token already eaten)
-    pub fn parse_for_expr(&mut self, opt_ident: Option<ast::SpannedIdent>,
+    pub fn parse_for_expr(&mut self, opt_label: Option<Label>,
                           span_lo: Span,
                           mut attrs: ThinVec<Attribute>) -> PResult<'a, P<Expr>> {
         // Parse: `for <src_pat> in <src_expr> <src_loop_block>`
@@ -3309,25 +3291,25 @@ impl<'a> Parser<'a> {
         attrs.extend(iattrs);
 
         let hi = self.prev_span;
-        Ok(self.mk_expr(span_lo.to(hi), ExprKind::ForLoop(pat, expr, loop_block, opt_ident), attrs))
+        Ok(self.mk_expr(span_lo.to(hi), ExprKind::ForLoop(pat, expr, loop_block, opt_label), attrs))
     }
 
     /// Parse a 'while' or 'while let' expression ('while' token already eaten)
-    pub fn parse_while_expr(&mut self, opt_ident: Option<ast::SpannedIdent>,
+    pub fn parse_while_expr(&mut self, opt_label: Option<Label>,
                             span_lo: Span,
                             mut attrs: ThinVec<Attribute>) -> PResult<'a, P<Expr>> {
         if self.token.is_keyword(keywords::Let) {
-            return self.parse_while_let_expr(opt_ident, span_lo, attrs);
+            return self.parse_while_let_expr(opt_label, span_lo, attrs);
         }
         let cond = self.parse_expr_res(Restrictions::NO_STRUCT_LITERAL, None)?;
         let (iattrs, body) = self.parse_inner_attrs_and_block()?;
         attrs.extend(iattrs);
         let span = span_lo.to(body.span);
-        return Ok(self.mk_expr(span, ExprKind::While(cond, body, opt_ident), attrs));
+        return Ok(self.mk_expr(span, ExprKind::While(cond, body, opt_label), attrs));
     }
 
     /// Parse a 'while let' expression ('while' token already eaten)
-    pub fn parse_while_let_expr(&mut self, opt_ident: Option<ast::SpannedIdent>,
+    pub fn parse_while_let_expr(&mut self, opt_label: Option<Label>,
                                 span_lo: Span,
                                 mut attrs: ThinVec<Attribute>) -> PResult<'a, P<Expr>> {
         self.expect_keyword(keywords::Let)?;
@@ -3337,17 +3319,17 @@ impl<'a> Parser<'a> {
         let (iattrs, body) = self.parse_inner_attrs_and_block()?;
         attrs.extend(iattrs);
         let span = span_lo.to(body.span);
-        return Ok(self.mk_expr(span, ExprKind::WhileLet(pat, expr, body, opt_ident), attrs));
+        return Ok(self.mk_expr(span, ExprKind::WhileLet(pat, expr, body, opt_label), attrs));
     }
 
     // parse `loop {...}`, `loop` token already eaten
-    pub fn parse_loop_expr(&mut self, opt_ident: Option<ast::SpannedIdent>,
+    pub fn parse_loop_expr(&mut self, opt_label: Option<Label>,
                            span_lo: Span,
                            mut attrs: ThinVec<Attribute>) -> PResult<'a, P<Expr>> {
         let (iattrs, body) = self.parse_inner_attrs_and_block()?;
         attrs.extend(iattrs);
         let span = span_lo.to(body.span);
-        Ok(self.mk_expr(span, ExprKind::Loop(body, opt_ident), attrs))
+        Ok(self.mk_expr(span, ExprKind::Loop(body, opt_label), attrs))
     }
 
     /// Parse a `do catch {...}` expression (`do catch` token already eaten)
diff --git a/src/libsyntax/print/pprust.rs b/src/libsyntax/print/pprust.rs
index 345c592a011..ae459c668aa 100644
--- a/src/libsyntax/print/pprust.rs
+++ b/src/libsyntax/print/pprust.rs
@@ -2104,9 +2104,9 @@ impl<'a> State<'a> {
             ast::ExprKind::IfLet(ref pat, ref expr, ref blk, ref elseopt) => {
                 self.print_if_let(pat, expr, blk, elseopt.as_ref().map(|e| &**e))?;
             }
-            ast::ExprKind::While(ref test, ref blk, opt_ident) => {
-                if let Some(ident) = opt_ident {
-                    self.print_ident(ident.node)?;
+            ast::ExprKind::While(ref test, ref blk, opt_label) => {
+                if let Some(label) = opt_label {
+                    self.print_ident(label.ident)?;
                     self.word_space(":")?;
                 }
                 self.head("while")?;
@@ -2114,9 +2114,9 @@ impl<'a> State<'a> {
                 self.s.space()?;
                 self.print_block_with_attrs(blk, attrs)?;
             }
-            ast::ExprKind::WhileLet(ref pat, ref expr, ref blk, opt_ident) => {
-                if let Some(ident) = opt_ident {
-                    self.print_ident(ident.node)?;
+            ast::ExprKind::WhileLet(ref pat, ref expr, ref blk, opt_label) => {
+                if let Some(label) = opt_label {
+                    self.print_ident(label.ident)?;
                     self.word_space(":")?;
                 }
                 self.head("while let")?;
@@ -2127,9 +2127,9 @@ impl<'a> State<'a> {
                 self.s.space()?;
                 self.print_block_with_attrs(blk, attrs)?;
             }
-            ast::ExprKind::ForLoop(ref pat, ref iter, ref blk, opt_ident) => {
-                if let Some(ident) = opt_ident {
-                    self.print_ident(ident.node)?;
+            ast::ExprKind::ForLoop(ref pat, ref iter, ref blk, opt_label) => {
+                if let Some(label) = opt_label {
+                    self.print_ident(label.ident)?;
                     self.word_space(":")?;
                 }
                 self.head("for")?;
@@ -2140,9 +2140,9 @@ impl<'a> State<'a> {
                 self.s.space()?;
                 self.print_block_with_attrs(blk, attrs)?;
             }
-            ast::ExprKind::Loop(ref blk, opt_ident) => {
-                if let Some(ident) = opt_ident {
-                    self.print_ident(ident.node)?;
+            ast::ExprKind::Loop(ref blk, opt_label) => {
+                if let Some(label) = opt_label {
+                    self.print_ident(label.ident)?;
                     self.word_space(":")?;
                 }
                 self.head("loop")?;
@@ -2238,11 +2238,11 @@ impl<'a> State<'a> {
             ast::ExprKind::Path(Some(ref qself), ref path) => {
                 self.print_qpath(path, qself, true)?
             }
-            ast::ExprKind::Break(opt_ident, ref opt_expr) => {
+            ast::ExprKind::Break(opt_label, ref opt_expr) => {
                 self.s.word("break")?;
                 self.s.space()?;
-                if let Some(ident) = opt_ident {
-                    self.print_ident(ident.node)?;
+                if let Some(label) = opt_label {
+                    self.print_ident(label.ident)?;
                     self.s.space()?;
                 }
                 if let Some(ref expr) = *opt_expr {
@@ -2250,11 +2250,11 @@ impl<'a> State<'a> {
                     self.s.space()?;
                 }
             }
-            ast::ExprKind::Continue(opt_ident) => {
+            ast::ExprKind::Continue(opt_label) => {
                 self.s.word("continue")?;
                 self.s.space()?;
-                if let Some(ident) = opt_ident {
-                    self.print_ident(ident.node)?;
+                if let Some(label) = opt_label {
+                    self.print_ident(label.ident)?;
                     self.s.space()?
                 }
             }
diff --git a/src/libsyntax/visit.rs b/src/libsyntax/visit.rs
index 8aeacf79cee..bbb123dab28 100644
--- a/src/libsyntax/visit.rs
+++ b/src/libsyntax/visit.rs
@@ -101,6 +101,9 @@ pub trait Visitor<'ast>: Sized {
     fn visit_variant(&mut self, v: &'ast Variant, g: &'ast Generics, item_id: NodeId) {
         walk_variant(self, v, g, item_id)
     }
+    fn visit_label(&mut self, label: &'ast Label) {
+        walk_label(self, label)
+    }
     fn visit_lifetime(&mut self, lifetime: &'ast Lifetime) {
         walk_lifetime(self, lifetime)
     }
@@ -163,25 +166,6 @@ macro_rules! walk_list {
     }
 }
 
-pub fn walk_opt_name<'a, V: Visitor<'a>>(visitor: &mut V, span: Span, opt_name: Option<Name>) {
-    if let Some(name) = opt_name {
-        visitor.visit_name(span, name);
-    }
-}
-
-pub fn walk_opt_ident<'a, V: Visitor<'a>>(visitor: &mut V, span: Span, opt_ident: Option<Ident>) {
-    if let Some(ident) = opt_ident {
-        visitor.visit_ident(span, ident);
-    }
-}
-
-pub fn walk_opt_sp_ident<'a, V: Visitor<'a>>(visitor: &mut V,
-                                             opt_sp_ident: &Option<Spanned<Ident>>) {
-    if let Some(ref sp_ident) = *opt_sp_ident {
-        visitor.visit_ident(sp_ident.span, sp_ident.node);
-    }
-}
-
 pub fn walk_ident<'a, V: Visitor<'a>>(visitor: &mut V, span: Span, ident: Ident) {
     visitor.visit_name(span, ident.name);
 }
@@ -204,6 +188,10 @@ pub fn walk_local<'a, V: Visitor<'a>>(visitor: &mut V, local: &'a Local) {
     walk_list!(visitor, visit_expr, &local.init);
 }
 
+pub fn walk_label<'a, V: Visitor<'a>>(visitor: &mut V, label: &'a Label) {
+    visitor.visit_ident(label.span, label.ident);
+}
+
 pub fn walk_lifetime<'a, V: Visitor<'a>>(visitor: &mut V, lifetime: &'a Lifetime) {
     visitor.visit_ident(lifetime.span, lifetime.ident);
 }
@@ -226,7 +214,9 @@ pub fn walk_item<'a, V: Visitor<'a>>(visitor: &mut V, item: &'a Item) {
     visitor.visit_ident(item.span, item.ident);
     match item.node {
         ItemKind::ExternCrate(opt_name) => {
-            walk_opt_name(visitor, item.span, opt_name)
+            if let Some(name) = opt_name {
+                visitor.visit_name(item.span, name);
+            }
         }
         ItemKind::Use(ref use_tree) => {
             visitor.visit_use_tree(use_tree, item.id, false)
@@ -622,7 +612,9 @@ pub fn walk_struct_def<'a, V: Visitor<'a>>(visitor: &mut V, struct_definition: &
 
 pub fn walk_struct_field<'a, V: Visitor<'a>>(visitor: &mut V, struct_field: &'a StructField) {
     visitor.visit_vis(&struct_field.vis);
-    walk_opt_ident(visitor, struct_field.span, struct_field.ident);
+    if let Some(ident) = struct_field.ident {
+        visitor.visit_ident(struct_field.span, ident);
+    }
     visitor.visit_ty(&struct_field.ty);
     walk_list!(visitor, visit_attribute, &struct_field.attrs);
 }
@@ -708,10 +700,10 @@ pub fn walk_expr<'a, V: Visitor<'a>>(visitor: &mut V, expression: &'a Expr) {
             visitor.visit_block(if_block);
             walk_list!(visitor, visit_expr, optional_else);
         }
-        ExprKind::While(ref subexpression, ref block, ref opt_sp_ident) => {
+        ExprKind::While(ref subexpression, ref block, ref opt_label) => {
+            walk_list!(visitor, visit_label, opt_label);
             visitor.visit_expr(subexpression);
             visitor.visit_block(block);
-            walk_opt_sp_ident(visitor, opt_sp_ident);
         }
         ExprKind::IfLet(ref pattern, ref subexpression, ref if_block, ref optional_else) => {
             visitor.visit_pat(pattern);
@@ -719,21 +711,21 @@ pub fn walk_expr<'a, V: Visitor<'a>>(visitor: &mut V, expression: &'a Expr) {
             visitor.visit_block(if_block);
             walk_list!(visitor, visit_expr, optional_else);
         }
-        ExprKind::WhileLet(ref pattern, ref subexpression, ref block, ref opt_sp_ident) => {
+        ExprKind::WhileLet(ref pattern, ref subexpression, ref block, ref opt_label) => {
+            walk_list!(visitor, visit_label, opt_label);
             visitor.visit_pat(pattern);
             visitor.visit_expr(subexpression);
             visitor.visit_block(block);
-            walk_opt_sp_ident(visitor, opt_sp_ident);
         }
-        ExprKind::ForLoop(ref pattern, ref subexpression, ref block, ref opt_sp_ident) => {
+        ExprKind::ForLoop(ref pattern, ref subexpression, ref block, ref opt_label) => {
+            walk_list!(visitor, visit_label, opt_label);
             visitor.visit_pat(pattern);
             visitor.visit_expr(subexpression);
             visitor.visit_block(block);
-            walk_opt_sp_ident(visitor, opt_sp_ident);
         }
-        ExprKind::Loop(ref block, ref opt_sp_ident) => {
+        ExprKind::Loop(ref block, ref opt_label) => {
+            walk_list!(visitor, visit_label, opt_label);
             visitor.visit_block(block);
-            walk_opt_sp_ident(visitor, opt_sp_ident);
         }
         ExprKind::Match(ref subexpression, ref arms) => {
             visitor.visit_expr(subexpression);
@@ -775,12 +767,12 @@ pub fn walk_expr<'a, V: Visitor<'a>>(visitor: &mut V, expression: &'a Expr) {
             }
             visitor.visit_path(path, expression.id)
         }
-        ExprKind::Break(ref opt_sp_ident, ref opt_expr) => {
-            walk_opt_sp_ident(visitor, opt_sp_ident);
+        ExprKind::Break(ref opt_label, ref opt_expr) => {
+            walk_list!(visitor, visit_label, opt_label);
             walk_list!(visitor, visit_expr, opt_expr);
         }
-        ExprKind::Continue(ref opt_sp_ident) => {
-            walk_opt_sp_ident(visitor, opt_sp_ident);
+        ExprKind::Continue(ref opt_label) => {
+            walk_list!(visitor, visit_label, opt_label);
         }
         ExprKind::Ret(ref optional_expression) => {
             walk_list!(visitor, visit_expr, optional_expression);