Repository: rust
Issue: $crate in a macro pattern behaves oddly
Labels: A-macros,T-compiler,C-bug

<!--
Thank you for filing a bug report! 🐛 Please provide a short summary of the bug,
along with any information you feel relevant to replicating the bug.
-->

It is my opinion that this should not have been allowed in the first place, and should be forward-compat deprecated for eventual removal.

I tried this code:

```rust
macro_rules! m {
    ($crate) => {};
}
```

#### I expected to see this happen:

A compiler error. Likely,

```
error: missing fragment specifier
 --> src/lib.rs:2:6
  |
2 |     ($crate) => {};
  |      ^^^^^^
  |
  = note: `#[deny(missing_fragment_specifier)]` on by default
  = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
  = note: for more information, [see issue #40107 <https://github.com/rust-lang/rust/issues/40107>](https://github.com/rust-lang/rust/issues/40107)
```

#### Instead, this happened:

The macro compiles without any errors. Calling such a macro is difficult:

```rust
m!($crate); //~ error: no rules expected the token `$`

macro_rules! call {
    () => { m!($crate); };
}

call!(); // this works
```

The following illustrates what is going on here:

```rust
// lib.rs
#[macro_export]
macro_rules! lib_macro {
    ($crate) => {};
}

#[macro_export]
macro_rules! try_call {
    ($m:path) => {
        $m!($crate);
    };
}

// main.rs
use lib::*;

macro_rules! main_macro {
    ($crate) => {};
}

macro_rules! tt_macro {
    ($krate:tt) => {};
}

macro_rules! ident_macro {
    ($krate:ident) => {};
}

try_call!(lib_macro);
try_call!(main_macro);
try_call!(tt_macro);
try_call!(ident_macro);

fn main() {}
```

All of these calls work. What is happening is that `$crate` *even in macro patterns* is getting glued into a single identifier token. Thus, in the macro pattern, it can only be fulfilled by another glued `$crate` token, which is only possible do in the expansion of a macro.

I think it is better to forbid this usage, as it is strongly inconsistent with the behavior of other keywords in macro binders (they work like any other identifier and are currently not reserved in this position), and `$crate` is taught as

> Within a macro imported from a crate named `foo`, the special macro variable `$crate` will expand to `::foo`. [[old 1.5 edition of The Book](https://doc.rust-lang.org/1.5.0/book/macros.html#the-variable-crate)]

> Hygiene is also the reason that we need the `$crate` metavariable when our macro needs access to other items in the defining crate. What this special metavariable does is that it expands to an absolute path to the defining crate. [[The Little Book of Rust Macros](https://veykril.github.io/tlborm/decl-macros/minutiae/hygiene.html#crate)]

While both of these are subtly wrong (`$crate` can be observed to "expand" into a single identifier), they agree that `$crate` is semantically a "reserved binder" which expands to the crate that the containing `macro_rules!` is defined in.

The current behavior of `$crate` in macro pattern position is as a compound token (only producible with macros) is incompatible with this understanding of `$crate`, which is otherwise ([mostly](https://github.com/rust-lang/rust/issues/99035)) correct. The behavior of `$crate` in pattern position should by this definition be to

- without a fragment specifier, error indicating that a fragment specifier is missing (and perhaps also/instead)
- with a fragment specifier, error indicating that `$crate` is a reserved keyword name that cannot be used as a custom binder.

### Meta
<!--
If you're using the stable version of the compiler, you should also check if the
bug also exists in the beta or nightly versions.
-->

`rustc --version --verbose`:
```
rustc 1.64.0-nightly (27eb6d701 2022-07-04)
binary: rustc
commit-hash: 27eb6d7018e397cf98d51c205e3576951d766323
commit-date: 2022-07-04
host: x86_64-pc-windows-msvc
release: 1.64.0-nightly
LLVM version: 14.0.6
```