E0425 deriving Error for an enum declared in a macro
opened this issue · comments
Deleted user commented
On rustc 1.43.1 stable, the following code results in error[E0425]: cannot find value `_0` in this scope
:
use thiserror::Error;
macro_rules! decl_error {
($($Variant:ident($Value:ident)),*) => {
#[derive(Debug, Error)] // <- E0425 here
pub enum Foo {
$(
#[error("{0:?}")]
$Variant($Value),
)*
}
};
}
decl_error!(
Foo(u8),
Bar(u16),
Baz(u32)
);
// For comparison, normal usage does not result in errors.
#[derive(Debug, Error)]
pub enum Bar {
#[error("{0:?}")]
Foo(u8),
#[error("{0:?}")]
Bar(u16),
#[error("{0:?}")]
Baz(u32)
}
Curiously, the output of cargo-expand
seems fine. Any possibility of a bug in rustc?
Output of cargo-expand
#![feature(prelude_import)]
#[prelude_import]
use std::prelude::v1::*;
#[macro_use]
extern crate std;
use thiserror::Error;
pub enum Foo {
#[error("{0:?}")]
Foo(u8),
#[error("{0:?}")]
Bar(u16),
#[error("{0:?}")]
Baz(u32),
}
#[automatically_derived]
#[allow(unused_qualifications)]
impl ::core::fmt::Debug for Foo {
fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
match (&*self,) {
(&Foo::Foo(ref __self_0),) => {
let mut debug_trait_builder = f.debug_tuple("Foo");
let _ = debug_trait_builder.field(&&(*__self_0));
debug_trait_builder.finish()
}
(&Foo::Bar(ref __self_0),) => {
let mut debug_trait_builder = f.debug_tuple("Bar");
let _ = debug_trait_builder.field(&&(*__self_0));
debug_trait_builder.finish()
}
(&Foo::Baz(ref __self_0),) => {
let mut debug_trait_builder = f.debug_tuple("Baz");
let _ = debug_trait_builder.field(&&(*__self_0));
debug_trait_builder.finish()
}
}
}
}
impl std::error::Error for Foo {}
impl std::fmt::Display for Foo {
fn fmt(&self, __formatter: &mut std::fmt::Formatter) -> std::fmt::Result {
#[allow(unused_variables, deprecated)]
match self {
Foo::Foo(_0) => __formatter.write_fmt(::core::fmt::Arguments::new_v1(
&[""],
&match (&_0,) {
(arg0,) => [::core::fmt::ArgumentV1::new(arg0, ::core::fmt::Debug::fmt)],
},
)),
Foo::Bar(_0) => __formatter.write_fmt(::core::fmt::Arguments::new_v1(
&[""],
&match (&_0,) {
(arg0,) => [::core::fmt::ArgumentV1::new(arg0, ::core::fmt::Debug::fmt)],
},
)),
Foo::Baz(_0) => __formatter.write_fmt(::core::fmt::Arguments::new_v1(
&[""],
&match (&_0,) {
(arg0,) => [::core::fmt::ArgumentV1::new(arg0, ::core::fmt::Debug::fmt)],
},
)),
}
}
}
pub enum Bar {
#[error("{0:?}")]
Foo(u8),
#[error("{0:?}")]
Bar(u16),
#[error("{0:?}")]
Baz(u32),
}
#[automatically_derived]
#[allow(unused_qualifications)]
impl ::core::fmt::Debug for Bar {
fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
match (&*self,) {
(&Bar::Foo(ref __self_0),) => {
let mut debug_trait_builder = f.debug_tuple("Foo");
let _ = debug_trait_builder.field(&&(*__self_0));
debug_trait_builder.finish()
}
(&Bar::Bar(ref __self_0),) => {
let mut debug_trait_builder = f.debug_tuple("Bar");
let _ = debug_trait_builder.field(&&(*__self_0));
debug_trait_builder.finish()
}
(&Bar::Baz(ref __self_0),) => {
let mut debug_trait_builder = f.debug_tuple("Baz");
let _ = debug_trait_builder.field(&&(*__self_0));
debug_trait_builder.finish()
}
}
}
}
impl std::error::Error for Bar {}
impl std::fmt::Display for Bar {
fn fmt(&self, __formatter: &mut std::fmt::Formatter) -> std::fmt::Result {
#[allow(unused_variables, deprecated)]
match self {
Bar::Foo(_0) => __formatter.write_fmt(::core::fmt::Arguments::new_v1(
&[""],
&match (&_0,) {
(arg0,) => [::core::fmt::ArgumentV1::new(arg0, ::core::fmt::Debug::fmt)],
},
)),
Bar::Bar(_0) => __formatter.write_fmt(::core::fmt::Arguments::new_v1(
&[""],
&match (&_0,) {
(arg0,) => [::core::fmt::ArgumentV1::new(arg0, ::core::fmt::Debug::fmt)],
},
)),
Bar::Baz(_0) => __formatter.write_fmt(::core::fmt::Arguments::new_v1(
&[""],
&match (&_0,) {
(arg0,) => [::core::fmt::ArgumentV1::new(arg0, ::core::fmt::Debug::fmt)],
},
)),
}
}
}
David Tolnay commented
Thanks for the nice repro. You are right that this is due to a compiler bug (rust-lang/rust#43081) but I've published a workaround in thiserror 1.0.18.
Deleted user commented
Thanks for the information and swift workaround!