Skip to content

Commit 7e5ff62

Browse files
committed
Emit an Error impl even in the presence of bad attributes
1 parent 0444cd5 commit 7e5ff62

22 files changed

Lines changed: 327 additions & 14 deletions

impl/src/expand.rs

Lines changed: 26 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,15 +7,39 @@ use quote::{format_ident, quote, quote_spanned, ToTokens};
77
use std::collections::BTreeSet as Set;
88
use syn::{DeriveInput, GenericArgument, Member, PathArguments, Result, Token, Type};
99

10-
pub fn derive(node: &DeriveInput) -> Result<TokenStream> {
11-
let input = Input::from_syn(node)?;
10+
pub fn derive(input: &DeriveInput) -> TokenStream {
11+
match try_expand(input) {
12+
Ok(expanded) => expanded,
13+
// If there are invalid attributes in the input, expand to an Error impl
14+
// anyway to minimize spurious knock-on errors in other code that uses
15+
// this type as an Error.
16+
Err(error) => fallback(input, error),
17+
}
18+
}
19+
20+
fn try_expand(input: &DeriveInput) -> Result<TokenStream> {
21+
let input = Input::from_syn(input)?;
1222
input.validate()?;
1323
Ok(match input {
1424
Input::Struct(input) => impl_struct(input),
1525
Input::Enum(input) => impl_enum(input),
1626
})
1727
}
1828

29+
fn fallback(input: &DeriveInput, error: syn::Error) -> TokenStream {
30+
let ty = &input.ident;
31+
let (impl_generics, ty_generics, where_clause) = input.generics.split_for_impl();
32+
33+
let error = error.to_compile_error();
34+
35+
quote! {
36+
#error
37+
38+
#[allow(unused_qualifications)]
39+
impl #impl_generics std::error::Error for #ty #ty_generics #where_clause {}
40+
}
41+
}
42+
1943
fn impl_struct(input: Struct) -> TokenStream {
2044
let ty = &input.ident;
2145
let (impl_generics, ty_generics, where_clause) = input.generics.split_for_impl();

impl/src/lib.rs

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,5 @@ use syn::{parse_macro_input, DeriveInput};
3333
#[proc_macro_derive(Error, attributes(backtrace, error, from, source))]
3434
pub fn derive_error(input: TokenStream) -> TokenStream {
3535
let input = parse_macro_input!(input as DeriveInput);
36-
expand::derive(&input)
37-
.unwrap_or_else(|err| err.to_compile_error())
38-
.into()
36+
expand::derive(&input).into()
3937
}

tests/ui/bad-field-attr.stderr

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,3 +3,17 @@ error: #[error(transparent)] needs to go outside the enum or struct, not on an i
33
|
44
5 | pub struct Error(#[error(transparent)] std::io::Error);
55
| ^^^^^^^^^^^^^^^^^^^^^
6+
7+
error[E0277]: `Error` doesn't implement `std::fmt::Display`
8+
--> tests/ui/bad-field-attr.rs:5:12
9+
|
10+
5 | pub struct Error(#[error(transparent)] std::io::Error);
11+
| ^^^^^ `Error` cannot be formatted with the default formatter
12+
|
13+
= help: the trait `std::fmt::Display` is not implemented for `Error`
14+
= note: in format strings you may be able to use `{:?}` (or {:#?} for pretty-print) instead
15+
note: required by a bound in `std::error::Error`
16+
--> $RUST/core/src/error.rs
17+
|
18+
| pub trait Error: Debug + Display {
19+
| ^^^^^^^ required by this bound in `Error`

tests/ui/concat-display.stderr

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,3 +8,17 @@ error: expected string literal
88
| ------------------------- in this macro invocation
99
|
1010
= note: this error originates in the macro `error_type` (in Nightly builds, run with -Z macro-backtrace for more info)
11+
12+
error[E0277]: `Error` doesn't implement `std::fmt::Display`
13+
--> tests/ui/concat-display.rs:13:13
14+
|
15+
13 | error_type!(Error, "foo");
16+
| ^^^^^ `Error` cannot be formatted with the default formatter
17+
|
18+
= help: the trait `std::fmt::Display` is not implemented for `Error`
19+
= note: in format strings you may be able to use `{:?}` (or {:#?} for pretty-print) instead
20+
note: required by a bound in `std::error::Error`
21+
--> $RUST/core/src/error.rs
22+
|
23+
| pub trait Error: Debug + Display {
24+
| ^^^^^^^ required by this bound in `Error`

tests/ui/duplicate-enum-source.stderr

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,3 +3,17 @@ error: duplicate #[source] attribute
33
|
44
8 | #[source]
55
| ^^^^^^^^^
6+
7+
error[E0277]: `ErrorEnum` doesn't implement `std::fmt::Display`
8+
--> tests/ui/duplicate-enum-source.rs:4:10
9+
|
10+
4 | pub enum ErrorEnum {
11+
| ^^^^^^^^^ `ErrorEnum` cannot be formatted with the default formatter
12+
|
13+
= help: the trait `std::fmt::Display` is not implemented for `ErrorEnum`
14+
= note: in format strings you may be able to use `{:?}` (or {:#?} for pretty-print) instead
15+
note: required by a bound in `std::error::Error`
16+
--> $RUST/core/src/error.rs
17+
|
18+
| pub trait Error: Debug + Display {
19+
| ^^^^^^^ required by this bound in `Error`

tests/ui/duplicate-fmt.stderr

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,3 +3,17 @@ error: only one #[error(...)] attribute is allowed
33
|
44
5 | #[error("...")]
55
| ^^^^^^^^^^^^^^^
6+
7+
error[E0277]: `Error` doesn't implement `std::fmt::Display`
8+
--> tests/ui/duplicate-fmt.rs:6:12
9+
|
10+
6 | pub struct Error;
11+
| ^^^^^ `Error` cannot be formatted with the default formatter
12+
|
13+
= help: the trait `std::fmt::Display` is not implemented for `Error`
14+
= note: in format strings you may be able to use `{:?}` (or {:#?} for pretty-print) instead
15+
note: required by a bound in `std::error::Error`
16+
--> $RUST/core/src/error.rs
17+
|
18+
| pub trait Error: Debug + Display {
19+
| ^^^^^^^ required by this bound in `Error`

tests/ui/duplicate-struct-source.stderr

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,3 +3,17 @@ error: duplicate #[source] attribute
33
|
44
7 | #[source]
55
| ^^^^^^^^^
6+
7+
error[E0277]: `ErrorStruct` doesn't implement `std::fmt::Display`
8+
--> tests/ui/duplicate-struct-source.rs:4:12
9+
|
10+
4 | pub struct ErrorStruct {
11+
| ^^^^^^^^^^^ `ErrorStruct` cannot be formatted with the default formatter
12+
|
13+
= help: the trait `std::fmt::Display` is not implemented for `ErrorStruct`
14+
= note: in format strings you may be able to use `{:?}` (or {:#?} for pretty-print) instead
15+
note: required by a bound in `std::error::Error`
16+
--> $RUST/core/src/error.rs
17+
|
18+
| pub trait Error: Debug + Display {
19+
| ^^^^^^^ required by this bound in `Error`

tests/ui/duplicate-transparent.stderr

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,3 +3,17 @@ error: duplicate #[error(transparent)] attribute
33
|
44
5 | #[error(transparent)]
55
| ^^^^^^^^^^^^^^^^^^^^^
6+
7+
error[E0277]: `Error` doesn't implement `std::fmt::Display`
8+
--> tests/ui/duplicate-transparent.rs:6:12
9+
|
10+
6 | pub struct Error(anyhow::Error);
11+
| ^^^^^ `Error` cannot be formatted with the default formatter
12+
|
13+
= help: the trait `std::fmt::Display` is not implemented for `Error`
14+
= note: in format strings you may be able to use `{:?}` (or {:#?} for pretty-print) instead
15+
note: required by a bound in `std::error::Error`
16+
--> $RUST/core/src/error.rs
17+
|
18+
| pub trait Error: Debug + Display {
19+
| ^^^^^^^ required by this bound in `Error`

tests/ui/from-backtrace-backtrace.stderr

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,3 +3,17 @@ error: deriving From requires no fields other than source and backtrace
33
|
44
9 | #[from]
55
| ^^^^^^^
6+
7+
error[E0277]: `Error` doesn't implement `std::fmt::Display`
8+
--> tests/ui/from-backtrace-backtrace.rs:8:12
9+
|
10+
8 | pub struct Error(
11+
| ^^^^^ `Error` cannot be formatted with the default formatter
12+
|
13+
= help: the trait `std::fmt::Display` is not implemented for `Error`
14+
= note: in format strings you may be able to use `{:?}` (or {:#?} for pretty-print) instead
15+
note: required by a bound in `std::error::Error`
16+
--> $RUST/core/src/error.rs
17+
|
18+
| pub trait Error: Debug + Display {
19+
| ^^^^^^^ required by this bound in `Error`

tests/ui/from-not-source.stderr

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,3 +3,17 @@ error: #[from] is only supported on the source field, not any other field
33
|
44
7 | #[from]
55
| ^^^^^^^
6+
7+
error[E0277]: `Error` doesn't implement `std::fmt::Display`
8+
--> tests/ui/from-not-source.rs:4:12
9+
|
10+
4 | pub struct Error {
11+
| ^^^^^ `Error` cannot be formatted with the default formatter
12+
|
13+
= help: the trait `std::fmt::Display` is not implemented for `Error`
14+
= note: in format strings you may be able to use `{:?}` (or {:#?} for pretty-print) instead
15+
note: required by a bound in `std::error::Error`
16+
--> $RUST/core/src/error.rs
17+
|
18+
| pub trait Error: Debug + Display {
19+
| ^^^^^^^ required by this bound in `Error`

0 commit comments

Comments
 (0)