macro_rules! uwu {
(a a a a) => {};
}
uwu!(a a b a);
Addressed by https://github.com/rust-lang/rust/pull/103439
macro_rules! uwu {
(uwu) => {};
}
macro_rules! forward_uwus {
($uwu:expr) => { uwu! { $uwu } };
}
forward_uwus!(uwu);
macro_rules! mk_matcher {( $_0:literal ) => (
macro_rules! matcher {( $_0 ) => ()}
)}
mk_matcher!(0);
matcher!(0);
Maybe a lint of this happens in matcher position?
Generally, hygiene is too invisible and its semantics, not known/taught enough.
So when a subtle hygiene error occurs, it can be painstakingly difficult to fix.
Mainly, there is no debugging tool to show hygiene: invisible during expansions, and the expanded,hygiene
pass is just unreadable, even for macro-savy people.
For instance, hygiene errors do not mention the presence of equally named items in scope that are unaccessible due to hygiene;
It would be really nice if there was some reporting tool that mentioned smth along the lines of:
macro_rules! let_x_42 {() => (
let x = 42; // <--- 4. is defined here, with private hygiene -+
)} // |
// |
let_x_42!(); // <--- 3. created by this macro invocation, which --+
// |
dbg!(x); // 1. Error, no `x` in scope // |
// 2. note: there is a macro-defined `x` in scope here, though --+
macro_rules! clear_x {() => (
x = 0; // <--- 4. but the `x` name here has private hygiene --+
)} // |
// |
let mut x = 42; // <--------- 3. defined here --------------------+
// |
clear_x!(); // 1. Error, no `x` in scope in this macro invo // |
// 2. note: there is a caller-defined `x` in scope here, though --+
This is especially problematic when an unhygienic proc-macro, say:
#[proc_macro] pub
fn let_x_42(_: TokenStream) -> TokenStream {
stringify!(
let x = 42;
)
.parse().unwrap() // defaults to unhygienic `Span::call_site()`
}
#[proc_macro] pub
fn clear_x(_: TokenStream) -> TokenStream {
stringify!(
x = 0;
)
.parse().unwrap() // defaults to unhygienic `Span::call_site()`
}
Both of these will work when doing:
{
let_x_42!();
dbg!(x);
}
{
let mut x = 42;
clear_x!();
}
But if one then does:
macro_rules! let_x_42_proxied {( $($tt:tt)* ) => (
$crate::proc_macros::let_x_42! { $($tt)* }
)}
// ditto for `clear_x`
then the following fails:
{
let_x_42!();
dbg!(x); // Error, no `x` in scope!
}
{
let mut x = 42;
clear_x!(); // Error in the macro invocation: no `x` in scope!
}
The reason for this is quite subtle, and with no diagnostics whatsoever, quite puzzling and even disheartening (see https://discord.com/channels/273534239310479360/512792629516173323/1039234673009762314): the thing is that the unhygienic call_site()
of these proc-macros stems from the path::to::macro_name
, !
, {}
tokens used to invoke it. And these tokens are created at the definition site of the proxy
macros. Since the definition site of a macro_rules!
macro is semitransparent
/ is like Span::mixed_site()
for a proc-macro, we end up with the situation wherein by funneling a proc-macro through a macro_rules!
macro, it becomes more hygienic than it used to be.
call_site()
hygiene of the x
forged by the proc-macro matches the span of $crate::proc_macros::let_x_42! {
, and that these tokens, by virtue of being literally written within the definition of a macro_rules!
macros, have "private hygiene" w.r.t. the call-site of this proxy macro.macro_rules! uwu {
($($t:tt)*) => { $($t, $($t)*)* }
}
uwu!(a);
error: attempted to repeat an expression containing no syntax variables matched as repeating at this depth
--> src/lib.rs:2:27
|
2 | ($($t:tt)*) => { $($t, $($t)*)* }
| ^^^^
error: could not compile `playground` due to previous error
$
macro_rules! long_list {
($(finish:ident)*) => {};
}
long_list! { T }
error: no rules expected the token `T`
--> uwu.rs:7:15
|
3 | macro_rules! long_list {
| ---------------------- when calling this macro
...
7 | long_list! { T }
| ^ no rules expected this token in macro call
|
= note: while trying to match sequence start
or
or
By clicking below, you agree to our terms of service.
New to HackMD? Sign up
Syntax | Example | Reference | |
---|---|---|---|
# Header | Header | 基本排版 | |
- Unordered List |
|
||
1. Ordered List |
|
||
- [ ] Todo List |
|
||
> Blockquote | Blockquote |
||
**Bold font** | Bold font | ||
*Italics font* | Italics font | ||
~~Strikethrough~~ | |||
19^th^ | 19th | ||
H~2~O | H2O | ||
++Inserted text++ | Inserted text | ||
==Marked text== | Marked text | ||
[link text](https:// "title") | Link | ||
 | Image | ||
`Code` | Code |
在筆記中貼入程式碼 | |
```javascript var i = 0; ``` |
|
||
:smile: | ![]() |
Emoji list | |
{%youtube youtube_id %} | Externals | ||
$L^aT_eX$ | LaTeX | ||
:::info This is a alert area. ::: |
This is a alert area. |
On a scale of 0-10, how likely is it that you would recommend HackMD to your friends, family or business associates?
Please give us some advice and help us improve HackMD.
Do you want to remove this version name and description?
Syncing