auto merge of #12338 : edwardw/rust/hygienic-break-continue, r=cmr
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:
commit
329fcd48e5
18 changed files with 262 additions and 28 deletions
|
|
@ -490,7 +490,7 @@ impl CFGBuilder {
|
|||
|
||||
fn find_scope(&self,
|
||||
expr: @ast::Expr,
|
||||
label: Option<ast::Name>) -> LoopScope {
|
||||
label: Option<ast::Ident>) -> LoopScope {
|
||||
match label {
|
||||
None => {
|
||||
return *self.loop_scopes.last().unwrap();
|
||||
|
|
|
|||
|
|
@ -770,7 +770,7 @@ impl<'a, O:DataFlowOperator> PropagationContext<'a, O> {
|
|||
|
||||
fn find_scope<'a>(&self,
|
||||
expr: &ast::Expr,
|
||||
label: Option<ast::Name>,
|
||||
label: Option<ast::Ident>,
|
||||
loop_scopes: &'a mut ~[LoopScope]) -> &'a mut LoopScope {
|
||||
let index = match label {
|
||||
None => {
|
||||
|
|
|
|||
|
|
@ -747,7 +747,7 @@ impl Liveness {
|
|||
}
|
||||
|
||||
pub fn find_loop_scope(&self,
|
||||
opt_label: Option<Name>,
|
||||
opt_label: Option<Ident>,
|
||||
id: NodeId,
|
||||
sp: Span)
|
||||
-> NodeId {
|
||||
|
|
|
|||
|
|
@ -5206,13 +5206,13 @@ impl Resolver {
|
|||
ExprLoop(_, Some(label)) => {
|
||||
self.with_label_rib(|this| {
|
||||
let def_like = DlDef(DefLabel(expr.id));
|
||||
// plain insert (no renaming)
|
||||
{
|
||||
let mut label_ribs = this.label_ribs.borrow_mut();
|
||||
let rib = label_ribs.get()[label_ribs.get().len() -
|
||||
1];
|
||||
let mut bindings = rib.bindings.borrow_mut();
|
||||
bindings.get().insert(label.name, def_like);
|
||||
let renamed = mtwt_resolve(label);
|
||||
bindings.get().insert(renamed, def_like);
|
||||
}
|
||||
|
||||
visit::walk_expr(this, expr, ());
|
||||
|
|
@ -5223,11 +5223,12 @@ impl Resolver {
|
|||
|
||||
ExprBreak(Some(label)) | ExprAgain(Some(label)) => {
|
||||
let mut label_ribs = self.label_ribs.borrow_mut();
|
||||
match self.search_ribs(label_ribs.get(), label, expr.span) {
|
||||
let renamed = mtwt_resolve(label);
|
||||
match self.search_ribs(label_ribs.get(), renamed, expr.span) {
|
||||
None =>
|
||||
self.resolve_error(expr.span,
|
||||
format!("use of undeclared label `{}`",
|
||||
token::get_name(label))),
|
||||
token::get_ident(label))),
|
||||
Some(DlDef(def @ DefLabel(_))) => {
|
||||
// Since this def is a label, it is never read.
|
||||
self.record_def(expr.id, (def, LastMod(AllPublic)))
|
||||
|
|
|
|||
|
|
@ -25,7 +25,7 @@ use util::ppaux::Repr;
|
|||
use middle::trans::type_::Type;
|
||||
|
||||
use syntax::ast;
|
||||
use syntax::ast::Name;
|
||||
use syntax::ast::Ident;
|
||||
use syntax::ast_util;
|
||||
use syntax::codemap::Span;
|
||||
use syntax::parse::token::InternedString;
|
||||
|
|
@ -260,7 +260,7 @@ pub fn trans_loop<'a>(bcx:&'a Block<'a>,
|
|||
|
||||
pub fn trans_break_cont<'a>(bcx: &'a Block<'a>,
|
||||
expr_id: ast::NodeId,
|
||||
opt_label: Option<Name>,
|
||||
opt_label: Option<Ident>,
|
||||
exit: uint)
|
||||
-> &'a Block<'a> {
|
||||
let _icx = push_ctxt("trans_break_cont");
|
||||
|
|
@ -293,14 +293,14 @@ pub fn trans_break_cont<'a>(bcx: &'a Block<'a>,
|
|||
|
||||
pub fn trans_break<'a>(bcx: &'a Block<'a>,
|
||||
expr_id: ast::NodeId,
|
||||
label_opt: Option<Name>)
|
||||
label_opt: Option<Ident>)
|
||||
-> &'a Block<'a> {
|
||||
return trans_break_cont(bcx, expr_id, label_opt, cleanup::EXIT_BREAK);
|
||||
}
|
||||
|
||||
pub fn trans_cont<'a>(bcx: &'a Block<'a>,
|
||||
expr_id: ast::NodeId,
|
||||
label_opt: Option<Name>)
|
||||
label_opt: Option<Ident>)
|
||||
-> &'a Block<'a> {
|
||||
return trans_break_cont(bcx, expr_id, label_opt, cleanup::EXIT_LOOP);
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue