Skip to content

Macros attempting to expand to multiple items silently only expand to the first one #8012

New issue

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

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

Already on GitHub? # to your account

Closed
paulstansifer opened this issue Jul 23, 2013 · 6 comments · Fixed by #9673
Closed
Labels
A-syntaxext Area: Syntax extensions

Comments

@paulstansifer
Copy link
Contributor

Users who want a macro that expands to a collection items are required to wrap the RHS in {} in order to get them to expand to a whole block. However, if they fail to do so, they unexpectedly just get the first item of the block, rather than an error message.

macro_rules! print_if_nonzero(
    ($msg:expr, $($field:ident),*) => ( /*{*/
        $(
            if t.$field != 0 {
                println($msg);
            }
        )*
    /*}*/ )
)

struct T { x: int, y: int }

fn main() {
    let t = T { x: 0, y: 0 };
    print_if_nonzero!("hello", x, y);
}

...expands to...

fn main() { let t = T{x: 0, y: 0,}; if t.x != 0 { println("hello"); }; }
@paulstansifer
Copy link
Contributor Author

Thanks to kmc on IRC for reporting this.

@bstrie
Copy link
Contributor

bstrie commented Jul 24, 2013

Perhaps this is really just another plaintive cry for someone to tackle #4375.

@huonw
Copy link
Member

huonw commented Aug 5, 2013

Smaller testcase:

rusti> macro_rules! t( () => { println("hi"); println("oops"); }) t!()
hi
()

@nejucomo
Copy link

I don't understand how this is different than #4375. If not justification for the distinction is given, can we mark this as a duplicate?

@paulstansifer
Copy link
Contributor Author

This source of this problem probably isn't specific to items. I'm worried
that there's a lurking (if minor) usability problem in the lack of erroring
out in this case.

@kmcallister
Copy link
Contributor

Yeah, jason_ on IRC provided this example using tuples:

macro_rules! omg(($n:expr) => ($n,$n+1))
omg!(100) // => 100, not (100, 101)

bors added a commit that referenced this issue Oct 2, 2013
That is, only a single expression or item gets parsed, so if there are
any extra tokens (e.g. the start of another item/expression) the user
should be told, rather than silently dropping them.

An example:

    macro_rules! foo {
        () => {
            println("hi");
            println("bye);
        }
    }

would expand to just `println("hi")`, which is almost certainly not
what the programmer wanted.

Fixes #8012.
@huonw huonw closed this as completed in 8284df9 Oct 2, 2013
# for free to join this conversation on GitHub. Already have an account? # to comment
Labels
A-syntaxext Area: Syntax extensions
Projects
None yet
Development

Successfully merging a pull request may close this issue.

5 participants