Make break and continue hygienic
Makes labelled loops hygiene by performing renaming of the labels defined in e.g. `'x: loop { ... }` and then used in break and continue statements within loop body so that they act hygienically when used with macros. Closes #12262.
This commit is contained in:
parent
551da06157
commit
386db05df8
18 changed files with 262 additions and 28 deletions
|
@ -139,6 +139,8 @@ pub fn expand_expr(e: @ast::Expr, fld: &mut MacroExpander) -> @ast::Expr {
|
|||
// Expand any interior macros etc.
|
||||
// NB: we don't fold pats yet. Curious.
|
||||
let src_expr = fld.fold_expr(src_expr).clone();
|
||||
// Rename label before expansion.
|
||||
let (opt_ident, src_loop_block) = rename_loop_label(opt_ident, src_loop_block, fld);
|
||||
let src_loop_block = fld.fold_block(src_loop_block);
|
||||
|
||||
let span = e.span;
|
||||
|
@ -165,8 +167,7 @@ pub fn expand_expr(e: @ast::Expr, fld: &mut MacroExpander) -> @ast::Expr {
|
|||
|
||||
// `None => break ['<ident>];`
|
||||
let none_arm = {
|
||||
// FIXME #6993: this map goes away:
|
||||
let break_expr = fld.cx.expr(span, ast::ExprBreak(opt_ident.map(|x| x.name)));
|
||||
let break_expr = fld.cx.expr(span, ast::ExprBreak(opt_ident));
|
||||
let none_pat = fld.cx.pat_ident(span, none_ident);
|
||||
fld.cx.arm(span, ~[none_pat], break_expr)
|
||||
};
|
||||
|
@ -199,10 +200,36 @@ pub fn expand_expr(e: @ast::Expr, fld: &mut MacroExpander) -> @ast::Expr {
|
|||
fld.cx.expr_match(span, discrim, ~[arm])
|
||||
}
|
||||
|
||||
ast::ExprLoop(loop_block, opt_ident) => {
|
||||
let (opt_ident, loop_block) =
|
||||
rename_loop_label(opt_ident, loop_block, fld);
|
||||
let loop_block = fld.fold_block(loop_block);
|
||||
fld.cx.expr(e.span, ast::ExprLoop(loop_block, opt_ident))
|
||||
}
|
||||
|
||||
_ => noop_fold_expr(e, fld)
|
||||
}
|
||||
}
|
||||
|
||||
// Rename loop label and its all occurrences inside the loop body
|
||||
fn rename_loop_label(opt_ident: Option<Ident>,
|
||||
loop_block: P<Block>,
|
||||
fld: &mut MacroExpander) -> (Option<Ident>, P<Block>) {
|
||||
match opt_ident {
|
||||
Some(label) => {
|
||||
// Generate fresh label and add to the existing pending renames
|
||||
let new_label = fresh_name(&label);
|
||||
let rename = (label, new_label);
|
||||
fld.extsbox.info().pending_renames.push(rename);
|
||||
let mut pending_renames = ~[rename];
|
||||
let mut rename_fld = renames_to_fold(&mut pending_renames);
|
||||
(Some(rename_fld.fold_ident(label)),
|
||||
rename_fld.fold_block(loop_block))
|
||||
}
|
||||
None => (None, loop_block)
|
||||
}
|
||||
}
|
||||
|
||||
// eval $e with a new exts frame:
|
||||
macro_rules! with_exts_frame (
|
||||
($extsboxexpr:expr,$macros_escape:expr,$e:expr) =>
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue