Reputation: 2662
I have a macro that gets called inside an unsafe
block which has the following pattern:
( $mrb:expr, $sig:expr, $args:ident, $name:ident : $t:tt) => {
let $args = uninitialized::<*const MRValue>();
let count = uninitialized::<i32>();
mrb_get_args($mrb, $sig, args!($name, $t), &$args as *const *const MRValue,
&count as *const i32);
};
I've expanded the macro with --pretty expanded,hygiene
which gives me:
let args /* 77#30 */ =
uninitialized /* 789#28
*/::<*const MRValue /* 793#28 */>();
let count /* 807#31 */ =
uninitialized /* 789#28 */::<i32 /* 68#28 */>();
mrb_get_args /* 805#28
*/(mrb /* 804#29 */, sig /* 797#29 */,
&v /* 76#33 */ as *const i32 /* 68#34 */,
&args /* 77#27 */ as
*const *const MRValue /* 793#28 */,
&count /* 807#28 */ as *const i32 /* 68#28 */);
args
appear to be the same (77
) and count also appear to be the same (807
), but I'm getting the following error nonetheless:
<mrusty macros>:24:20: 24:21 error: unresolved name `args`. Did you mean the macro `args!`? [E0425]
<mrusty macros>:24 mrb , sig , $ args , $ ( $ name : $ t ) , * ) ; conv ! (
^
<mrusty macros>:23:29: 24:48 note: in this expansion of args_rest! (defined in <mrusty macros>)
src/main.rs:12:47: 16:7 note: in this expansion of mrfn! (defined in <mrusty macros>)
<mrusty macros>:24:20: 24:21 help: run `rustc --explain E0425` to see a detailed explanation
<mrusty macros>:6:5: 6:10 error: unresolved name `count` [E0425]
<mrusty macros>:6 , & count as * const i32 ) ; } ; (
^~~~~
<mrusty macros>:23:29: 24:48 note: in this expansion of args_rest! (defined in <mrusty macros>)
src/main.rs:12:47: 16:7 note: in this expansion of mrfn! (defined in <mrusty macros>)
<mrusty macros>:6:5: 6:10 help: run `rustc --explain E0425` to see a detailed explanation
This looks fishy and it appears to be a bug, but I'd like another pair of eyes over this before I submit an issue on Rust.
Upvotes: 4
Views: 171
Reputation: 2662
The basic reason why this doesn't work is because multi-statement macros are broken. Any macros that don't return a value (e.g. a block) will only return the first statement.
macro_rules! example {
( $name:ident ) => {
let mut $name = 0;
let mut $name = 1;
}
}
fn main() {
example!(x);
println!("{}", x);
}
This example prints 0
, not 1
. The bug has been closed, though, at it will probably land in Rust 1.10.
In the meanwhile, use blocks where applicable.
Upvotes: 0
Reputation: 127941
Try this:
( $mrb:expr, $sig:expr, $args:ident, $name:ident : $t:tt) => {{
let $args = uninitialized::<*const MRValue>();
let count = uninitialized::<i32>();
mrb_get_args($mrb, $sig, args!($name, $t), &$args as *const *const MRValue,
&count as *const i32);
}};
(note that the body of the macro expansion is wrapped into the second set of braces)
I don't remember the exact reason why you need this, but the basic idea is that each statement in the macro expansion block is expanded with its own hygiene context, therefore $args
in the first line is not the same as $args
in the last line. If you put all the statements into a single block, however, the hygiene context becomes shared, and both expansions of $args
now refer to the same identifier. So, this is likely not a bug; it's just how macro expansion in Rust works.
Upvotes: 4