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

Macro matching is incorrect for macros invoked in macro expansions #26361

Closed
reem opened this issue Jun 17, 2015 · 6 comments
Closed

Macro matching is incorrect for macros invoked in macro expansions #26361

reem opened this issue Jun 17, 2015 · 6 comments
Assignees
Labels
A-macros Area: All kinds of macros (custom derive, macro_rules!, proc macros, ..) C-bug Category: This is a bug. E-hard Call for participation: Hard difficulty. Experience needed to fix: A lot.

Comments

@reem
Copy link
Contributor

reem commented Jun 17, 2015

Example: http://is.gd/y5Wa67

This example should print "Type::Byte" but instead prints "Type::Struct". Calling ty_to_type! directly on u8 works, as does having forwards! receive a tt rather than a ty.

@bluss
Copy link
Member

bluss commented Jun 17, 2015

isn't this a feature too? I have macros where I don't want to risk that a user-supplied parameter matches such a “literal” parameter that you have in ‘bool’ etc in your example.

@steveklabnik steveklabnik added the A-macros Area: All kinds of macros (custom derive, macro_rules!, proc macros, ..) label Jun 23, 2015
@michaelsproul
Copy link
Contributor

I think the current behaviour makes sense - once you've matched u8 as a type its token represents that type and not the string "u8" any more.

@steveklabnik
Copy link
Member

@rust-lang/lang , is this a bug or not?

@eddyb
Copy link
Member

eddyb commented Jan 3, 2017

cc @jseyfried

@jseyfried jseyfried added the E-hard Call for participation: Hard difficulty. Experience needed to fix: A lot. label Jan 4, 2017
@nikomatsakis
Copy link
Contributor

Personally, I consider this a bug, but it may not be a bug we want to fix in the existing macros because of backwards compat. I've never liked how macros insert "pseudo-tokens" representing parsed entities -- although I understand the original motivation, which was to avoid the performance cost of re-parsing things over and over. I just think it should be an optimization, and not something that has visible effects on the behavior of the code.

(But all that said, it can't be as simple as "paste the tokens $foo where it appears". For example, if you have $l:expr and you do $l * $l, and $l = x + y, I would not want that to parse as x + (y * x) + y. So it seems like my mental model is that the tokens for $l are "pasted" in but inside a synthetic token tree of some kind.)

@jseyfried jseyfried self-assigned this Feb 1, 2017
bors added a commit that referenced this issue May 22, 2017
Initial implementation of declarative macros 2.0

Implement declarative macros 2.0 (rust-lang/rfcs#1584) behind `#![feature(decl_macro)]`.
Differences from `macro_rules!` include:
 - new syntax: `macro m(..) { .. }` instead of `macro_rules! m { (..) => { .. } }`
 - declarative macros are items:
```rust
// crate A:
mod foo {
    m!(); // use before definition; declaration order is irrelevant
    pub macro m() {} // `pub`, `pub(super)`, etc. work
}
fn main() {
    foo::m!(); // named like other items
    { use foo::m as n; n!(); } // imported like other items
}
pub use foo::m; // re-exported like other items

// crate B:
extern crate A; // no need for `#[macro_use]`
A::foo::m!(); A::m!();
```
 - Racket-like hygiene for items, imports, methods, fields, type parameters, privacy, etc.
   - Intuitively, names in a macro definition are resolved in the macro definition's scope, not the scope in which the macro is used.
   - This [explaination](http://beautifulracket.com/explainer/hygiene.html) of hygiene for Racket applies here (except for the "Breaking Hygiene" section). I wrote a similar [explanation](https://github.com/jseyfried/rfcs/blob/hygiene/text/0000-hygiene.md) for Rust.
   - Generally speaking, if `fn f() { <body> }` resolves, `pub macro m() { <body> } ... m!()` also resolves, even if `m!()` is in a separate crate.
   - `::foo::bar` in a `macro` behaves like `$crate::foo::bar` in a `macro_rules!`, except it can access everything visible from the `macro` (thus more permissive).
   - See [`src/test/{run-pass, compile-fail}/hygiene`](afe7d89) for examples. Small example:
```rust
mod foo {
    fn f() { println!("hello world"); }
    pub macro m() { f(); }
}
fn main() { foo::m!(); }
```

Limitations:
 - This does not address planned changes to matchers (`expr`,`ty`, etc.), c.f. #26361.
 - Lints (including stability and deprecation) and `unsafe` are not hygienic.
   - adding hygiene here will be mostly or entirely backwards compatible
 - Nested macro definitions (a `macro` inside another `macro`) don't always work correctly when invoked from external crates.
   - pending improvements in how we encode macro definitions in crate metadata
 - There is no way to "escape" hygiene without using a procedural macro.

r? @nrc
bors added a commit that referenced this issue May 25, 2017
Initial implementation of declarative macros 2.0

Implement declarative macros 2.0 (rust-lang/rfcs#1584) behind `#![feature(decl_macro)]`.
Differences from `macro_rules!` include:
 - new syntax: `macro m(..) { .. }` instead of `macro_rules! m { (..) => { .. } }`
 - declarative macros are items:
```rust
// crate A:
pub mod foo {
    m!(); // use before definition; declaration order is irrelevant
    pub macro m() {} // `pub`, `pub(super)`, etc. work
}
fn main() {
    foo::m!(); // named like other items
    { use foo::m as n; n!(); } // imported like other items
}
pub use foo::m; // re-exported like other items

// crate B:
extern crate A; // no need for `#[macro_use]`
A::foo::m!(); A::m!();
```
 - Racket-like hygiene for items, imports, methods, fields, type parameters, privacy, etc.
   - Intuitively, names in a macro definition are resolved in the macro definition's scope, not the scope in which the macro is used.
   - This [explaination](http://beautifulracket.com/explainer/hygiene.html) of hygiene for Racket applies here (except for the "Breaking Hygiene" section). I wrote a similar [explanation](https://github.com/jseyfried/rfcs/blob/hygiene/text/0000-hygiene.md) for Rust.
   - Generally speaking, if `fn f() { <body> }` resolves, `pub macro m() { <body> } ... m!()` also resolves, even if `m!()` is in a separate crate.
   - `::foo::bar` in a `macro` behaves like `$crate::foo::bar` in a `macro_rules!`, except it can access everything visible from the `macro` (thus more permissive).
   - See [`src/test/{run-pass, compile-fail}/hygiene`](afe7d89) for examples. Small example:
```rust
mod foo {
    fn f() { println!("hello world"); }
    pub macro m() { f(); }
}
fn main() { foo::m!(); }
```

Limitations:
 - This does not address planned changes to matchers (`expr`,`ty`, etc.), c.f. #26361.
 - Lints (including stability and deprecation) and `unsafe` are not hygienic.
   - adding hygiene here will be mostly or entirely backwards compatible
 - Nested macro definitions (a `macro` inside another `macro`) don't always work correctly when invoked from external crates.
   - pending improvements in how we encode macro definitions in crate metadata
 - There is no way to "escape" hygiene without using a procedural macro.

r? @nrc
@Mark-Simulacrum Mark-Simulacrum added the C-bug Category: This is a bug. label Jul 22, 2017
@steveklabnik
Copy link
Member

Triage: not any changes here. Per niko's last comment, I am guessing this is a WONTFIX, especially given that nobody else other than the original reporter has commented here, really. I'm gonna give this one a close for now, please let me know if this is still useful to track.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
A-macros Area: All kinds of macros (custom derive, macro_rules!, proc macros, ..) C-bug Category: This is a bug. E-hard Call for participation: Hard difficulty. Experience needed to fix: A lot.
Projects
None yet
Development

No branches or pull requests

8 participants