1
Fork 0

Rollup merge of #47502 - petrochenkov:label, r=eddyb

AST/HIR: Add a separate structure for labels
This commit is contained in:
Alex Crichton 2018-01-25 12:48:49 -06:00 committed by GitHub
commit 98b375483c
13 changed files with 203 additions and 202 deletions

View file

@ -43,7 +43,6 @@
use syntax::abi::Abi; use syntax::abi::Abi;
use syntax::ast::{NodeId, CRATE_NODE_ID, Name, Attribute}; use syntax::ast::{NodeId, CRATE_NODE_ID, Name, Attribute};
use syntax::codemap::Spanned;
use syntax_pos::Span; use syntax_pos::Span;
use hir::*; use hir::*;
use hir::def::Def; 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) { fn visit_variant(&mut self, v: &'v Variant, g: &'v Generics, item_id: NodeId) {
walk_variant(self, v, g, item_id) 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) { fn visit_lifetime(&mut self, lifetime: &'v Lifetime) {
walk_lifetime(self, 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`. /// 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) { pub fn walk_crate<'v, V: Visitor<'v>>(visitor: &mut V, krate: &'v Crate) {
visitor.visit_mod(&krate.module, krate.span, CRATE_NODE_ID); 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); 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) { pub fn walk_lifetime<'v, V: Visitor<'v>>(visitor: &mut V, lifetime: &'v Lifetime) {
visitor.visit_id(lifetime.id); visitor.visit_id(lifetime.id);
match lifetime.name { match lifetime.name {
@ -452,7 +446,9 @@ pub fn walk_item<'v, V: Visitor<'v>>(visitor: &mut V, item: &'v Item) {
match item.node { match item.node {
ItemExternCrate(opt_name) => { ItemExternCrate(opt_name) => {
visitor.visit_id(item.id); 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, _) => { ItemUse(ref path, _) => {
visitor.visit_id(item.id); 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); visitor.visit_expr(if_block);
walk_list!(visitor, visit_expr, optional_else); 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_expr(subexpression);
visitor.visit_block(block); 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); visitor.visit_block(block);
walk_opt_sp_name(visitor, opt_sp_name);
} }
ExprMatch(ref subexpression, ref arms, _) => { ExprMatch(ref subexpression, ref arms, _) => {
visitor.visit_expr(subexpression); 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) => { ExprPath(ref qpath) => {
visitor.visit_qpath(qpath, expression.id, expression.span); visitor.visit_qpath(qpath, expression.id, expression.span);
} }
ExprBreak(label, ref opt_expr) => { ExprBreak(ref destination, ref opt_expr) => {
label.ident.map(|ident| { if let Some(ref label) = destination.label {
match label.target_id { visitor.visit_label(label);
match destination.target_id {
ScopeTarget::Block(node_id) | ScopeTarget::Block(node_id) |
ScopeTarget::Loop(LoopIdResult::Ok(node_id)) => ScopeTarget::Loop(LoopIdResult::Ok(node_id)) =>
visitor.visit_def_mention(Def::Label(node_id)), visitor.visit_def_mention(Def::Label(node_id)),
ScopeTarget::Loop(LoopIdResult::Err(_)) => {}, ScopeTarget::Loop(LoopIdResult::Err(_)) => {},
}; };
visitor.visit_name(ident.span, ident.node.name); }
});
walk_list!(visitor, visit_expr, opt_expr); walk_list!(visitor, visit_expr, opt_expr);
} }
ExprAgain(label) => { ExprAgain(ref destination) => {
label.ident.map(|ident| { if let Some(ref label) = destination.label {
match label.target_id { visitor.visit_label(label);
match destination.target_id {
ScopeTarget::Block(_) => bug!("can't `continue` to a non-loop block"), ScopeTarget::Block(_) => bug!("can't `continue` to a non-loop block"),
ScopeTarget::Loop(LoopIdResult::Ok(node_id)) => ScopeTarget::Loop(LoopIdResult::Ok(node_id)) =>
visitor.visit_def_mention(Def::Label(node_id)), visitor.visit_def_mention(Def::Label(node_id)),
ScopeTarget::Loop(LoopIdResult::Err(_)) => {}, ScopeTarget::Loop(LoopIdResult::Err(_)) => {},
}; };
visitor.visit_name(ident.span, ident.node.name); }
});
} }
ExprRet(ref optional_expression) => { ExprRet(ref optional_expression) => {
walk_list!(visitor, visit_expr, optional_expression); walk_list!(visitor, visit_expr, optional_expression);

View file

@ -773,22 +773,22 @@ impl<'a> LoweringContext<'a> {
*self.name_map.entry(ident).or_insert_with(|| Symbol::from_ident(ident)) *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>> { fn lower_label(&mut self, label: Option<Label>) -> Option<hir::Label> {
o_id.map(|sp_ident| respan(sp_ident.span, sp_ident.node.name)) 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 -> hir::Destination
{ {
match destination { match destination {
Some((id, label_ident)) => { Some((id, label)) => {
let target = if let Def::Label(loop_id) = self.expect_full_def(id) { let target = if let Def::Label(loop_id) = self.expect_full_def(id) {
hir::LoopIdResult::Ok(self.lower_node_id(loop_id).node_id) hir::LoopIdResult::Ok(self.lower_node_id(loop_id).node_id)
} else { } else {
hir::LoopIdResult::Err(hir::LoopIdError::UnresolvedLabel) hir::LoopIdResult::Err(hir::LoopIdError::UnresolvedLabel)
}; };
hir::Destination { hir::Destination {
ident: Some(label_ident), label: self.lower_label(Some(label)),
target_id: hir::ScopeTarget::Loop(target), target_id: hir::ScopeTarget::Loop(target),
} }
}, },
@ -798,7 +798,7 @@ impl<'a> LoweringContext<'a> {
.map(|innermost_loop_id| *innermost_loop_id); .map(|innermost_loop_id| *innermost_loop_id);
hir::Destination { hir::Destination {
ident: None, label: None,
target_id: hir::ScopeTarget::Loop( target_id: hir::ScopeTarget::Loop(
loop_id.map(|id| Ok(self.lower_node_id(id).node_id)) loop_id.map(|id| Ok(self.lower_node_id(id).node_id))
.unwrap_or(Err(hir::LoopIdError::OutsideLoopScope)) .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) 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| self.with_loop_scope(e.id, |this|
hir::ExprWhile( hir::ExprWhile(
this.with_loop_condition_scope(|this| P(this.lower_expr(cond))), this.with_loop_condition_scope(|this| P(this.lower_expr(cond))),
this.lower_block(body, false), 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| self.with_loop_scope(e.id, |this|
hir::ExprLoop(this.lower_block(body, false), hir::ExprLoop(this.lower_block(body, false),
this.lower_opt_sp_ident(opt_ident), this.lower_label(opt_label),
hir::LoopSource::Loop)) hir::LoopSource::Loop))
} }
ExprKind::Catch(ref body) => { ExprKind::Catch(ref body) => {
@ -2877,30 +2877,30 @@ impl<'a> LoweringContext<'a> {
hir::ExprPath(self.lower_qpath(e.id, qself, path, ParamMode::Optional, hir::ExprPath(self.lower_qpath(e.id, qself, path, ParamMode::Optional,
ImplTraitContext::Disallowed)) ImplTraitContext::Disallowed))
} }
ExprKind::Break(opt_ident, ref opt_expr) => { ExprKind::Break(opt_label, ref opt_expr) => {
let label_result = if self.is_in_loop_condition && opt_ident.is_none() { let destination = if self.is_in_loop_condition && opt_label.is_none() {
hir::Destination { hir::Destination {
ident: opt_ident, label: None,
target_id: hir::ScopeTarget::Loop( target_id: hir::ScopeTarget::Loop(
Err(hir::LoopIdError::UnlabeledCfInWhileCondition).into()), Err(hir::LoopIdError::UnlabeledCfInWhileCondition).into()),
} }
} else { } 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( hir::ExprBreak(
label_result, destination,
opt_expr.as_ref().map(|x| P(self.lower_expr(x)))) opt_expr.as_ref().map(|x| P(self.lower_expr(x))))
} }
ExprKind::Continue(opt_ident) => ExprKind::Continue(opt_label) =>
hir::ExprAgain( hir::ExprAgain(
if self.is_in_loop_condition && opt_ident.is_none() { if self.is_in_loop_condition && opt_label.is_none() {
hir::Destination { hir::Destination {
ident: opt_ident, label: None,
target_id: hir::ScopeTarget::Loop(Err( target_id: hir::ScopeTarget::Loop(Err(
hir::LoopIdError::UnlabeledCfInWhileCondition).into()), hir::LoopIdError::UnlabeledCfInWhileCondition).into()),
} }
} else { } 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::Ret(ref e) => hir::ExprRet(e.as_ref().map(|x| P(self.lower_expr(x)))),
ExprKind::InlineAsm(ref asm) => { ExprKind::InlineAsm(ref asm) => {
@ -3000,7 +3000,7 @@ impl<'a> LoweringContext<'a> {
// Desugar ExprWhileLet // Desugar ExprWhileLet
// From: `[opt_ident]: while let <pat> = <sub_expr> <body>` // 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: // to:
// //
// [opt_ident]: loop { // [opt_ident]: loop {
@ -3041,7 +3041,7 @@ impl<'a> LoweringContext<'a> {
// `[opt_ident]: loop { ... }` // `[opt_ident]: loop { ... }`
let loop_block = P(self.block_expr(P(match_expr))); 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); hir::LoopSource::WhileLet);
// add attributes to the outer returned expr node // add attributes to the outer returned expr node
loop_expr loop_expr
@ -3049,7 +3049,7 @@ impl<'a> LoweringContext<'a> {
// Desugar ExprForLoop // Desugar ExprForLoop
// From: `[opt_ident]: for <pat> in <head> <body>` // 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: // to:
// //
// { // {
@ -3150,7 +3150,7 @@ impl<'a> LoweringContext<'a> {
None)); None));
// `[opt_ident]: loop { ... }` // `[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); hir::LoopSource::ForLoop);
let LoweredNodeId { node_id, hir_id } = self.lower_node_id(e.id); let LoweredNodeId { node_id, hir_id } = self.lower_node_id(e.id);
let loop_expr = P(hir::Expr { let loop_expr = P(hir::Expr {
@ -3270,7 +3270,7 @@ impl<'a> LoweringContext<'a> {
e.span, e.span,
hir::ExprBreak( hir::ExprBreak(
hir::Destination { hir::Destination {
ident: None, label: None,
target_id: hir::ScopeTarget::Block(catch_node), target_id: hir::ScopeTarget::Block(catch_node),
}, },
Some(from_err_expr) Some(from_err_expr)

View file

@ -34,7 +34,7 @@ use util::nodemap::{NodeMap, FxHashSet};
use syntax_pos::{Span, DUMMY_SP}; use syntax_pos::{Span, DUMMY_SP};
use syntax::codemap::{self, Spanned}; use syntax::codemap::{self, Spanned};
use syntax::abi::Abi; 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::ast::{Attribute, Lit, StrStyle, FloatTy, IntTy, UintTy, MetaItem};
use syntax::ext::hygiene::SyntaxContext; use syntax::ext::hygiene::SyntaxContext;
use syntax::ptr::P; use syntax::ptr::P;
@ -172,6 +172,18 @@ pub const DUMMY_HIR_ID: HirId = HirId {
pub const DUMMY_ITEM_LOCAL_ID: ItemLocalId = ItemLocalId(!0); 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)] #[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Copy)]
pub struct Lifetime { pub struct Lifetime {
pub id: NodeId, pub id: NodeId,
@ -1276,11 +1288,11 @@ pub enum Expr_ {
/// A while loop, with an optional label /// A while loop, with an optional label
/// ///
/// `'label: while expr { block }` /// `'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) /// Conditionless loop (can be exited with break, continue, or return)
/// ///
/// `'label: loop { block }` /// `'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 /// A `match` block, with a source that indicates whether or not it is
/// the result of a desugaring, and if so, which kind. /// the result of a desugaring, and if so, which kind.
ExprMatch(P<Expr>, HirVec<Arm>, MatchSource), ExprMatch(P<Expr>, HirVec<Arm>, MatchSource),
@ -1459,7 +1471,7 @@ impl ScopeTarget {
#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug, Copy)] #[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug, Copy)]
pub struct Destination { pub struct Destination {
// This is `Some(_)` iff there is an explicit user-specified `label // 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 // These errors are caught and then reported during the diagnostics pass in
// librustc_passes/loops.rs // librustc_passes/loops.rs

View file

@ -1337,9 +1337,9 @@ impl<'a> State<'a> {
hir::ExprIf(ref test, ref blk, ref elseopt) => { hir::ExprIf(ref test, ref blk, ref elseopt) => {
self.print_if(&test, &blk, elseopt.as_ref().map(|e| &**e))?; self.print_if(&test, &blk, elseopt.as_ref().map(|e| &**e))?;
} }
hir::ExprWhile(ref test, ref blk, opt_sp_name) => { hir::ExprWhile(ref test, ref blk, opt_label) => {
if let Some(sp_name) = opt_sp_name { if let Some(label) = opt_label {
self.print_name(sp_name.node)?; self.print_name(label.name)?;
self.word_space(":")?; self.word_space(":")?;
} }
self.head("while")?; self.head("while")?;
@ -1347,9 +1347,9 @@ impl<'a> State<'a> {
self.s.space()?; self.s.space()?;
self.print_block(&blk)?; self.print_block(&blk)?;
} }
hir::ExprLoop(ref blk, opt_sp_name, _) => { hir::ExprLoop(ref blk, opt_label, _) => {
if let Some(sp_name) = opt_sp_name { if let Some(label) = opt_label {
self.print_name(sp_name.node)?; self.print_name(label.name)?;
self.word_space(":")?; self.word_space(":")?;
} }
self.head("loop")?; self.head("loop")?;
@ -1424,11 +1424,11 @@ impl<'a> State<'a> {
hir::ExprPath(ref qpath) => { hir::ExprPath(ref qpath) => {
self.print_qpath(qpath, true)? self.print_qpath(qpath, true)?
} }
hir::ExprBreak(label, ref opt_expr) => { hir::ExprBreak(destination, ref opt_expr) => {
self.s.word("break")?; self.s.word("break")?;
self.s.space()?; self.s.space()?;
if let Some(label_ident) = label.ident { if let Some(label) = destination.label {
self.print_name(label_ident.node.name)?; self.print_name(label.name)?;
self.s.space()?; self.s.space()?;
} }
if let Some(ref expr) = *opt_expr { if let Some(ref expr) = *opt_expr {
@ -1436,11 +1436,11 @@ impl<'a> State<'a> {
self.s.space()?; self.s.space()?;
} }
} }
hir::ExprAgain(label) => { hir::ExprAgain(destination) => {
self.s.word("continue")?; self.s.word("continue")?;
self.s.space()?; self.s.space()?;
if let Some(label_ident) = label.ident { if let Some(label) = destination.label {
self.print_name(label_ident.node.name)?; self.print_name(label.name)?;
self.s.space()? self.s.space()?
} }
} }

View file

@ -148,6 +148,11 @@ impl_stable_hash_for!(enum hir::LifetimeName {
Name(name) Name(name)
}); });
impl_stable_hash_for!(struct hir::Label {
span,
name
});
impl_stable_hash_for!(struct hir::Lifetime { impl_stable_hash_for!(struct hir::Lifetime {
id, id,
span, span,
@ -619,7 +624,7 @@ impl_stable_hash_for!(enum hir::CaptureClause {
impl_stable_hash_for_spanned!(usize); impl_stable_hash_for_spanned!(usize);
impl_stable_hash_for!(struct hir::Destination { impl_stable_hash_for!(struct hir::Destination {
ident, label,
target_id target_id
}); });

View file

@ -1018,7 +1018,7 @@ fn extract_labels(ctxt: &mut LifetimeContext<'_, '_>, body: &hir::Body) {
fn expression_label(ex: &hir::Expr) -> Option<(ast::Name, Span)> { fn expression_label(ex: &hir::Expr) -> Option<(ast::Name, Span)> {
match ex.node { match ex.node {
hir::ExprWhile(.., Some(label)) | hir::ExprLoop(_, Some(label), _) => { hir::ExprWhile(.., Some(label)) | hir::ExprLoop(_, Some(label), _) => {
Some((label.node, label.span)) Some((label.name, label.span))
} }
_ => None, _ => None,
} }

View file

@ -141,14 +141,6 @@ impl<'a> AstValidator<'a> {
impl<'a> Visitor<'a> for AstValidator<'a> { impl<'a> Visitor<'a> for AstValidator<'a> {
fn visit_expr(&mut self, expr: &'a Expr) { fn visit_expr(&mut self, expr: &'a Expr) {
match expr.node { 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 => { ExprKind::InlineAsm(..) if !self.session.target.target.options.allow_asm => {
span_err!(self.session, expr.span, E0472, "asm! is unsupported on this target"); 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); 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) { fn visit_lifetime(&mut self, lifetime: &'a Lifetime) {
self.check_lifetime(lifetime); self.check_lifetime(lifetime);
visit::walk_lifetime(self, lifetime); visit::walk_lifetime(self, lifetime);

View file

@ -55,7 +55,7 @@ use syntax::attr;
use syntax::ast::{Arm, BindingMode, Block, Crate, Expr, ExprKind}; use syntax::ast::{Arm, BindingMode, Block, Crate, Expr, ExprKind};
use syntax::ast::{FnDecl, ForeignItem, ForeignItemKind, GenericParam, Generics}; use syntax::ast::{FnDecl, ForeignItem, ForeignItemKind, GenericParam, Generics};
use syntax::ast::{Item, ItemKind, ImplItem, ImplItemKind}; 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::ast::{QSelf, TraitItemKind, TraitRef, Ty, TyKind};
use syntax::feature_gate::{feature_err, emit_feature_err, GateIssue}; use syntax::feature_gate::{feature_err, emit_feature_err, GateIssue};
use syntax::parse::token; 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) where F: FnOnce(&mut Resolver)
{ {
if let Some(label) = label { if let Some(label) = label {
let def = Def::Label(id); let def = Def::Label(id);
self.with_label_rib(|this| { 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); f(this);
}); });
} else { } 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)); 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)) => { 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 => { None => {
// Search again for close matches... // Search again for close matches...
// Picks the first label that is "close enough", which is not necessarily // Picks the first label that is "close enough", which is not necessarily
// the closest match // 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); let names = rib.bindings.iter().map(|(id, _)| &id.name);
find_best_match_for_name(names, &*ident.name.as_str(), None) find_best_match_for_name(names, &*ident.name.as_str(), None)
}); });
self.record_def(expr.id, err_path_resolution()); self.record_def(expr.id, err_path_resolution());
resolve_error(self, resolve_error(self,
label.span, label.span,
ResolutionError::UndeclaredLabel(&label.node.name.as_str(), ResolutionError::UndeclaredLabel(&label.ident.name.as_str(),
close_match)); close_match));
} }
Some(def @ Def::Label(_)) => { Some(def @ Def::Label(_)) => {

View file

@ -33,6 +33,18 @@ use std::fmt;
use std::rc::Rc; use std::rc::Rc;
use std::u32; 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)] #[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Copy)]
pub struct Lifetime { pub struct Lifetime {
pub id: NodeId, pub id: NodeId,
@ -1078,23 +1090,23 @@ pub enum ExprKind {
/// A while loop, with an optional label /// A while loop, with an optional label
/// ///
/// `'label: while expr { block }` /// `'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 /// A while-let loop, with an optional label
/// ///
/// `'label: while let pat = expr { block }` /// `'label: while let pat = expr { block }`
/// ///
/// This is desugared to a combination of `loop` and `match` expressions. /// 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 /// A for loop, with an optional label
/// ///
/// `'label: for pat in expr { block }` /// `'label: for pat in expr { block }`
/// ///
/// This is desugared to a combination of `loop` and `match` expressions. /// 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) /// Conditionless loop (can be exited with break, continue, or return)
/// ///
/// `'label: loop { block }` /// `'label: loop { block }`
Loop(P<Block>, Option<SpannedIdent>), Loop(P<Block>, Option<Label>),
/// A `match` block. /// A `match` block.
Match(P<Expr>, Vec<Arm>), Match(P<Expr>, Vec<Arm>),
/// A closure (for example, `move |a, b, c| a + b + c`) /// 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`) /// A referencing operation (`&a` or `&mut a`)
AddrOf(Mutability, P<Expr>), AddrOf(Mutability, P<Expr>),
/// A `break`, with an optional label to break, and an optional expression /// 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 /// A `continue`, with an optional label
Continue(Option<SpannedIdent>), Continue(Option<Label>),
/// A `return`, with an optional value to be returned /// A `return`, with an optional value to be returned
Ret(Option<P<Expr>>), Ret(Option<P<Expr>>),

View file

@ -193,6 +193,10 @@ pub trait Folder : Sized {
noop_fold_macro_def(def, self) 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 { fn fold_lifetime(&mut self, l: Lifetime) -> Lifetime {
noop_fold_lifetime(l, self) 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)) 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 { pub fn noop_fold_lifetime<T: Folder>(l: Lifetime, fld: &mut T) -> Lifetime {
Lifetime { Lifetime {
id: fld.new_id(l.id), 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), folder.fold_block(tr),
fl.map(|x| folder.fold_expr(x))) 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), ExprKind::While(folder.fold_expr(cond),
folder.fold_block(body), folder.fold_block(body),
opt_ident.map(|label| respan(folder.new_span(label.span), opt_label.map(|label| folder.fold_label(label)))
folder.fold_ident(label.node))))
} }
ExprKind::WhileLet(pat, expr, body, opt_ident) => { ExprKind::WhileLet(pat, expr, body, opt_label) => {
ExprKind::WhileLet(folder.fold_pat(pat), ExprKind::WhileLet(folder.fold_pat(pat),
folder.fold_expr(expr), folder.fold_expr(expr),
folder.fold_block(body), folder.fold_block(body),
opt_ident.map(|label| respan(folder.new_span(label.span), opt_label.map(|label| folder.fold_label(label)))
folder.fold_ident(label.node))))
} }
ExprKind::ForLoop(pat, iter, body, opt_ident) => { ExprKind::ForLoop(pat, iter, body, opt_label) => {
ExprKind::ForLoop(folder.fold_pat(pat), ExprKind::ForLoop(folder.fold_pat(pat),
folder.fold_expr(iter), folder.fold_expr(iter),
folder.fold_block(body), folder.fold_block(body),
opt_ident.map(|label| respan(folder.new_span(label.span), opt_label.map(|label| folder.fold_label(label)))
folder.fold_ident(label.node))))
} }
ExprKind::Loop(body, opt_ident) => { ExprKind::Loop(body, opt_label) => {
ExprKind::Loop(folder.fold_block(body), ExprKind::Loop(folder.fold_block(body),
opt_ident.map(|label| respan(folder.new_span(label.span), opt_label.map(|label| folder.fold_label(label)))
folder.fold_ident(label.node))))
} }
ExprKind::Match(expr, arms) => { ExprKind::Match(expr, arms) => {
ExprKind::Match(folder.fold_expr(expr), 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::Path(qself, folder.fold_path(path))
} }
ExprKind::Break(opt_ident, opt_expr) => { ExprKind::Break(opt_label, opt_expr) => {
ExprKind::Break(opt_ident.map(|label| respan(folder.new_span(label.span), ExprKind::Break(opt_label.map(|label| folder.fold_label(label)),
folder.fold_ident(label.node))),
opt_expr.map(|e| folder.fold_expr(e))) opt_expr.map(|e| folder.fold_expr(e)))
} }
ExprKind::Continue(opt_ident) => ExprKind::Continue(opt_ident.map(|label| ExprKind::Continue(opt_label) => {
respan(folder.new_span(label.span), ExprKind::Continue(opt_label.map(|label| folder.fold_label(label)))
folder.fold_ident(label.node))) }
),
ExprKind::Ret(e) => ExprKind::Ret(e.map(|x| folder.fold_expr(x))), ExprKind::Ret(e) => ExprKind::Ret(e.map(|x| folder.fold_expr(x))),
ExprKind::InlineAsm(asm) => ExprKind::InlineAsm(asm.map(|asm| { ExprKind::InlineAsm(asm) => ExprKind::InlineAsm(asm.map(|asm| {
InlineAsm { InlineAsm {

View file

@ -23,7 +23,7 @@ use ast::{Field, FnDecl};
use ast::{ForeignItem, ForeignItemKind, FunctionRetTy}; use ast::{ForeignItem, ForeignItemKind, FunctionRetTy};
use ast::GenericParam; use ast::GenericParam;
use ast::{Ident, ImplItem, IsAuto, Item, ItemKind}; 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::Local;
use ast::MacStmtStyle; use ast::MacStmtStyle;
use ast::Mac_; use ast::Mac_;
@ -1325,15 +1325,17 @@ impl<'a> Parser<'a> {
self.check_keyword(keywords::Extern) self.check_keyword(keywords::Extern)
} }
fn get_label(&mut self) -> ast::Ident { fn eat_label(&mut self) -> Option<Label> {
match self.token { let ident = match self.token {
token::Lifetime(ref ident) => *ident, token::Lifetime(ref ident) => *ident,
token::Interpolated(ref nt) => match nt.0 { token::Interpolated(ref nt) => match nt.0 {
token::NtLifetime(lifetime) => lifetime.ident, 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: /// parse a TyKind::BareFn type:
@ -2317,11 +2319,8 @@ impl<'a> Parser<'a> {
let lo = self.prev_span; let lo = self.prev_span;
return self.parse_while_expr(None, lo, attrs); return self.parse_while_expr(None, lo, attrs);
} }
if self.token.is_lifetime() { if let Some(label) = self.eat_label() {
let label = Spanned { node: self.get_label(), let lo = label.span;
span: self.span };
let lo = self.span;
self.bump();
self.expect(&token::Colon)?; self.expect(&token::Colon)?;
if self.eat_keyword(keywords::While) { if self.eat_keyword(keywords::While) {
return self.parse_while_expr(Some(label), lo, attrs) 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); return self.parse_loop_expr(None, lo, attrs);
} }
if self.eat_keyword(keywords::Continue) { if self.eat_keyword(keywords::Continue) {
let ex = if self.token.is_lifetime() { let label = self.eat_label();
let ex = ExprKind::Continue(Some(Spanned{ let ex = ExprKind::Continue(label);
node: self.get_label(),
span: self.span
}));
self.bump();
ex
} else {
ExprKind::Continue(None)
};
let hi = self.prev_span; let hi = self.prev_span;
return Ok(self.mk_expr(lo.to(hi), ex, attrs)); return Ok(self.mk_expr(lo.to(hi), ex, attrs));
} }
@ -2376,16 +2367,7 @@ impl<'a> Parser<'a> {
ex = ExprKind::Ret(None); ex = ExprKind::Ret(None);
} }
} else if self.eat_keyword(keywords::Break) { } else if self.eat_keyword(keywords::Break) {
let lt = if self.token.is_lifetime() { let label = self.eat_label();
let spanned_lt = Spanned {
node: self.get_label(),
span: self.span
};
self.bump();
Some(spanned_lt)
} else {
None
};
let e = if self.token.can_begin_expr() let e = if self.token.can_begin_expr()
&& !(self.token == token::OpenDelim(token::Brace) && !(self.token == token::OpenDelim(token::Brace)
&& self.restrictions.contains( && self.restrictions.contains(
@ -2394,7 +2376,7 @@ impl<'a> Parser<'a> {
} else { } else {
None None
}; };
ex = ExprKind::Break(lt, e); ex = ExprKind::Break(label, e);
hi = self.prev_span; hi = self.prev_span;
} else if self.eat_keyword(keywords::Yield) { } else if self.eat_keyword(keywords::Yield) {
if self.token.can_begin_expr() { if self.token.can_begin_expr() {
@ -3291,7 +3273,7 @@ impl<'a> Parser<'a> {
} }
/// Parse a 'for' .. 'in' expression ('for' token already eaten) /// 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, span_lo: Span,
mut attrs: ThinVec<Attribute>) -> PResult<'a, P<Expr>> { mut attrs: ThinVec<Attribute>) -> PResult<'a, P<Expr>> {
// Parse: `for <src_pat> in <src_expr> <src_loop_block>` // Parse: `for <src_pat> in <src_expr> <src_loop_block>`
@ -3309,25 +3291,25 @@ impl<'a> Parser<'a> {
attrs.extend(iattrs); attrs.extend(iattrs);
let hi = self.prev_span; 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) /// 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, span_lo: Span,
mut attrs: ThinVec<Attribute>) -> PResult<'a, P<Expr>> { mut attrs: ThinVec<Attribute>) -> PResult<'a, P<Expr>> {
if self.token.is_keyword(keywords::Let) { 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 cond = self.parse_expr_res(Restrictions::NO_STRUCT_LITERAL, None)?;
let (iattrs, body) = self.parse_inner_attrs_and_block()?; let (iattrs, body) = self.parse_inner_attrs_and_block()?;
attrs.extend(iattrs); attrs.extend(iattrs);
let span = span_lo.to(body.span); 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) /// 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, span_lo: Span,
mut attrs: ThinVec<Attribute>) -> PResult<'a, P<Expr>> { mut attrs: ThinVec<Attribute>) -> PResult<'a, P<Expr>> {
self.expect_keyword(keywords::Let)?; self.expect_keyword(keywords::Let)?;
@ -3337,17 +3319,17 @@ impl<'a> Parser<'a> {
let (iattrs, body) = self.parse_inner_attrs_and_block()?; let (iattrs, body) = self.parse_inner_attrs_and_block()?;
attrs.extend(iattrs); attrs.extend(iattrs);
let span = span_lo.to(body.span); 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 // 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, span_lo: Span,
mut attrs: ThinVec<Attribute>) -> PResult<'a, P<Expr>> { mut attrs: ThinVec<Attribute>) -> PResult<'a, P<Expr>> {
let (iattrs, body) = self.parse_inner_attrs_and_block()?; let (iattrs, body) = self.parse_inner_attrs_and_block()?;
attrs.extend(iattrs); attrs.extend(iattrs);
let span = span_lo.to(body.span); 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) /// Parse a `do catch {...}` expression (`do catch` token already eaten)

View file

@ -2104,9 +2104,9 @@ impl<'a> State<'a> {
ast::ExprKind::IfLet(ref pat, ref expr, ref blk, ref elseopt) => { ast::ExprKind::IfLet(ref pat, ref expr, ref blk, ref elseopt) => {
self.print_if_let(pat, expr, blk, elseopt.as_ref().map(|e| &**e))?; self.print_if_let(pat, expr, blk, elseopt.as_ref().map(|e| &**e))?;
} }
ast::ExprKind::While(ref test, ref blk, opt_ident) => { ast::ExprKind::While(ref test, ref blk, opt_label) => {
if let Some(ident) = opt_ident { if let Some(label) = opt_label {
self.print_ident(ident.node)?; self.print_ident(label.ident)?;
self.word_space(":")?; self.word_space(":")?;
} }
self.head("while")?; self.head("while")?;
@ -2114,9 +2114,9 @@ impl<'a> State<'a> {
self.s.space()?; self.s.space()?;
self.print_block_with_attrs(blk, attrs)?; self.print_block_with_attrs(blk, attrs)?;
} }
ast::ExprKind::WhileLet(ref pat, ref expr, ref blk, opt_ident) => { ast::ExprKind::WhileLet(ref pat, ref expr, ref blk, opt_label) => {
if let Some(ident) = opt_ident { if let Some(label) = opt_label {
self.print_ident(ident.node)?; self.print_ident(label.ident)?;
self.word_space(":")?; self.word_space(":")?;
} }
self.head("while let")?; self.head("while let")?;
@ -2127,9 +2127,9 @@ impl<'a> State<'a> {
self.s.space()?; self.s.space()?;
self.print_block_with_attrs(blk, attrs)?; self.print_block_with_attrs(blk, attrs)?;
} }
ast::ExprKind::ForLoop(ref pat, ref iter, ref blk, opt_ident) => { ast::ExprKind::ForLoop(ref pat, ref iter, ref blk, opt_label) => {
if let Some(ident) = opt_ident { if let Some(label) = opt_label {
self.print_ident(ident.node)?; self.print_ident(label.ident)?;
self.word_space(":")?; self.word_space(":")?;
} }
self.head("for")?; self.head("for")?;
@ -2140,9 +2140,9 @@ impl<'a> State<'a> {
self.s.space()?; self.s.space()?;
self.print_block_with_attrs(blk, attrs)?; self.print_block_with_attrs(blk, attrs)?;
} }
ast::ExprKind::Loop(ref blk, opt_ident) => { ast::ExprKind::Loop(ref blk, opt_label) => {
if let Some(ident) = opt_ident { if let Some(label) = opt_label {
self.print_ident(ident.node)?; self.print_ident(label.ident)?;
self.word_space(":")?; self.word_space(":")?;
} }
self.head("loop")?; self.head("loop")?;
@ -2238,11 +2238,11 @@ impl<'a> State<'a> {
ast::ExprKind::Path(Some(ref qself), ref path) => { ast::ExprKind::Path(Some(ref qself), ref path) => {
self.print_qpath(path, qself, true)? 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.word("break")?;
self.s.space()?; self.s.space()?;
if let Some(ident) = opt_ident { if let Some(label) = opt_label {
self.print_ident(ident.node)?; self.print_ident(label.ident)?;
self.s.space()?; self.s.space()?;
} }
if let Some(ref expr) = *opt_expr { if let Some(ref expr) = *opt_expr {
@ -2250,11 +2250,11 @@ impl<'a> State<'a> {
self.s.space()?; self.s.space()?;
} }
} }
ast::ExprKind::Continue(opt_ident) => { ast::ExprKind::Continue(opt_label) => {
self.s.word("continue")?; self.s.word("continue")?;
self.s.space()?; self.s.space()?;
if let Some(ident) = opt_ident { if let Some(label) = opt_label {
self.print_ident(ident.node)?; self.print_ident(label.ident)?;
self.s.space()? self.s.space()?
} }
} }

View file

@ -101,6 +101,9 @@ pub trait Visitor<'ast>: Sized {
fn visit_variant(&mut self, v: &'ast Variant, g: &'ast Generics, item_id: NodeId) { fn visit_variant(&mut self, v: &'ast Variant, g: &'ast Generics, item_id: NodeId) {
walk_variant(self, v, g, item_id) 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) { fn visit_lifetime(&mut self, lifetime: &'ast Lifetime) {
walk_lifetime(self, 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) { pub fn walk_ident<'a, V: Visitor<'a>>(visitor: &mut V, span: Span, ident: Ident) {
visitor.visit_name(span, ident.name); 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); 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) { pub fn walk_lifetime<'a, V: Visitor<'a>>(visitor: &mut V, lifetime: &'a Lifetime) {
visitor.visit_ident(lifetime.span, lifetime.ident); 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); visitor.visit_ident(item.span, item.ident);
match item.node { match item.node {
ItemKind::ExternCrate(opt_name) => { 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) => { ItemKind::Use(ref use_tree) => {
visitor.visit_use_tree(use_tree, item.id, false) 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) { pub fn walk_struct_field<'a, V: Visitor<'a>>(visitor: &mut V, struct_field: &'a StructField) {
visitor.visit_vis(&struct_field.vis); 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); visitor.visit_ty(&struct_field.ty);
walk_list!(visitor, visit_attribute, &struct_field.attrs); 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); visitor.visit_block(if_block);
walk_list!(visitor, visit_expr, optional_else); 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_expr(subexpression);
visitor.visit_block(block); visitor.visit_block(block);
walk_opt_sp_ident(visitor, opt_sp_ident);
} }
ExprKind::IfLet(ref pattern, ref subexpression, ref if_block, ref optional_else) => { ExprKind::IfLet(ref pattern, ref subexpression, ref if_block, ref optional_else) => {
visitor.visit_pat(pattern); 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); visitor.visit_block(if_block);
walk_list!(visitor, visit_expr, optional_else); 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_pat(pattern);
visitor.visit_expr(subexpression); visitor.visit_expr(subexpression);
visitor.visit_block(block); 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_pat(pattern);
visitor.visit_expr(subexpression); visitor.visit_expr(subexpression);
visitor.visit_block(block); 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); visitor.visit_block(block);
walk_opt_sp_ident(visitor, opt_sp_ident);
} }
ExprKind::Match(ref subexpression, ref arms) => { ExprKind::Match(ref subexpression, ref arms) => {
visitor.visit_expr(subexpression); 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) visitor.visit_path(path, expression.id)
} }
ExprKind::Break(ref opt_sp_ident, ref opt_expr) => { ExprKind::Break(ref opt_label, ref opt_expr) => {
walk_opt_sp_ident(visitor, opt_sp_ident); walk_list!(visitor, visit_label, opt_label);
walk_list!(visitor, visit_expr, opt_expr); walk_list!(visitor, visit_expr, opt_expr);
} }
ExprKind::Continue(ref opt_sp_ident) => { ExprKind::Continue(ref opt_label) => {
walk_opt_sp_ident(visitor, opt_sp_ident); walk_list!(visitor, visit_label, opt_label);
} }
ExprKind::Ret(ref optional_expression) => { ExprKind::Ret(ref optional_expression) => {
walk_list!(visitor, visit_expr, optional_expression); walk_list!(visitor, visit_expr, optional_expression);