proc-macro derive panicked when using #[br(args)] directive in macro_rules
A minimal example is as follows
#![allow(unused)]
use binrw::BinRead;
enum Foo {
V1(u8),
V2(u16),
}
#[derive(BinRead)]
#[br(import(_version: &u8))]
struct Data1 {}
#[derive(BinRead)]
#[br(import(_version: &u16))]
struct Data2 {}
#[derive(BinRead)]
#[br(import(version: &Foo))]
enum Bar {
#[br(pre_assert(matches!(version, Foo::V1(_))))]
Data1(
#[br(args(match version {
Foo::V1(x) => x,
_ => unreachable!(),
}))]
Data1
),
#[br(pre_assert(matches!(version, Foo::V2(_))))]
Data2(
#[br(args(match version {
Foo::V2(x) => x,
_ => unreachable!(),
}))]
Data2
),
}
macro_rules! macro_versioned_enum {
(
$name_in:ident, $name_out:ident,
$( ($v_in:ident, $v_out:ident) ),*
) => {
#[derive(BinRead)]
#[br(import(version: &$name_in))]
enum $name_out {
$(
#[br(pre_assert(matches!(version, $name_in::$v_in(_))))]
$v_out(
#[br(args(match version {
$name_in::$v_in(v) => v,
_ => unreachable!(),
}))]
$v_out
),
)*
}
}
}
// This does not compile with the following error:
// ```
// proc-macro derive panicked
// message: byte index 6 is out of bounds of ` #`
// ```
macro_versioned_enum!(Foo, Baz,
(V1, Data1),
(V2, Data2)
);
Basically, I attempt to parse the enum Bar or Baz based on the contents in the enum Foo.
Bar is defined explicitly while Baz is defined using a macro, and both are supposedly equivalent.
However, Bar compiles fine while Baz compilation failed with
|
44 | #[derive(BinRead)]
| ^^^^^^^
...
66 | / macro_versioned_enum!(Foo, Baz,
67 | | (V1, Data1),
68 | | (V2, Data2)
69 | | );
| |_- in this macro invocation
|
= help: message: byte index 6 is out of bounds of ` #`
= note: this error originates in the macro `macro_versioned_enum` (in Nightly builds, run with -Z macro-backtrace for more info)
(-Z macro-backtrace does not give more info)
Thanks for your report! I’ve copied your test case and it seems to compile here without panicking on rustc 1.91.0. Which Rust version are you using? Thanks!
(I also obviously don’t know what your real types look like but I would encourage to consider an approach where multi-versioning is handled by a combination of impl From<V1> for VLatest and passing generic types if needed, instead of using macros like this.)
Sorry for missing the version information! The versions for seeing the above were
- cargo 1.91.1 (ea2d97820 2025-10-10)
- cargo 1.93.0-nightly (445fe4a68 2025-11-07)
The OS is Ubuntu 22.04.5 LTS.
The full project structure includes the main.rs which was the code above plus a main function (doing nothing), with the following Cargo.toml.
[package]
name = "some-name"
version = "0.1.0"
edition = "2024"
[dependencies]
binrw = "0.15.0"
Thanks for the additional information. I am only able to reproduce this issue using nightly, and it is related to the verbose-backtrace feature. This suggests that something in proc_macro2 or upstream of proc_macro2 has broken unexpectedly. Do you have the ability to bisect nightly versions? There are similar reports of things being broken (https://github.com/GaloisInc/mir-json/issues/186), but that appears to only apply to an older range of nightly compilers, and not related to macro_rules macros. It seems plausible this is a related but different issue, since it is only occurring when the code is inside a macro_rules macro.