Can't access local variable when on a nested macro
wolfiestyle opened this issue · 3 comments
wolfiestyle commented
It fails to use the local variable in [1], but it works fine in [2]
#[derive(Default, Debug)]
struct Test {
val: i32,
}
impl Test {
fn set_val(&mut self, arg: i32) {
self.val = arg;
}
}
macro_rules! setter {
($obj:expr, $field:ident, $value:expr) => {
paste::expr! { $obj.[<set_ $field>]($value); }
};
// this should work [1]
($field:ident, $value:expr) => {{
let mut new = Test::default();
setter!(new, val, $value);
new
}};
}
fn main() {
// error: cannot find value `new` in this scope
let a = setter!(val, 42);
println!("{:?}", a);
// works fine this way [2]
let b = {
let mut new = Test::default();
setter!(new, val, 42);
new
};
println!("{:?}", b);
}
Tested on Rust 1.31.1 stable, Gentoo Linux x86_64.
dtolnay commented
This looks like a compiler bug. The input is being passed into the macro without Span information. We will need to minimize the bug and file it against the compiler.
Unfortunately the compiler's span handling is totally broken right now --- rust-lang/rust#43081.
TokenStream [
Ident {
ident: "new",
span: #0 bytes(0..0)
},
Punct {
ch: '.',
spacing: Alone,
span: #0 bytes(0..0)
},
Group {
delimiter: Bracket,
stream: TokenStream [
Punct {
ch: '<',
spacing: Alone,
span: #0 bytes(0..0)
},
Ident {
ident: "set_",
span: #0 bytes(0..0)
},
Ident {
ident: "val",
span: #0 bytes(0..0)
},
Punct {
ch: '>',
spacing: Alone,
span: #0 bytes(0..0)
}
],
span: #0 bytes(0..0)
},
Group {
delimiter: Parenthesis,
stream: TokenStream [
Literal {
lit: Integer(42),
suffix: None,
span: #0 bytes(0..0)
}
],
span: #0 bytes(0..0)
},
Punct {
ch: ';',
spacing: Alone,
span: #0 bytes(0..0)
}
]
dtolnay commented
The code in #7 (comment) now builds successfully with Rust 1.45 and paste 1.0.
dtolnay commented
Correction: it builds with Rust 1.46+ (the current beta; releasing on August 27).