Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

break and continue are not hygienic #12262

Closed
flaper87 opened this issue Feb 14, 2014 · 14 comments · Fixed by #12338
Closed

break and continue are not hygienic #12262

flaper87 opened this issue Feb 14, 2014 · 14 comments · Fixed by #12338
Labels
A-parser Area: The parsing of Rust source code to an AST A-resolve Area: Name/path resolution done by `rustc_resolve` specifically A-syntaxext Area: Syntax extensions E-mentor Call for participation: This issue has a mentor. Use #t-compiler/help on Zulip for discussion.

Comments

@flaper87
Copy link
Contributor

Working on #6993 specifically on #12179 raised the fact that break and continue use Name as opposed of Ident. This was introduced in #9103 and unfortunately this change seems to have made them non-hygienic.

An example taken from @huonw comment:

#[feature(macro_rules)];

macro_rules! foo {
    ($e: expr) => {
        // $e shouldn't be able to interact with this 'x
        'x: loop { $e }
    }
}

fn main() {
    'x: loop {
        // i.e. this 'x should refer to the outer loop, but may be "captured"
        // by the 'x declaration inside foo
        foo!(break 'x);
        println!("should not be printed")
    }
}

Presumably, reverting the change should make them hygienic again.

I volunteer as a mentor for this fix.

@huonw
Copy link
Member

huonw commented Feb 15, 2014

Note that #9047 was caused by (semi-)hygienic break & continue.

@edwardw
Copy link
Contributor

edwardw commented Feb 15, 2014

My first try here: edwardw@4e06bc6

I may not fully revert the change of #9103 since three new tests still fail.

@flaper87
Copy link
Contributor Author

@edwardw Thanks, looking good. I think you can squash those test in a single test that ensures break and continue are hygienic.

Also, could you please add this test too?

macro_rules! foo {
    () => {
        // this should just break from this inner loop...
        'x: loop { break 'x; }
    }
}

'x: loop {
    // ...but it may refer to the outer 'x when used inside here
    foo!();
    println!("should be printed");
}

@flaper87
Copy link
Contributor Author

I may not fully revert the change of #9103 since three new tests still fail.

@edwardw Sorry, did you mean that with your changes those tests still fail?

@edwardw
Copy link
Contributor

edwardw commented Feb 15, 2014

Yes it was even with this change seconds ago: edwardw@9427d36

@edwardw
Copy link
Contributor

edwardw commented Feb 15, 2014

I noticed two things. One is that ast::NodeId seems to play a more important role in trans now. The other is rustc::middle::trans::controlflow::trans_break_cont has been radically changed since #9103.

@huonw
Copy link
Member

huonw commented Feb 16, 2014

@edwardw I think you need to be renaming the labels as you register them, e.g.:

diff --git a/src/librustc/middle/resolve.rs b/src/librustc/middle/resolve.rs
index 7eb9b23..99ce3f9 100644
--- a/src/librustc/middle/resolve.rs
+++ b/src/librustc/middle/resolve.rs
@@ -5177,7 +5177,7 @@ impl Resolver {
                         let rib = label_ribs.get()[label_ribs.get().len() -
                                                    1];
                         let mut bindings = rib.bindings.borrow_mut();
-                        bindings.get().insert(label.name, def_like);
+                        bindings.get().insert(mtwt_resolve(label), def_like);
                     }

                     visit::walk_expr(this, expr, ());

(Just building this to test it now.)

(You'll need to adjust the comments too.)

@huonw
Copy link
Member

huonw commented Feb 16, 2014

Also, I'd recommend that you have some compile-fail tests to double/triple check the hygiene is working, e.g.

macro_rules! foo { () => { break 'x; } } //~ ERROR use of undeclared label `x`

fn main() {
    'x: loop { foo!() }
}
macro_rules! foo { ($e: expr) => { 'x: loop { $e } } }

fn main() {
    foo!(break 'x); //~ ERROR use of undeclared label `x`
}

@huonw
Copy link
Member

huonw commented Feb 16, 2014

Ah, so the problem is actually the macro expansion never renames these idents... see syntax::ext::expand, e.g. the new_pending_renames interactions in expand_stmt (expand_expr would need something similar).

@edwardw
Copy link
Contributor

edwardw commented Feb 16, 2014

Tried to rename label of for loop: edwardw@9054b80 but the tests still fail.

@flaper87
Copy link
Contributor Author

Just a quick note based on your last commit. You need to do the rename for both ExprForLoop and ExprLoop

@edwardw
Copy link
Contributor

edwardw commented Feb 16, 2014

Oh, I leave ExprLoop out on purpose for now. I was hoping at least that for loop in main() and infinite loop in macro would work hygienically with the patch. Alas, even that fails.

@huonw
Copy link
Member

huonw commented Feb 17, 2014

@edwardw it might be easier to get feedback and iterate if you open a PR even if it's not ready (for commenting, etc.).

@edwardw
Copy link
Contributor

edwardw commented Feb 21, 2014

Can we remove the E-easy label? This one is far from easy.

@flaper87 flaper87 removed the E-easy label Feb 21, 2014
bors added a commit that referenced this issue Feb 23, 2014
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.
@bors bors closed this as completed in 386db05 Feb 24, 2014
bors added a commit to rust-lang-ci/rust that referenced this issue Jul 25, 2022
…in-macro-expansion, r=lnicola

ide: insert whitespace between 'mut' and 'self' in macro expansion

fixes rust-lang#12260
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
A-parser Area: The parsing of Rust source code to an AST A-resolve Area: Name/path resolution done by `rustc_resolve` specifically A-syntaxext Area: Syntax extensions E-mentor Call for participation: This issue has a mentor. Use #t-compiler/help on Zulip for discussion.
Projects
None yet
Development

Successfully merging a pull request may close this issue.

3 participants