From f4eac7ef7be36981b314d098049f6874af090e48 Mon Sep 17 00:00:00 2001 From: David Tolnay Date: Tue, 26 Sep 2023 19:02:54 -0700 Subject: [PATCH 01/31] Ignore needless_raw_string_hashes clippy lint warning: unnecessary hashes around raw string literal --> build.rs:10:21 | 10 | const PROBE: &str = r#" | _____________________^ 11 | | #![feature(error_generic_member_access)] 12 | | 13 | | use std::error::{Error, Request}; ... | 35 | | } 36 | | "#; | |__^ | = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#needless_raw_string_hashes = note: `-W clippy::needless-raw-string-hashes` implied by `-W clippy::all` = help: to override `-W clippy::all` add `#[allow(clippy::needless_raw_string_hashes)]` help: remove all the hashes around the literal | 10 ~ const PROBE: &str = r" 11 | #![feature(error_generic_member_access)] ... 35 | } 36 ~ "; | --- build.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/build.rs b/build.rs index 7983a2b0..8bf19e19 100644 --- a/build.rs +++ b/build.rs @@ -1,3 +1,5 @@ +#![allow(clippy::needless_raw_string_hashes)] + use std::env; use std::fs; use std::path::Path; From a49f7c603ddff7ecbfff1bf02dea100772621753 Mon Sep 17 00:00:00 2001 From: Maarten de Vries Date: Thu, 19 Oct 2023 15:04:40 +0200 Subject: [PATCH 02/31] Change span of `as_dyn_error()` to point compile error at attribute. --- impl/src/expand.rs | 15 ++++++------ impl/src/prop.rs | 13 ++++++++++- .../ui/source-enum-unnamed-field-not-error.rs | 12 ++++++++++ ...source-enum-unnamed-field-not-error.stderr | 22 ++++++++++++++++++ .../source-struct-unnamed-field-not-error.rs | 10 ++++++++ ...urce-struct-unnamed-field-not-error.stderr | 21 +++++++++++++++++ tests/ui/transparent-enum-not-error.rs | 11 +++++++++ tests/ui/transparent-enum-not-error.stderr | 23 +++++++++++++++++++ ...ransparent-enum-unnamed-field-not-error.rs | 9 ++++++++ ...parent-enum-unnamed-field-not-error.stderr | 23 +++++++++++++++++++ tests/ui/transparent-struct-not-error.rs | 9 ++++++++ tests/ui/transparent-struct-not-error.stderr | 21 +++++++++++++++++ ...nsparent-struct-unnamed-field-not-error.rs | 7 ++++++ ...rent-struct-unnamed-field-not-error.stderr | 21 +++++++++++++++++ 14 files changed, 209 insertions(+), 8 deletions(-) create mode 100644 tests/ui/source-enum-unnamed-field-not-error.rs create mode 100644 tests/ui/source-enum-unnamed-field-not-error.stderr create mode 100644 tests/ui/source-struct-unnamed-field-not-error.rs create mode 100644 tests/ui/source-struct-unnamed-field-not-error.stderr create mode 100644 tests/ui/transparent-enum-not-error.rs create mode 100644 tests/ui/transparent-enum-not-error.stderr create mode 100644 tests/ui/transparent-enum-unnamed-field-not-error.rs create mode 100644 tests/ui/transparent-enum-unnamed-field-not-error.stderr create mode 100644 tests/ui/transparent-struct-not-error.rs create mode 100644 tests/ui/transparent-struct-not-error.stderr create mode 100644 tests/ui/transparent-struct-unnamed-field-not-error.rs create mode 100644 tests/ui/transparent-struct-unnamed-field-not-error.stderr diff --git a/impl/src/expand.rs b/impl/src/expand.rs index a1fe0c75..80a39789 100644 --- a/impl/src/expand.rs +++ b/impl/src/expand.rs @@ -23,14 +23,14 @@ fn impl_struct(input: Struct) -> TokenStream { let (impl_generics, ty_generics, where_clause) = input.generics.split_for_impl(); let mut error_inferred_bounds = InferredBounds::new(); - let source_body = if input.attrs.transparent.is_some() { + let source_body = if let Some(transparent_attr) = &input.attrs.transparent { let only_field = &input.fields[0]; if only_field.contains_generic { error_inferred_bounds.insert(only_field.ty, quote!(std::error::Error)); } let member = &only_field.member; - Some(quote! { - std::error::Error::source(self.#member.as_dyn_error()) + Some(quote_spanned! { + transparent_attr.span => std::error::Error::source(self.#member.as_dyn_error()) }) } else if let Some(source_field) = input.source_field() { let source = &source_field.member; @@ -43,7 +43,8 @@ fn impl_struct(input: Struct) -> TokenStream { } else { None }; - let dyn_error = quote_spanned!(source.span()=> self.#source #asref.as_dyn_error()); + let dyn_error = + quote_spanned!(source_field.source_span() => self.#source #asref.as_dyn_error()); Some(quote! { ::core::option::Option::Some(#dyn_error) }) @@ -193,13 +194,13 @@ fn impl_enum(input: Enum) -> TokenStream { let source_method = if input.has_source() { let arms = input.variants.iter().map(|variant| { let ident = &variant.ident; - if variant.attrs.transparent.is_some() { + if let Some(transparent_attr) = &variant.attrs.transparent { let only_field = &variant.fields[0]; if only_field.contains_generic { error_inferred_bounds.insert(only_field.ty, quote!(std::error::Error)); } let member = &only_field.member; - let source = quote!(std::error::Error::source(transparent.as_dyn_error())); + let source = quote_spanned!(transparent_attr.span => std::error::Error::source(transparent.as_dyn_error())); quote! { #ty::#ident {#member: transparent} => #source, } @@ -215,7 +216,7 @@ fn impl_enum(input: Enum) -> TokenStream { None }; let varsource = quote!(source); - let dyn_error = quote_spanned!(source.span()=> #varsource #asref.as_dyn_error()); + let dyn_error = quote_spanned!(source_field.source_span()=> #varsource #asref.as_dyn_error()); quote! { #ty::#ident {#source: #varsource, ..} => ::core::option::Option::Some(#dyn_error), } diff --git a/impl/src/prop.rs b/impl/src/prop.rs index 6d8a924c..62f269b3 100644 --- a/impl/src/prop.rs +++ b/impl/src/prop.rs @@ -1,5 +1,6 @@ use crate::ast::{Enum, Field, Struct, Variant}; -use syn::{Member, Type}; +use proc_macro2::Span; +use syn::{spanned::Spanned, Member, Type}; impl Struct<'_> { pub(crate) fn from_field(&self) -> Option<&Field> { @@ -70,6 +71,16 @@ impl Field<'_> { pub(crate) fn is_backtrace(&self) -> bool { type_is_backtrace(self.ty) } + + pub(crate) fn source_span(&self) -> Span { + if let Some(source_attr) = &self.attrs.source { + source_attr.path().span() + } else if let Some(from_attr) = &self.attrs.from { + from_attr.path().span() + } else { + self.member.span() + } + } } fn from_field<'a, 'b>(fields: &'a [Field<'b>]) -> Option<&'a Field<'b>> { diff --git a/tests/ui/source-enum-unnamed-field-not-error.rs b/tests/ui/source-enum-unnamed-field-not-error.rs new file mode 100644 index 00000000..a877c2cd --- /dev/null +++ b/tests/ui/source-enum-unnamed-field-not-error.rs @@ -0,0 +1,12 @@ +use thiserror::Error; + +#[derive(Debug)] +pub struct NotError; + +#[derive(Error, Debug)] +#[error("...")] +pub enum ErrorEnum { + Broken(#[source] NotError), +} + +fn main() {} diff --git a/tests/ui/source-enum-unnamed-field-not-error.stderr b/tests/ui/source-enum-unnamed-field-not-error.stderr new file mode 100644 index 00000000..da6d225f --- /dev/null +++ b/tests/ui/source-enum-unnamed-field-not-error.stderr @@ -0,0 +1,22 @@ +error[E0599]: the method `as_dyn_error` exists for reference `&NotError`, but its trait bounds were not satisfied + --> tests/ui/source-enum-unnamed-field-not-error.rs:9:14 + | +4 | pub struct NotError; + | ------------------- + | | + | doesn't satisfy `NotError: AsDynError<'_>` + | doesn't satisfy `NotError: std::error::Error` +... +9 | Broken(#[source] NotError), + | ^^^^^^ method cannot be called on `&NotError` due to unsatisfied trait bounds + | + = note: the following trait bounds were not satisfied: + `NotError: std::error::Error` + which is required by `NotError: AsDynError<'_>` + `&NotError: std::error::Error` + which is required by `&NotError: AsDynError<'_>` +note: the trait `std::error::Error` must be implemented + --> $RUST/core/src/error.rs + | + | pub trait Error: Debug + Display { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/tests/ui/source-struct-unnamed-field-not-error.rs b/tests/ui/source-struct-unnamed-field-not-error.rs new file mode 100644 index 00000000..160b6b24 --- /dev/null +++ b/tests/ui/source-struct-unnamed-field-not-error.rs @@ -0,0 +1,10 @@ +use thiserror::Error; + +#[derive(Debug)] +struct NotError; + +#[derive(Error, Debug)] +#[error("...")] +pub struct ErrorStruct(#[source] NotError); + +fn main() {} diff --git a/tests/ui/source-struct-unnamed-field-not-error.stderr b/tests/ui/source-struct-unnamed-field-not-error.stderr new file mode 100644 index 00000000..a23f2682 --- /dev/null +++ b/tests/ui/source-struct-unnamed-field-not-error.stderr @@ -0,0 +1,21 @@ +error[E0599]: the method `as_dyn_error` exists for struct `NotError`, but its trait bounds were not satisfied + --> tests/ui/source-struct-unnamed-field-not-error.rs:8:26 + | +4 | struct NotError; + | --------------- + | | + | method `as_dyn_error` not found for this struct + | doesn't satisfy `NotError: AsDynError<'_>` + | doesn't satisfy `NotError: std::error::Error` +... +8 | pub struct ErrorStruct(#[source] NotError); + | ^^^^^^ method cannot be called on `NotError` due to unsatisfied trait bounds + | + = note: the following trait bounds were not satisfied: + `NotError: std::error::Error` + which is required by `NotError: AsDynError<'_>` +note: the trait `std::error::Error` must be implemented + --> $RUST/core/src/error.rs + | + | pub trait Error: Debug + Display { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/tests/ui/transparent-enum-not-error.rs b/tests/ui/transparent-enum-not-error.rs new file mode 100644 index 00000000..2ef74571 --- /dev/null +++ b/tests/ui/transparent-enum-not-error.rs @@ -0,0 +1,11 @@ +use thiserror::Error; + +#[derive(Error, Debug)] +pub enum Error { + #[error(transparent)] + Other { + message: String, + } +} + +fn main() {} diff --git a/tests/ui/transparent-enum-not-error.stderr b/tests/ui/transparent-enum-not-error.stderr new file mode 100644 index 00000000..9be51434 --- /dev/null +++ b/tests/ui/transparent-enum-not-error.stderr @@ -0,0 +1,23 @@ +error[E0599]: the method `as_dyn_error` exists for reference `&String`, but its trait bounds were not satisfied + --> tests/ui/transparent-enum-not-error.rs:5:13 + | +5 | #[error(transparent)] + | ^^^^^^^^^^^ method cannot be called on `&String` due to unsatisfied trait bounds + | + ::: $RUST/alloc/src/string.rs + | + | pub struct String { + | ----------------- + | | + | doesn't satisfy `String: AsDynError<'_>` + | doesn't satisfy `String: std::error::Error` + | + = note: the following trait bounds were not satisfied: + `String: std::error::Error` + which is required by `String: AsDynError<'_>` + `&String: std::error::Error` + which is required by `&String: AsDynError<'_>` + `str: Sized` + which is required by `str: AsDynError<'_>` + `str: std::error::Error` + which is required by `str: AsDynError<'_>` diff --git a/tests/ui/transparent-enum-unnamed-field-not-error.rs b/tests/ui/transparent-enum-unnamed-field-not-error.rs new file mode 100644 index 00000000..87c32e0b --- /dev/null +++ b/tests/ui/transparent-enum-unnamed-field-not-error.rs @@ -0,0 +1,9 @@ +use thiserror::Error; + +#[derive(Error, Debug)] +pub enum Error { + #[error(transparent)] + Other(String), +} + +fn main() {} diff --git a/tests/ui/transparent-enum-unnamed-field-not-error.stderr b/tests/ui/transparent-enum-unnamed-field-not-error.stderr new file mode 100644 index 00000000..3d23c3a0 --- /dev/null +++ b/tests/ui/transparent-enum-unnamed-field-not-error.stderr @@ -0,0 +1,23 @@ +error[E0599]: the method `as_dyn_error` exists for reference `&String`, but its trait bounds were not satisfied + --> tests/ui/transparent-enum-unnamed-field-not-error.rs:5:13 + | +5 | #[error(transparent)] + | ^^^^^^^^^^^ method cannot be called on `&String` due to unsatisfied trait bounds + | + ::: $RUST/alloc/src/string.rs + | + | pub struct String { + | ----------------- + | | + | doesn't satisfy `String: AsDynError<'_>` + | doesn't satisfy `String: std::error::Error` + | + = note: the following trait bounds were not satisfied: + `String: std::error::Error` + which is required by `String: AsDynError<'_>` + `&String: std::error::Error` + which is required by `&String: AsDynError<'_>` + `str: Sized` + which is required by `str: AsDynError<'_>` + `str: std::error::Error` + which is required by `str: AsDynError<'_>` diff --git a/tests/ui/transparent-struct-not-error.rs b/tests/ui/transparent-struct-not-error.rs new file mode 100644 index 00000000..811ff539 --- /dev/null +++ b/tests/ui/transparent-struct-not-error.rs @@ -0,0 +1,9 @@ +use thiserror::Error; + +#[derive(Error, Debug)] +#[error(transparent)] +pub struct Error { + message: String, +} + +fn main() {} diff --git a/tests/ui/transparent-struct-not-error.stderr b/tests/ui/transparent-struct-not-error.stderr new file mode 100644 index 00000000..d67a6944 --- /dev/null +++ b/tests/ui/transparent-struct-not-error.stderr @@ -0,0 +1,21 @@ +error[E0599]: the method `as_dyn_error` exists for struct `String`, but its trait bounds were not satisfied + --> tests/ui/transparent-struct-not-error.rs:4:9 + | +4 | #[error(transparent)] + | ^^^^^^^^^^^ method cannot be called on `String` due to unsatisfied trait bounds + | + ::: $RUST/alloc/src/string.rs + | + | pub struct String { + | ----------------- + | | + | doesn't satisfy `String: AsDynError<'_>` + | doesn't satisfy `String: std::error::Error` + | + = note: the following trait bounds were not satisfied: + `String: std::error::Error` + which is required by `String: AsDynError<'_>` + `str: Sized` + which is required by `str: AsDynError<'_>` + `str: std::error::Error` + which is required by `str: AsDynError<'_>` diff --git a/tests/ui/transparent-struct-unnamed-field-not-error.rs b/tests/ui/transparent-struct-unnamed-field-not-error.rs new file mode 100644 index 00000000..b4f7fbbf --- /dev/null +++ b/tests/ui/transparent-struct-unnamed-field-not-error.rs @@ -0,0 +1,7 @@ +use thiserror::Error; + +#[derive(Error, Debug)] +#[error(transparent)] +pub struct Error(String); + +fn main() {} diff --git a/tests/ui/transparent-struct-unnamed-field-not-error.stderr b/tests/ui/transparent-struct-unnamed-field-not-error.stderr new file mode 100644 index 00000000..f715a151 --- /dev/null +++ b/tests/ui/transparent-struct-unnamed-field-not-error.stderr @@ -0,0 +1,21 @@ +error[E0599]: the method `as_dyn_error` exists for struct `String`, but its trait bounds were not satisfied + --> tests/ui/transparent-struct-unnamed-field-not-error.rs:4:9 + | +4 | #[error(transparent)] + | ^^^^^^^^^^^ method cannot be called on `String` due to unsatisfied trait bounds + | + ::: $RUST/alloc/src/string.rs + | + | pub struct String { + | ----------------- + | | + | doesn't satisfy `String: AsDynError<'_>` + | doesn't satisfy `String: std::error::Error` + | + = note: the following trait bounds were not satisfied: + `String: std::error::Error` + which is required by `String: AsDynError<'_>` + `str: Sized` + which is required by `str: AsDynError<'_>` + `str: std::error::Error` + which is required by `str: AsDynError<'_>` From c9fe739272dee48b0dedc6114780e1ca63c42ad3 Mon Sep 17 00:00:00 2001 From: David Tolnay Date: Thu, 19 Oct 2023 10:37:00 -0700 Subject: [PATCH 03/31] Touch up PR 258 --- impl/src/expand.rs | 17 +++++++++++------ impl/src/prop.rs | 3 ++- 2 files changed, 13 insertions(+), 7 deletions(-) diff --git a/impl/src/expand.rs b/impl/src/expand.rs index 80a39789..394aafbc 100644 --- a/impl/src/expand.rs +++ b/impl/src/expand.rs @@ -29,8 +29,8 @@ fn impl_struct(input: Struct) -> TokenStream { error_inferred_bounds.insert(only_field.ty, quote!(std::error::Error)); } let member = &only_field.member; - Some(quote_spanned! { - transparent_attr.span => std::error::Error::source(self.#member.as_dyn_error()) + Some(quote_spanned! {transparent_attr.span=> + std::error::Error::source(self.#member.as_dyn_error()) }) } else if let Some(source_field) = input.source_field() { let source = &source_field.member; @@ -43,8 +43,9 @@ fn impl_struct(input: Struct) -> TokenStream { } else { None }; - let dyn_error = - quote_spanned!(source_field.source_span() => self.#source #asref.as_dyn_error()); + let dyn_error = quote_spanned! {source_field.source_span()=> + self.#source #asref.as_dyn_error() + }; Some(quote! { ::core::option::Option::Some(#dyn_error) }) @@ -200,7 +201,9 @@ fn impl_enum(input: Enum) -> TokenStream { error_inferred_bounds.insert(only_field.ty, quote!(std::error::Error)); } let member = &only_field.member; - let source = quote_spanned!(transparent_attr.span => std::error::Error::source(transparent.as_dyn_error())); + let source = quote_spanned! {transparent_attr.span=> + std::error::Error::source(transparent.as_dyn_error()) + }; quote! { #ty::#ident {#member: transparent} => #source, } @@ -216,7 +219,9 @@ fn impl_enum(input: Enum) -> TokenStream { None }; let varsource = quote!(source); - let dyn_error = quote_spanned!(source_field.source_span()=> #varsource #asref.as_dyn_error()); + let dyn_error = quote_spanned! {source_field.source_span()=> + #varsource #asref.as_dyn_error() + }; quote! { #ty::#ident {#source: #varsource, ..} => ::core::option::Option::Some(#dyn_error), } diff --git a/impl/src/prop.rs b/impl/src/prop.rs index 62f269b3..e4d2f188 100644 --- a/impl/src/prop.rs +++ b/impl/src/prop.rs @@ -1,6 +1,7 @@ use crate::ast::{Enum, Field, Struct, Variant}; use proc_macro2::Span; -use syn::{spanned::Spanned, Member, Type}; +use syn::spanned::Spanned; +use syn::{Member, Type}; impl Struct<'_> { pub(crate) fn from_field(&self) -> Option<&Field> { From 7cec716420b0f0bfbec8a827955d810b0f9804ab Mon Sep 17 00:00:00 2001 From: David Tolnay Date: Thu, 19 Oct 2023 10:42:06 -0700 Subject: [PATCH 04/31] Remove reliance on Spanned for Member --- impl/src/expand.rs | 18 +++++++++--------- impl/src/lib.rs | 1 + impl/src/prop.rs | 3 ++- impl/src/span.rs | 15 +++++++++++++++ 4 files changed, 27 insertions(+), 10 deletions(-) create mode 100644 impl/src/span.rs diff --git a/impl/src/expand.rs b/impl/src/expand.rs index 394aafbc..9124ca3a 100644 --- a/impl/src/expand.rs +++ b/impl/src/expand.rs @@ -1,10 +1,10 @@ use crate::ast::{Enum, Field, Input, Struct}; use crate::attr::Trait; use crate::generics::InferredBounds; +use crate::span::MemberSpan; use proc_macro2::TokenStream; use quote::{format_ident, quote, quote_spanned, ToTokens}; use std::collections::BTreeSet as Set; -use syn::spanned::Spanned; use syn::{ Data, DeriveInput, GenericArgument, Member, PathArguments, Result, Token, Type, Visibility, }; @@ -39,7 +39,7 @@ fn impl_struct(input: Struct) -> TokenStream { error_inferred_bounds.insert(ty, quote!(std::error::Error + 'static)); } let asref = if type_is_option(source_field.ty) { - Some(quote_spanned!(source.span()=> .as_ref()?)) + Some(quote_spanned!(source.member_span()=> .as_ref()?)) } else { None }; @@ -67,13 +67,13 @@ fn impl_struct(input: Struct) -> TokenStream { let body = if let Some(source_field) = input.source_field() { let source = &source_field.member; let source_provide = if type_is_option(source_field.ty) { - quote_spanned! {source.span()=> + quote_spanned! {source.member_span()=> if let ::core::option::Option::Some(source) = &self.#source { source.thiserror_provide(#request); } } } else { - quote_spanned! {source.span()=> + quote_spanned! {source.member_span()=> self.#source.thiserror_provide(#request); } }; @@ -214,7 +214,7 @@ fn impl_enum(input: Enum) -> TokenStream { error_inferred_bounds.insert(ty, quote!(std::error::Error + 'static)); } let asref = if type_is_option(source_field.ty) { - Some(quote_spanned!(source.span()=> .as_ref()?)) + Some(quote_spanned!(source.member_span()=> .as_ref()?)) } else { None }; @@ -256,13 +256,13 @@ fn impl_enum(input: Enum) -> TokenStream { let source = &source_field.member; let varsource = quote!(source); let source_provide = if type_is_option(source_field.ty) { - quote_spanned! {source.span()=> + quote_spanned! {source.member_span()=> if let ::core::option::Option::Some(source) = #varsource { source.thiserror_provide(#request); } } } else { - quote_spanned! {source.span()=> + quote_spanned! {source.member_span()=> #varsource.thiserror_provide(#request); } }; @@ -295,13 +295,13 @@ fn impl_enum(input: Enum) -> TokenStream { let backtrace = &backtrace_field.member; let varsource = quote!(source); let source_provide = if type_is_option(source_field.ty) { - quote_spanned! {backtrace.span()=> + quote_spanned! {backtrace.member_span()=> if let ::core::option::Option::Some(source) = #varsource { source.thiserror_provide(#request); } } } else { - quote_spanned! {backtrace.span()=> + quote_spanned! {backtrace.member_span()=> #varsource.thiserror_provide(#request); } }; diff --git a/impl/src/lib.rs b/impl/src/lib.rs index c5dab93f..683c8fb6 100644 --- a/impl/src/lib.rs +++ b/impl/src/lib.rs @@ -22,6 +22,7 @@ mod expand; mod fmt; mod generics; mod prop; +mod span; mod valid; use proc_macro::TokenStream; diff --git a/impl/src/prop.rs b/impl/src/prop.rs index e4d2f188..5a6a6bc5 100644 --- a/impl/src/prop.rs +++ b/impl/src/prop.rs @@ -1,4 +1,5 @@ use crate::ast::{Enum, Field, Struct, Variant}; +use crate::span::MemberSpan; use proc_macro2::Span; use syn::spanned::Spanned; use syn::{Member, Type}; @@ -79,7 +80,7 @@ impl Field<'_> { } else if let Some(from_attr) = &self.attrs.from { from_attr.path().span() } else { - self.member.span() + self.member.member_span() } } } diff --git a/impl/src/span.rs b/impl/src/span.rs new file mode 100644 index 00000000..c1237ddf --- /dev/null +++ b/impl/src/span.rs @@ -0,0 +1,15 @@ +use proc_macro2::Span; +use syn::Member; + +pub trait MemberSpan { + fn member_span(&self) -> Span; +} + +impl MemberSpan for Member { + fn member_span(&self) -> Span { + match self { + Member::Named(ident) => ident.span(), + Member::Unnamed(index) => index.span, + } + } +} From ff0a0a58590e9c12c1a2fe7d4dcb1d96e06eba26 Mon Sep 17 00:00:00 2001 From: David Tolnay Date: Thu, 19 Oct 2023 10:50:31 -0700 Subject: [PATCH 05/31] Source and From attributes only have single-ident path --- impl/src/prop.rs | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/impl/src/prop.rs b/impl/src/prop.rs index 5a6a6bc5..2867cd31 100644 --- a/impl/src/prop.rs +++ b/impl/src/prop.rs @@ -1,7 +1,6 @@ use crate::ast::{Enum, Field, Struct, Variant}; use crate::span::MemberSpan; use proc_macro2::Span; -use syn::spanned::Spanned; use syn::{Member, Type}; impl Struct<'_> { @@ -76,9 +75,9 @@ impl Field<'_> { pub(crate) fn source_span(&self) -> Span { if let Some(source_attr) = &self.attrs.source { - source_attr.path().span() + source_attr.path().get_ident().unwrap().span() } else if let Some(from_attr) = &self.attrs.from { - from_attr.path().span() + from_attr.path().get_ident().unwrap().span() } else { self.member.member_span() } From ebebf77fe0a130769f92306d402e266ca30c512d Mon Sep 17 00:00:00 2001 From: David Tolnay Date: Thu, 19 Oct 2023 11:03:31 -0700 Subject: [PATCH 06/31] Format ui tests with rustfmt `rustfmt tests/ui/*.rs` --- tests/ui/from-backtrace-backtrace.rs | 7 ++++- tests/ui/from-backtrace-backtrace.stderr | 6 ++-- tests/ui/source-enum-not-error.rs | 4 +-- tests/ui/source-enum-not-error.stderr | 38 ++++++++++++------------ tests/ui/transparent-enum-not-error.rs | 4 +-- 5 files changed, 30 insertions(+), 29 deletions(-) diff --git a/tests/ui/from-backtrace-backtrace.rs b/tests/ui/from-backtrace-backtrace.rs index 8f411bf5..3b781ac4 100644 --- a/tests/ui/from-backtrace-backtrace.rs +++ b/tests/ui/from-backtrace-backtrace.rs @@ -5,6 +5,11 @@ use thiserror::Error; #[derive(Error, Debug)] #[error("...")] -pub struct Error(#[from] #[backtrace] std::io::Error, Backtrace); +pub struct Error( + #[from] + #[backtrace] + std::io::Error, + Backtrace, +); fn main() {} diff --git a/tests/ui/from-backtrace-backtrace.stderr b/tests/ui/from-backtrace-backtrace.stderr index 55d647b4..5c0b9a3b 100644 --- a/tests/ui/from-backtrace-backtrace.stderr +++ b/tests/ui/from-backtrace-backtrace.stderr @@ -1,5 +1,5 @@ error: deriving From requires no fields other than source and backtrace - --> tests/ui/from-backtrace-backtrace.rs:8:18 + --> tests/ui/from-backtrace-backtrace.rs:9:5 | -8 | pub struct Error(#[from] #[backtrace] std::io::Error, Backtrace); - | ^^^^^^^ +9 | #[from] + | ^^^^^^^ diff --git a/tests/ui/source-enum-not-error.rs b/tests/ui/source-enum-not-error.rs index 3eb0d3e8..dae2285b 100644 --- a/tests/ui/source-enum-not-error.rs +++ b/tests/ui/source-enum-not-error.rs @@ -6,9 +6,7 @@ pub struct NotError; #[derive(Error, Debug)] #[error("...")] pub enum ErrorEnum { - Broken { - source: NotError, - }, + Broken { source: NotError }, } fn main() {} diff --git a/tests/ui/source-enum-not-error.stderr b/tests/ui/source-enum-not-error.stderr index 750c69eb..4c44742d 100644 --- a/tests/ui/source-enum-not-error.stderr +++ b/tests/ui/source-enum-not-error.stderr @@ -1,22 +1,22 @@ error[E0599]: the method `as_dyn_error` exists for reference `&NotError`, but its trait bounds were not satisfied - --> tests/ui/source-enum-not-error.rs:10:9 - | -4 | pub struct NotError; - | ------------------- - | | - | doesn't satisfy `NotError: AsDynError<'_>` - | doesn't satisfy `NotError: std::error::Error` + --> tests/ui/source-enum-not-error.rs:9:14 + | +4 | pub struct NotError; + | ------------------- + | | + | doesn't satisfy `NotError: AsDynError<'_>` + | doesn't satisfy `NotError: std::error::Error` ... -10 | source: NotError, - | ^^^^^^ method cannot be called on `&NotError` due to unsatisfied trait bounds - | - = note: the following trait bounds were not satisfied: - `NotError: std::error::Error` - which is required by `NotError: AsDynError<'_>` - `&NotError: std::error::Error` - which is required by `&NotError: AsDynError<'_>` +9 | Broken { source: NotError }, + | ^^^^^^ method cannot be called on `&NotError` due to unsatisfied trait bounds + | + = note: the following trait bounds were not satisfied: + `NotError: std::error::Error` + which is required by `NotError: AsDynError<'_>` + `&NotError: std::error::Error` + which is required by `&NotError: AsDynError<'_>` note: the trait `std::error::Error` must be implemented - --> $RUST/core/src/error.rs - | - | pub trait Error: Debug + Display { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + --> $RUST/core/src/error.rs + | + | pub trait Error: Debug + Display { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/tests/ui/transparent-enum-not-error.rs b/tests/ui/transparent-enum-not-error.rs index 2ef74571..80ccfc97 100644 --- a/tests/ui/transparent-enum-not-error.rs +++ b/tests/ui/transparent-enum-not-error.rs @@ -3,9 +3,7 @@ use thiserror::Error; #[derive(Error, Debug)] pub enum Error { #[error(transparent)] - Other { - message: String, - } + Other { message: String }, } fn main() {} From 4088d169edce8fe029935273bf8cbbc6f08f3a7d Mon Sep 17 00:00:00 2001 From: David Tolnay Date: Thu, 19 Oct 2023 11:07:53 -0700 Subject: [PATCH 07/31] Ignore module_name_repetitions pedantic clippy lint warning: item name ends with its containing module's name --> impl/src/span.rs:4:11 | 4 | pub trait MemberSpan { | ^^^^^^^^^^ | = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#module_name_repetitions = note: `-W clippy::module-name-repetitions` implied by `-W clippy::pedantic` = help: to override `-W clippy::pedantic` add `#[allow(clippy::module_name_repetitions)]` --- impl/src/lib.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/impl/src/lib.rs b/impl/src/lib.rs index 683c8fb6..cc86dc49 100644 --- a/impl/src/lib.rs +++ b/impl/src/lib.rs @@ -6,6 +6,7 @@ clippy::manual_let_else, clippy::manual_map, clippy::map_unwrap_or, + clippy::module_name_repetitions, clippy::needless_pass_by_value, clippy::option_if_let_else, clippy::range_plus_one, From a7d220d7915fb888413aa7978efd70f7006bda9d Mon Sep 17 00:00:00 2001 From: David Tolnay Date: Thu, 19 Oct 2023 11:10:16 -0700 Subject: [PATCH 08/31] Release 1.0.50 --- Cargo.toml | 4 ++-- impl/Cargo.toml | 2 +- src/lib.rs | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 71cf1def..86e24299 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "thiserror" -version = "1.0.49" +version = "1.0.50" authors = ["David Tolnay "] categories = ["rust-patterns"] description = "derive(Error)" @@ -12,7 +12,7 @@ repository = "https://github.com/dtolnay/thiserror" rust-version = "1.56" [dependencies] -thiserror-impl = { version = "=1.0.49", path = "impl" } +thiserror-impl = { version = "=1.0.50", path = "impl" } [dev-dependencies] anyhow = "1.0.73" diff --git a/impl/Cargo.toml b/impl/Cargo.toml index 6a538a90..f96b8883 100644 --- a/impl/Cargo.toml +++ b/impl/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "thiserror-impl" -version = "1.0.49" +version = "1.0.50" authors = ["David Tolnay "] description = "Implementation detail of the `thiserror` crate" edition = "2021" diff --git a/src/lib.rs b/src/lib.rs index 3242c1f6..97406363 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -228,7 +228,7 @@ //! //! [`anyhow`]: https://github.com/dtolnay/anyhow -#![doc(html_root_url = "https://docs.rs/thiserror/1.0.49")] +#![doc(html_root_url = "https://docs.rs/thiserror/1.0.50")] #![allow( clippy::module_name_repetitions, clippy::needless_lifetimes, From e9ea67c7e251764c3c2d839b6c06d9f35b154647 Mon Sep 17 00:00:00 2001 From: David Tolnay Date: Sat, 21 Oct 2023 21:36:54 -0700 Subject: [PATCH 09/31] Ignore struct_field_names pedantic clippy lint warning: field name ends with the struct's name --> impl/src/attr.rs:23:5 | 23 | pub has_bonus_display: bool, | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#struct_field_names = note: `-W clippy::struct-field-names` implied by `-W clippy::pedantic` = help: to override `-W clippy::pedantic` add `#[allow(clippy::struct_field_names)]` --- impl/src/lib.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/impl/src/lib.rs b/impl/src/lib.rs index cc86dc49..39951789 100644 --- a/impl/src/lib.rs +++ b/impl/src/lib.rs @@ -11,6 +11,7 @@ clippy::option_if_let_else, clippy::range_plus_one, clippy::single_match_else, + clippy::struct_field_names, clippy::too_many_lines, clippy::wrong_self_convention )] From 4fe306f5c39c6f488e13b7c3de1ccab586375289 Mon Sep 17 00:00:00 2001 From: David Tolnay Date: Fri, 15 Dec 2023 09:25:24 -0800 Subject: [PATCH 10/31] Restore UI test involving missing Display impl This test existed prior to 04b91d76462834279a323b7771b48158aba19db4. Since 791a98eb93e08f111bd16d7ec73caf50f7225f31, we can rely on rust-src being installed. --- tests/ui/missing-display.rs | 9 +++++++++ tests/ui/missing-display.stderr | 8 ++++++++ 2 files changed, 17 insertions(+) create mode 100644 tests/ui/missing-display.rs create mode 100644 tests/ui/missing-display.stderr diff --git a/tests/ui/missing-display.rs b/tests/ui/missing-display.rs new file mode 100644 index 00000000..31e23fe6 --- /dev/null +++ b/tests/ui/missing-display.rs @@ -0,0 +1,9 @@ +use thiserror::Error; + +#[derive(Error, Debug)] +pub enum MyError { + First, + Second, +} + +fn main() {} diff --git a/tests/ui/missing-display.stderr b/tests/ui/missing-display.stderr new file mode 100644 index 00000000..8dea6c57 --- /dev/null +++ b/tests/ui/missing-display.stderr @@ -0,0 +1,8 @@ +error[E0277]: `MyError` doesn't implement `std::fmt::Display` + --> tests/ui/missing-display.rs:4:1 + | +4 | pub enum MyError { + | ^^^^^^^^^^^^^^^^ `MyError` cannot be formatted with the default formatter + | + = help: the trait `std::fmt::Display` is not implemented for `MyError` + = note: in format strings you may be able to use `{:?}` (or {:#?} for pretty-print) instead From 65f7773ccae67dc18eef2b03ec53b25720eea0a8 Mon Sep 17 00:00:00 2001 From: David Tolnay Date: Fri, 15 Dec 2023 10:06:05 -0800 Subject: [PATCH 11/31] Update to nightly-2020-04-20 --- tests/ui/missing-display.stderr | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/tests/ui/missing-display.stderr b/tests/ui/missing-display.stderr index 8dea6c57..d6861898 100644 --- a/tests/ui/missing-display.stderr +++ b/tests/ui/missing-display.stderr @@ -4,5 +4,10 @@ error[E0277]: `MyError` doesn't implement `std::fmt::Display` 4 | pub enum MyError { | ^^^^^^^^^^^^^^^^ `MyError` cannot be formatted with the default formatter | + ::: $RUST/src/libstd/error.rs + | + | pub trait Error: Debug + Display { + | ------- required by this bound in `std::error::Error` + | = help: the trait `std::fmt::Display` is not implemented for `MyError` = note: in format strings you may be able to use `{:?}` (or {:#?} for pretty-print) instead From 34e4333af7e416e2b8c532ede92c761470bf56b0 Mon Sep 17 00:00:00 2001 From: David Tolnay Date: Fri, 15 Dec 2023 10:16:51 -0800 Subject: [PATCH 12/31] Update to nightly-2020-07-29 --- tests/ui/missing-display.stderr | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/ui/missing-display.stderr b/tests/ui/missing-display.stderr index d6861898..050cdf4e 100644 --- a/tests/ui/missing-display.stderr +++ b/tests/ui/missing-display.stderr @@ -4,7 +4,7 @@ error[E0277]: `MyError` doesn't implement `std::fmt::Display` 4 | pub enum MyError { | ^^^^^^^^^^^^^^^^ `MyError` cannot be formatted with the default formatter | - ::: $RUST/src/libstd/error.rs + ::: $RUST/std/src/error.rs | | pub trait Error: Debug + Display { | ------- required by this bound in `std::error::Error` From 2fe64972de24d3ff4f13a3abb02ab57b73f0319a Mon Sep 17 00:00:00 2001 From: David Tolnay Date: Fri, 15 Dec 2023 10:25:01 -0800 Subject: [PATCH 13/31] Update to nightly-2021-08-18 --- tests/ui/missing-display.stderr | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/tests/ui/missing-display.stderr b/tests/ui/missing-display.stderr index 050cdf4e..ad1d814a 100644 --- a/tests/ui/missing-display.stderr +++ b/tests/ui/missing-display.stderr @@ -4,10 +4,10 @@ error[E0277]: `MyError` doesn't implement `std::fmt::Display` 4 | pub enum MyError { | ^^^^^^^^^^^^^^^^ `MyError` cannot be formatted with the default formatter | - ::: $RUST/std/src/error.rs - | - | pub trait Error: Debug + Display { - | ------- required by this bound in `std::error::Error` - | = help: the trait `std::fmt::Display` is not implemented for `MyError` = note: in format strings you may be able to use `{:?}` (or {:#?} for pretty-print) instead +note: required by a bound in `std::error::Error` + --> $RUST/std/src/error.rs + | + | pub trait Error: Debug + Display { + | ^^^^^^^ required by this bound in `std::error::Error` From e7ab6fbd4c5c3a7ff799a8964e8b34d031e865f9 Mon Sep 17 00:00:00 2001 From: David Tolnay Date: Fri, 15 Dec 2023 10:30:13 -0800 Subject: [PATCH 14/31] Update to nightly-2022-08-24 --- tests/ui/missing-display.stderr | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/ui/missing-display.stderr b/tests/ui/missing-display.stderr index ad1d814a..35cdb703 100644 --- a/tests/ui/missing-display.stderr +++ b/tests/ui/missing-display.stderr @@ -7,7 +7,7 @@ error[E0277]: `MyError` doesn't implement `std::fmt::Display` = help: the trait `std::fmt::Display` is not implemented for `MyError` = note: in format strings you may be able to use `{:?}` (or {:#?} for pretty-print) instead note: required by a bound in `std::error::Error` - --> $RUST/std/src/error.rs + --> $RUST/core/src/error.rs | | pub trait Error: Debug + Display { | ^^^^^^^ required by this bound in `std::error::Error` From cf0c5a85c353f59bbfeb6bbdcb790f7fd6f4a914 Mon Sep 17 00:00:00 2001 From: David Tolnay Date: Fri, 15 Dec 2023 10:37:48 -0800 Subject: [PATCH 15/31] Update to nightly-2022-12-12 --- tests/ui/missing-display.stderr | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/ui/missing-display.stderr b/tests/ui/missing-display.stderr index 35cdb703..31f08c0e 100644 --- a/tests/ui/missing-display.stderr +++ b/tests/ui/missing-display.stderr @@ -10,4 +10,4 @@ note: required by a bound in `std::error::Error` --> $RUST/core/src/error.rs | | pub trait Error: Debug + Display { - | ^^^^^^^ required by this bound in `std::error::Error` + | ^^^^^^^ required by this bound in `Error` From 88edb2b0df7d530db11365ae92089920cfa64afe Mon Sep 17 00:00:00 2001 From: David Tolnay Date: Fri, 15 Dec 2023 10:43:16 -0800 Subject: [PATCH 16/31] Update to nightly-2023-01-14 --- tests/ui/missing-display.stderr | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/ui/missing-display.stderr b/tests/ui/missing-display.stderr index 31f08c0e..df2bbe02 100644 --- a/tests/ui/missing-display.stderr +++ b/tests/ui/missing-display.stderr @@ -1,8 +1,8 @@ error[E0277]: `MyError` doesn't implement `std::fmt::Display` - --> tests/ui/missing-display.rs:4:1 + --> tests/ui/missing-display.rs:4:10 | 4 | pub enum MyError { - | ^^^^^^^^^^^^^^^^ `MyError` cannot be formatted with the default formatter + | ^^^^^^^ `MyError` cannot be formatted with the default formatter | = help: the trait `std::fmt::Display` is not implemented for `MyError` = note: in format strings you may be able to use `{:?}` (or {:#?} for pretty-print) instead From abb651db3e43093eae684bff17c40de494cd5bb7 Mon Sep 17 00:00:00 2001 From: David Tolnay Date: Fri, 15 Dec 2023 10:47:16 -0800 Subject: [PATCH 17/31] Regenerate missing-display.stderr using modern trybuild --- tests/ui/missing-display.stderr | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/tests/ui/missing-display.stderr b/tests/ui/missing-display.stderr index df2bbe02..48c9ded9 100644 --- a/tests/ui/missing-display.stderr +++ b/tests/ui/missing-display.stderr @@ -1,13 +1,13 @@ error[E0277]: `MyError` doesn't implement `std::fmt::Display` - --> tests/ui/missing-display.rs:4:10 - | -4 | pub enum MyError { - | ^^^^^^^ `MyError` cannot be formatted with the default formatter - | - = help: the trait `std::fmt::Display` is not implemented for `MyError` - = note: in format strings you may be able to use `{:?}` (or {:#?} for pretty-print) instead + --> tests/ui/missing-display.rs:4:10 + | +4 | pub enum MyError { + | ^^^^^^^ `MyError` cannot be formatted with the default formatter + | + = help: the trait `std::fmt::Display` is not implemented for `MyError` + = note: in format strings you may be able to use `{:?}` (or {:#?} for pretty-print) instead note: required by a bound in `std::error::Error` - --> $RUST/core/src/error.rs - | - | pub trait Error: Debug + Display { - | ^^^^^^^ required by this bound in `Error` + --> $RUST/core/src/error.rs + | + | pub trait Error: Debug + Display { + | ^^^^^^^ required by this bound in `Error` From ed16526d4dda99938a4e067c1d61e01b67eb1d6c Mon Sep 17 00:00:00 2001 From: David Tolnay Date: Fri, 15 Dec 2023 10:51:40 -0800 Subject: [PATCH 18/31] Delete elaborate spans on path of error trait --- impl/src/expand.rs | 28 +++------------------------- 1 file changed, 3 insertions(+), 25 deletions(-) diff --git a/impl/src/expand.rs b/impl/src/expand.rs index 9124ca3a..2cf0967a 100644 --- a/impl/src/expand.rs +++ b/impl/src/expand.rs @@ -5,9 +5,7 @@ use crate::span::MemberSpan; use proc_macro2::TokenStream; use quote::{format_ident, quote, quote_spanned, ToTokens}; use std::collections::BTreeSet as Set; -use syn::{ - Data, DeriveInput, GenericArgument, Member, PathArguments, Result, Token, Type, Visibility, -}; +use syn::{DeriveInput, GenericArgument, Member, PathArguments, Result, Token, Type}; pub fn derive(node: &DeriveInput) -> Result { let input = Input::from_syn(node)?; @@ -168,7 +166,6 @@ fn impl_struct(input: Struct) -> TokenStream { } }); - let error_trait = spanned_error_trait(input.original); if input.generics.type_params().next().is_some() { let self_token = ::default(); error_inferred_bounds.insert(self_token, Trait::Debug); @@ -178,7 +175,7 @@ fn impl_struct(input: Struct) -> TokenStream { quote! { #[allow(unused_qualifications)] - impl #impl_generics #error_trait for #ty #ty_generics #error_where_clause { + impl #impl_generics std::error::Error for #ty #ty_generics #error_where_clause { #source_method #provide_method } @@ -425,7 +422,6 @@ fn impl_enum(input: Enum) -> TokenStream { }) }); - let error_trait = spanned_error_trait(input.original); if input.generics.type_params().next().is_some() { let self_token = ::default(); error_inferred_bounds.insert(self_token, Trait::Debug); @@ -435,7 +431,7 @@ fn impl_enum(input: Enum) -> TokenStream { quote! { #[allow(unused_qualifications)] - impl #impl_generics #error_trait for #ty #ty_generics #error_where_clause { + impl #impl_generics std::error::Error for #ty #ty_generics #error_where_clause { #source_method #provide_method } @@ -528,21 +524,3 @@ fn type_parameter_of_option(ty: &Type) -> Option<&Type> { _ => None, } } - -fn spanned_error_trait(input: &DeriveInput) -> TokenStream { - let vis_span = match &input.vis { - Visibility::Public(vis) => Some(vis.span), - Visibility::Restricted(vis) => Some(vis.pub_token.span), - Visibility::Inherited => None, - }; - let data_span = match &input.data { - Data::Struct(data) => data.struct_token.span, - Data::Enum(data) => data.enum_token.span, - Data::Union(data) => data.union_token.span, - }; - let first_span = vis_span.unwrap_or(data_span); - let last_span = input.ident.span(); - let path = quote_spanned!(first_span=> std::error::); - let error = quote_spanned!(last_span=> Error); - quote!(#path #error) -} From d1efad11a57833578a81215662829cd656e6b2ed Mon Sep 17 00:00:00 2001 From: David Tolnay Date: Fri, 15 Dec 2023 10:54:25 -0800 Subject: [PATCH 19/31] Delete unused original DeriveInput from ast --- impl/src/ast.rs | 4 ---- 1 file changed, 4 deletions(-) diff --git a/impl/src/ast.rs b/impl/src/ast.rs index 2aa7246c..9e069289 100644 --- a/impl/src/ast.rs +++ b/impl/src/ast.rs @@ -12,7 +12,6 @@ pub enum Input<'a> { } pub struct Struct<'a> { - pub original: &'a DeriveInput, pub attrs: Attrs<'a>, pub ident: Ident, pub generics: &'a Generics, @@ -20,7 +19,6 @@ pub struct Struct<'a> { } pub struct Enum<'a> { - pub original: &'a DeriveInput, pub attrs: Attrs<'a>, pub ident: Ident, pub generics: &'a Generics, @@ -65,7 +63,6 @@ impl<'a> Struct<'a> { display.expand_shorthand(&fields); } Ok(Struct { - original: node, attrs, ident: node.ident.clone(), generics: &node.generics, @@ -96,7 +93,6 @@ impl<'a> Enum<'a> { }) .collect::>()?; Ok(Enum { - original: node, attrs, ident: node.ident.clone(), generics: &node.generics, From b010e52359f3e68d29eff4b08a2890bac3fc1644 Mon Sep 17 00:00:00 2001 From: David Tolnay Date: Fri, 15 Dec 2023 12:13:15 -0800 Subject: [PATCH 20/31] Add test looking for invalid input to still generate an impl --- tests/ui/invalid-input-impl-anyway.rs | 11 +++++++++++ tests/ui/invalid-input-impl-anyway.stderr | 13 +++++++++++++ 2 files changed, 24 insertions(+) create mode 100644 tests/ui/invalid-input-impl-anyway.rs create mode 100644 tests/ui/invalid-input-impl-anyway.stderr diff --git a/tests/ui/invalid-input-impl-anyway.rs b/tests/ui/invalid-input-impl-anyway.rs new file mode 100644 index 00000000..f9a10d84 --- /dev/null +++ b/tests/ui/invalid-input-impl-anyway.rs @@ -0,0 +1,11 @@ +use thiserror::Error; + +#[derive(Error, Debug)] +#[error] +pub struct MyError; + +fn main() { + // FIXME: there should be no error on the following line. Thiserror should + // emit an Error impl regardless of the bad attribute. + _ = &MyError as &dyn std::error::Error; +} diff --git a/tests/ui/invalid-input-impl-anyway.stderr b/tests/ui/invalid-input-impl-anyway.stderr new file mode 100644 index 00000000..297b1001 --- /dev/null +++ b/tests/ui/invalid-input-impl-anyway.stderr @@ -0,0 +1,13 @@ +error: expected attribute arguments in parentheses: #[error(...)] + --> tests/ui/invalid-input-impl-anyway.rs:4:3 + | +4 | #[error] + | ^^^^^ + +error[E0277]: the trait bound `MyError: std::error::Error` is not satisfied + --> tests/ui/invalid-input-impl-anyway.rs:10:9 + | +10 | _ = &MyError as &dyn std::error::Error; + | ^^^^^^^^ the trait `std::error::Error` is not implemented for `MyError` + | + = note: required for the cast from `&MyError` to `&dyn std::error::Error` From 7e5ff62806e75a89f92980420d64c4a460cb6751 Mon Sep 17 00:00:00 2001 From: David Tolnay Date: Fri, 15 Dec 2023 12:14:48 -0800 Subject: [PATCH 21/31] Emit an Error impl even in the presence of bad attributes --- impl/src/expand.rs | 28 +++++++++++++++++-- impl/src/lib.rs | 4 +-- tests/ui/bad-field-attr.stderr | 14 ++++++++++ tests/ui/concat-display.stderr | 14 ++++++++++ tests/ui/duplicate-enum-source.stderr | 14 ++++++++++ tests/ui/duplicate-fmt.stderr | 14 ++++++++++ tests/ui/duplicate-struct-source.stderr | 14 ++++++++++ tests/ui/duplicate-transparent.stderr | 14 ++++++++++ tests/ui/from-backtrace-backtrace.stderr | 14 ++++++++++ tests/ui/from-not-source.stderr | 14 ++++++++++ tests/ui/invalid-input-impl-anyway.rs | 4 +-- tests/ui/invalid-input-impl-anyway.stderr | 20 +++++++++----- tests/ui/lifetime.stderr | 28 +++++++++++++++++++ tests/ui/missing-fmt.stderr | 14 ++++++++++ tests/ui/transparent-display.stderr | 14 ++++++++++ tests/ui/transparent-enum-many.stderr | 14 ++++++++++ tests/ui/transparent-enum-source.stderr | 14 ++++++++++ tests/ui/transparent-struct-many.stderr | 14 ++++++++++ tests/ui/transparent-struct-source.stderr | 14 ++++++++++ tests/ui/unexpected-field-fmt.stderr | 14 ++++++++++ tests/ui/unexpected-struct-source.stderr | 14 ++++++++++ tests/ui/union.stderr | 33 +++++++++++++++++++++++ 22 files changed, 327 insertions(+), 14 deletions(-) diff --git a/impl/src/expand.rs b/impl/src/expand.rs index 2cf0967a..2183d4cc 100644 --- a/impl/src/expand.rs +++ b/impl/src/expand.rs @@ -7,8 +7,18 @@ use quote::{format_ident, quote, quote_spanned, ToTokens}; use std::collections::BTreeSet as Set; use syn::{DeriveInput, GenericArgument, Member, PathArguments, Result, Token, Type}; -pub fn derive(node: &DeriveInput) -> Result { - let input = Input::from_syn(node)?; +pub fn derive(input: &DeriveInput) -> TokenStream { + match try_expand(input) { + Ok(expanded) => expanded, + // If there are invalid attributes in the input, expand to an Error impl + // anyway to minimize spurious knock-on errors in other code that uses + // this type as an Error. + Err(error) => fallback(input, error), + } +} + +fn try_expand(input: &DeriveInput) -> Result { + let input = Input::from_syn(input)?; input.validate()?; Ok(match input { Input::Struct(input) => impl_struct(input), @@ -16,6 +26,20 @@ pub fn derive(node: &DeriveInput) -> Result { }) } +fn fallback(input: &DeriveInput, error: syn::Error) -> TokenStream { + let ty = &input.ident; + let (impl_generics, ty_generics, where_clause) = input.generics.split_for_impl(); + + let error = error.to_compile_error(); + + quote! { + #error + + #[allow(unused_qualifications)] + impl #impl_generics std::error::Error for #ty #ty_generics #where_clause {} + } +} + fn impl_struct(input: Struct) -> TokenStream { let ty = &input.ident; let (impl_generics, ty_generics, where_clause) = input.generics.split_for_impl(); diff --git a/impl/src/lib.rs b/impl/src/lib.rs index 39951789..b6471ff3 100644 --- a/impl/src/lib.rs +++ b/impl/src/lib.rs @@ -33,7 +33,5 @@ use syn::{parse_macro_input, DeriveInput}; #[proc_macro_derive(Error, attributes(backtrace, error, from, source))] pub fn derive_error(input: TokenStream) -> TokenStream { let input = parse_macro_input!(input as DeriveInput); - expand::derive(&input) - .unwrap_or_else(|err| err.to_compile_error()) - .into() + expand::derive(&input).into() } diff --git a/tests/ui/bad-field-attr.stderr b/tests/ui/bad-field-attr.stderr index 5fb57441..2476eb5d 100644 --- a/tests/ui/bad-field-attr.stderr +++ b/tests/ui/bad-field-attr.stderr @@ -3,3 +3,17 @@ error: #[error(transparent)] needs to go outside the enum or struct, not on an i | 5 | pub struct Error(#[error(transparent)] std::io::Error); | ^^^^^^^^^^^^^^^^^^^^^ + +error[E0277]: `Error` doesn't implement `std::fmt::Display` + --> tests/ui/bad-field-attr.rs:5:12 + | +5 | pub struct Error(#[error(transparent)] std::io::Error); + | ^^^^^ `Error` cannot be formatted with the default formatter + | + = help: the trait `std::fmt::Display` is not implemented for `Error` + = note: in format strings you may be able to use `{:?}` (or {:#?} for pretty-print) instead +note: required by a bound in `std::error::Error` + --> $RUST/core/src/error.rs + | + | pub trait Error: Debug + Display { + | ^^^^^^^ required by this bound in `Error` diff --git a/tests/ui/concat-display.stderr b/tests/ui/concat-display.stderr index dbecd69f..aa49a8c2 100644 --- a/tests/ui/concat-display.stderr +++ b/tests/ui/concat-display.stderr @@ -8,3 +8,17 @@ error: expected string literal | ------------------------- in this macro invocation | = note: this error originates in the macro `error_type` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0277]: `Error` doesn't implement `std::fmt::Display` + --> tests/ui/concat-display.rs:13:13 + | +13 | error_type!(Error, "foo"); + | ^^^^^ `Error` cannot be formatted with the default formatter + | + = help: the trait `std::fmt::Display` is not implemented for `Error` + = note: in format strings you may be able to use `{:?}` (or {:#?} for pretty-print) instead +note: required by a bound in `std::error::Error` + --> $RUST/core/src/error.rs + | + | pub trait Error: Debug + Display { + | ^^^^^^^ required by this bound in `Error` diff --git a/tests/ui/duplicate-enum-source.stderr b/tests/ui/duplicate-enum-source.stderr index 4a4b2d39..6a9fc6e0 100644 --- a/tests/ui/duplicate-enum-source.stderr +++ b/tests/ui/duplicate-enum-source.stderr @@ -3,3 +3,17 @@ error: duplicate #[source] attribute | 8 | #[source] | ^^^^^^^^^ + +error[E0277]: `ErrorEnum` doesn't implement `std::fmt::Display` + --> tests/ui/duplicate-enum-source.rs:4:10 + | +4 | pub enum ErrorEnum { + | ^^^^^^^^^ `ErrorEnum` cannot be formatted with the default formatter + | + = help: the trait `std::fmt::Display` is not implemented for `ErrorEnum` + = note: in format strings you may be able to use `{:?}` (or {:#?} for pretty-print) instead +note: required by a bound in `std::error::Error` + --> $RUST/core/src/error.rs + | + | pub trait Error: Debug + Display { + | ^^^^^^^ required by this bound in `Error` diff --git a/tests/ui/duplicate-fmt.stderr b/tests/ui/duplicate-fmt.stderr index 532b16bd..dba5ed57 100644 --- a/tests/ui/duplicate-fmt.stderr +++ b/tests/ui/duplicate-fmt.stderr @@ -3,3 +3,17 @@ error: only one #[error(...)] attribute is allowed | 5 | #[error("...")] | ^^^^^^^^^^^^^^^ + +error[E0277]: `Error` doesn't implement `std::fmt::Display` + --> tests/ui/duplicate-fmt.rs:6:12 + | +6 | pub struct Error; + | ^^^^^ `Error` cannot be formatted with the default formatter + | + = help: the trait `std::fmt::Display` is not implemented for `Error` + = note: in format strings you may be able to use `{:?}` (or {:#?} for pretty-print) instead +note: required by a bound in `std::error::Error` + --> $RUST/core/src/error.rs + | + | pub trait Error: Debug + Display { + | ^^^^^^^ required by this bound in `Error` diff --git a/tests/ui/duplicate-struct-source.stderr b/tests/ui/duplicate-struct-source.stderr index c8de5747..af9769f6 100644 --- a/tests/ui/duplicate-struct-source.stderr +++ b/tests/ui/duplicate-struct-source.stderr @@ -3,3 +3,17 @@ error: duplicate #[source] attribute | 7 | #[source] | ^^^^^^^^^ + +error[E0277]: `ErrorStruct` doesn't implement `std::fmt::Display` + --> tests/ui/duplicate-struct-source.rs:4:12 + | +4 | pub struct ErrorStruct { + | ^^^^^^^^^^^ `ErrorStruct` cannot be formatted with the default formatter + | + = help: the trait `std::fmt::Display` is not implemented for `ErrorStruct` + = note: in format strings you may be able to use `{:?}` (or {:#?} for pretty-print) instead +note: required by a bound in `std::error::Error` + --> $RUST/core/src/error.rs + | + | pub trait Error: Debug + Display { + | ^^^^^^^ required by this bound in `Error` diff --git a/tests/ui/duplicate-transparent.stderr b/tests/ui/duplicate-transparent.stderr index a8308790..03bda29e 100644 --- a/tests/ui/duplicate-transparent.stderr +++ b/tests/ui/duplicate-transparent.stderr @@ -3,3 +3,17 @@ error: duplicate #[error(transparent)] attribute | 5 | #[error(transparent)] | ^^^^^^^^^^^^^^^^^^^^^ + +error[E0277]: `Error` doesn't implement `std::fmt::Display` + --> tests/ui/duplicate-transparent.rs:6:12 + | +6 | pub struct Error(anyhow::Error); + | ^^^^^ `Error` cannot be formatted with the default formatter + | + = help: the trait `std::fmt::Display` is not implemented for `Error` + = note: in format strings you may be able to use `{:?}` (or {:#?} for pretty-print) instead +note: required by a bound in `std::error::Error` + --> $RUST/core/src/error.rs + | + | pub trait Error: Debug + Display { + | ^^^^^^^ required by this bound in `Error` diff --git a/tests/ui/from-backtrace-backtrace.stderr b/tests/ui/from-backtrace-backtrace.stderr index 5c0b9a3b..259aea53 100644 --- a/tests/ui/from-backtrace-backtrace.stderr +++ b/tests/ui/from-backtrace-backtrace.stderr @@ -3,3 +3,17 @@ error: deriving From requires no fields other than source and backtrace | 9 | #[from] | ^^^^^^^ + +error[E0277]: `Error` doesn't implement `std::fmt::Display` + --> tests/ui/from-backtrace-backtrace.rs:8:12 + | +8 | pub struct Error( + | ^^^^^ `Error` cannot be formatted with the default formatter + | + = help: the trait `std::fmt::Display` is not implemented for `Error` + = note: in format strings you may be able to use `{:?}` (or {:#?} for pretty-print) instead +note: required by a bound in `std::error::Error` + --> $RUST/core/src/error.rs + | + | pub trait Error: Debug + Display { + | ^^^^^^^ required by this bound in `Error` diff --git a/tests/ui/from-not-source.stderr b/tests/ui/from-not-source.stderr index 97136017..92f58703 100644 --- a/tests/ui/from-not-source.stderr +++ b/tests/ui/from-not-source.stderr @@ -3,3 +3,17 @@ error: #[from] is only supported on the source field, not any other field | 7 | #[from] | ^^^^^^^ + +error[E0277]: `Error` doesn't implement `std::fmt::Display` + --> tests/ui/from-not-source.rs:4:12 + | +4 | pub struct Error { + | ^^^^^ `Error` cannot be formatted with the default formatter + | + = help: the trait `std::fmt::Display` is not implemented for `Error` + = note: in format strings you may be able to use `{:?}` (or {:#?} for pretty-print) instead +note: required by a bound in `std::error::Error` + --> $RUST/core/src/error.rs + | + | pub trait Error: Debug + Display { + | ^^^^^^^ required by this bound in `Error` diff --git a/tests/ui/invalid-input-impl-anyway.rs b/tests/ui/invalid-input-impl-anyway.rs index f9a10d84..0a0bcbee 100644 --- a/tests/ui/invalid-input-impl-anyway.rs +++ b/tests/ui/invalid-input-impl-anyway.rs @@ -5,7 +5,7 @@ use thiserror::Error; pub struct MyError; fn main() { - // FIXME: there should be no error on the following line. Thiserror should - // emit an Error impl regardless of the bad attribute. + // No error on the following line. Thiserror emits an Error impl despite the + // bad attribute. _ = &MyError as &dyn std::error::Error; } diff --git a/tests/ui/invalid-input-impl-anyway.stderr b/tests/ui/invalid-input-impl-anyway.stderr index 297b1001..1b58b6c1 100644 --- a/tests/ui/invalid-input-impl-anyway.stderr +++ b/tests/ui/invalid-input-impl-anyway.stderr @@ -4,10 +4,16 @@ error: expected attribute arguments in parentheses: #[error(...)] 4 | #[error] | ^^^^^ -error[E0277]: the trait bound `MyError: std::error::Error` is not satisfied - --> tests/ui/invalid-input-impl-anyway.rs:10:9 - | -10 | _ = &MyError as &dyn std::error::Error; - | ^^^^^^^^ the trait `std::error::Error` is not implemented for `MyError` - | - = note: required for the cast from `&MyError` to `&dyn std::error::Error` +error[E0277]: `MyError` doesn't implement `std::fmt::Display` + --> tests/ui/invalid-input-impl-anyway.rs:5:12 + | +5 | pub struct MyError; + | ^^^^^^^ `MyError` cannot be formatted with the default formatter + | + = help: the trait `std::fmt::Display` is not implemented for `MyError` + = note: in format strings you may be able to use `{:?}` (or {:#?} for pretty-print) instead +note: required by a bound in `std::error::Error` + --> $RUST/core/src/error.rs + | + | pub trait Error: Debug + Display { + | ^^^^^^^ required by this bound in `Error` diff --git a/tests/ui/lifetime.stderr b/tests/ui/lifetime.stderr index 8b58136e..b2d71380 100644 --- a/tests/ui/lifetime.stderr +++ b/tests/ui/lifetime.stderr @@ -9,3 +9,31 @@ error: non-static lifetimes are not allowed in the source of an error, because s | 15 | Foo(#[from] Generic<&'a str>), | ^^^^^^^^^^^^^^^^ + +error[E0277]: `Error<'a>` doesn't implement `std::fmt::Display` + --> tests/ui/lifetime.rs:6:8 + | +6 | struct Error<'a>(#[from] Inner<'a>); + | ^^^^^^^^^ `Error<'a>` cannot be formatted with the default formatter + | + = help: the trait `std::fmt::Display` is not implemented for `Error<'a>` + = note: in format strings you may be able to use `{:?}` (or {:#?} for pretty-print) instead +note: required by a bound in `std::error::Error` + --> $RUST/core/src/error.rs + | + | pub trait Error: Debug + Display { + | ^^^^^^^ required by this bound in `Error` + +error[E0277]: `Enum<'a>` doesn't implement `std::fmt::Display` + --> tests/ui/lifetime.rs:13:6 + | +13 | enum Enum<'a> { + | ^^^^^^^^ `Enum<'a>` cannot be formatted with the default formatter + | + = help: the trait `std::fmt::Display` is not implemented for `Enum<'a>` + = note: in format strings you may be able to use `{:?}` (or {:#?} for pretty-print) instead +note: required by a bound in `std::error::Error` + --> $RUST/core/src/error.rs + | + | pub trait Error: Debug + Display { + | ^^^^^^^ required by this bound in `Error` diff --git a/tests/ui/missing-fmt.stderr b/tests/ui/missing-fmt.stderr index c0be3735..9f34ff1f 100644 --- a/tests/ui/missing-fmt.stderr +++ b/tests/ui/missing-fmt.stderr @@ -3,3 +3,17 @@ error: missing #[error("...")] display attribute | 7 | B(usize), | ^^^^^^^^ + +error[E0277]: `Error` doesn't implement `std::fmt::Display` + --> tests/ui/missing-fmt.rs:4:10 + | +4 | pub enum Error { + | ^^^^^ `Error` cannot be formatted with the default formatter + | + = help: the trait `std::fmt::Display` is not implemented for `Error` + = note: in format strings you may be able to use `{:?}` (or {:#?} for pretty-print) instead +note: required by a bound in `std::error::Error` + --> $RUST/core/src/error.rs + | + | pub trait Error: Debug + Display { + | ^^^^^^^ required by this bound in `Error` diff --git a/tests/ui/transparent-display.stderr b/tests/ui/transparent-display.stderr index 54d958b2..e35d7320 100644 --- a/tests/ui/transparent-display.stderr +++ b/tests/ui/transparent-display.stderr @@ -3,3 +3,17 @@ error: cannot have both #[error(transparent)] and a display attribute | 5 | #[error("...")] | ^^^^^^^^^^^^^^^ + +error[E0277]: `Error` doesn't implement `std::fmt::Display` + --> tests/ui/transparent-display.rs:6:12 + | +6 | pub struct Error(anyhow::Error); + | ^^^^^ `Error` cannot be formatted with the default formatter + | + = help: the trait `std::fmt::Display` is not implemented for `Error` + = note: in format strings you may be able to use `{:?}` (or {:#?} for pretty-print) instead +note: required by a bound in `std::error::Error` + --> $RUST/core/src/error.rs + | + | pub trait Error: Debug + Display { + | ^^^^^^^ required by this bound in `Error` diff --git a/tests/ui/transparent-enum-many.stderr b/tests/ui/transparent-enum-many.stderr index a9adfa5a..849a8aba 100644 --- a/tests/ui/transparent-enum-many.stderr +++ b/tests/ui/transparent-enum-many.stderr @@ -4,3 +4,17 @@ error: #[error(transparent)] requires exactly one field 5 | / #[error(transparent)] 6 | | Other(anyhow::Error, String), | |________________________________^ + +error[E0277]: `Error` doesn't implement `std::fmt::Display` + --> tests/ui/transparent-enum-many.rs:4:10 + | +4 | pub enum Error { + | ^^^^^ `Error` cannot be formatted with the default formatter + | + = help: the trait `std::fmt::Display` is not implemented for `Error` + = note: in format strings you may be able to use `{:?}` (or {:#?} for pretty-print) instead +note: required by a bound in `std::error::Error` + --> $RUST/core/src/error.rs + | + | pub trait Error: Debug + Display { + | ^^^^^^^ required by this bound in `Error` diff --git a/tests/ui/transparent-enum-source.stderr b/tests/ui/transparent-enum-source.stderr index ccb90677..fb33d127 100644 --- a/tests/ui/transparent-enum-source.stderr +++ b/tests/ui/transparent-enum-source.stderr @@ -3,3 +3,17 @@ error: transparent variant can't contain #[source] | 6 | Other(#[source] anyhow::Error), | ^^^^^^^^^ + +error[E0277]: `Error` doesn't implement `std::fmt::Display` + --> tests/ui/transparent-enum-source.rs:4:10 + | +4 | pub enum Error { + | ^^^^^ `Error` cannot be formatted with the default formatter + | + = help: the trait `std::fmt::Display` is not implemented for `Error` + = note: in format strings you may be able to use `{:?}` (or {:#?} for pretty-print) instead +note: required by a bound in `std::error::Error` + --> $RUST/core/src/error.rs + | + | pub trait Error: Debug + Display { + | ^^^^^^^ required by this bound in `Error` diff --git a/tests/ui/transparent-struct-many.stderr b/tests/ui/transparent-struct-many.stderr index c0e3806e..add231a6 100644 --- a/tests/ui/transparent-struct-many.stderr +++ b/tests/ui/transparent-struct-many.stderr @@ -3,3 +3,17 @@ error: #[error(transparent)] requires exactly one field | 4 | #[error(transparent)] | ^^^^^^^^^^^^^^^^^^^^^ + +error[E0277]: `Error` doesn't implement `std::fmt::Display` + --> tests/ui/transparent-struct-many.rs:5:12 + | +5 | pub struct Error { + | ^^^^^ `Error` cannot be formatted with the default formatter + | + = help: the trait `std::fmt::Display` is not implemented for `Error` + = note: in format strings you may be able to use `{:?}` (or {:#?} for pretty-print) instead +note: required by a bound in `std::error::Error` + --> $RUST/core/src/error.rs + | + | pub trait Error: Debug + Display { + | ^^^^^^^ required by this bound in `Error` diff --git a/tests/ui/transparent-struct-source.stderr b/tests/ui/transparent-struct-source.stderr index 3012ca31..54d8230e 100644 --- a/tests/ui/transparent-struct-source.stderr +++ b/tests/ui/transparent-struct-source.stderr @@ -3,3 +3,17 @@ error: transparent error struct can't contain #[source] | 5 | pub struct Error(#[source] anyhow::Error); | ^^^^^^^^^ + +error[E0277]: `Error` doesn't implement `std::fmt::Display` + --> tests/ui/transparent-struct-source.rs:5:12 + | +5 | pub struct Error(#[source] anyhow::Error); + | ^^^^^ `Error` cannot be formatted with the default formatter + | + = help: the trait `std::fmt::Display` is not implemented for `Error` + = note: in format strings you may be able to use `{:?}` (or {:#?} for pretty-print) instead +note: required by a bound in `std::error::Error` + --> $RUST/core/src/error.rs + | + | pub trait Error: Debug + Display { + | ^^^^^^^ required by this bound in `Error` diff --git a/tests/ui/unexpected-field-fmt.stderr b/tests/ui/unexpected-field-fmt.stderr index bf3c24df..65d4ff9a 100644 --- a/tests/ui/unexpected-field-fmt.stderr +++ b/tests/ui/unexpected-field-fmt.stderr @@ -3,3 +3,17 @@ error: not expected here; the #[error(...)] attribute belongs on top of a struct | 6 | #[error("...")] | ^^^^^^^^^^^^^^^ + +error[E0277]: `Error` doesn't implement `std::fmt::Display` + --> tests/ui/unexpected-field-fmt.rs:4:10 + | +4 | pub enum Error { + | ^^^^^ `Error` cannot be formatted with the default formatter + | + = help: the trait `std::fmt::Display` is not implemented for `Error` + = note: in format strings you may be able to use `{:?}` (or {:#?} for pretty-print) instead +note: required by a bound in `std::error::Error` + --> $RUST/core/src/error.rs + | + | pub trait Error: Debug + Display { + | ^^^^^^^ required by this bound in `Error` diff --git a/tests/ui/unexpected-struct-source.stderr b/tests/ui/unexpected-struct-source.stderr index 6f15841d..f075ed89 100644 --- a/tests/ui/unexpected-struct-source.stderr +++ b/tests/ui/unexpected-struct-source.stderr @@ -3,3 +3,17 @@ error: not expected here; the #[source] attribute belongs on a specific field | 4 | #[source] | ^^^^^^^^^ + +error[E0277]: `Error` doesn't implement `std::fmt::Display` + --> tests/ui/unexpected-struct-source.rs:5:12 + | +5 | pub struct Error; + | ^^^^^ `Error` cannot be formatted with the default formatter + | + = help: the trait `std::fmt::Display` is not implemented for `Error` + = note: in format strings you may be able to use `{:?}` (or {:#?} for pretty-print) instead +note: required by a bound in `std::error::Error` + --> $RUST/core/src/error.rs + | + | pub trait Error: Debug + Display { + | ^^^^^^^ required by this bound in `Error` diff --git a/tests/ui/union.stderr b/tests/ui/union.stderr index 3ec4d71c..d8588ffa 100644 --- a/tests/ui/union.stderr +++ b/tests/ui/union.stderr @@ -6,3 +6,36 @@ error: union as errors are not supported 6 | | num: usize, 7 | | } | |_^ + +error[E0277]: `U` doesn't implement `std::fmt::Display` + --> tests/ui/union.rs:4:11 + | +4 | pub union U { + | ^ `U` cannot be formatted with the default formatter + | + = help: the trait `std::fmt::Display` is not implemented for `U` + = note: in format strings you may be able to use `{:?}` (or {:#?} for pretty-print) instead +note: required by a bound in `std::error::Error` + --> $RUST/core/src/error.rs + | + | pub trait Error: Debug + Display { + | ^^^^^^^ required by this bound in `Error` + +error[E0277]: `U` doesn't implement `Debug` + --> tests/ui/union.rs:4:11 + | +4 | pub union U { + | ^ `U` cannot be formatted using `{:?}` + | + = help: the trait `Debug` is not implemented for `U` + = note: add `#[derive(Debug)]` to `U` or manually `impl Debug for U` +note: required by a bound in `std::error::Error` + --> $RUST/core/src/error.rs + | + | pub trait Error: Debug + Display { + | ^^^^^ required by this bound in `Error` +help: consider annotating `U` with `#[derive(Debug)]` + | +4 + #[derive(Debug)] +5 | pub union U { + | From d7e3bdd980520731862d8bcd83ad1955355b1bd3 Mon Sep 17 00:00:00 2001 From: David Tolnay Date: Fri, 15 Dec 2023 14:12:30 -0800 Subject: [PATCH 22/31] Fix redundant "Error doesn't implement Display" in fallback --- impl/src/expand.rs | 7 ++++++ tests/ui/bad-field-attr.stderr | 14 ------------ tests/ui/concat-display.stderr | 14 ------------ tests/ui/duplicate-enum-source.stderr | 14 ------------ tests/ui/duplicate-fmt.stderr | 14 ------------ tests/ui/duplicate-struct-source.stderr | 14 ------------ tests/ui/duplicate-transparent.stderr | 14 ------------ tests/ui/from-backtrace-backtrace.stderr | 14 ------------ tests/ui/from-not-source.stderr | 14 ------------ tests/ui/invalid-input-impl-anyway.stderr | 14 ------------ tests/ui/lifetime.stderr | 28 ----------------------- tests/ui/missing-fmt.stderr | 14 ------------ tests/ui/transparent-display.stderr | 14 ------------ tests/ui/transparent-enum-many.stderr | 14 ------------ tests/ui/transparent-enum-source.stderr | 14 ------------ tests/ui/transparent-struct-many.stderr | 14 ------------ tests/ui/transparent-struct-source.stderr | 14 ------------ tests/ui/unexpected-field-fmt.stderr | 14 ------------ tests/ui/unexpected-struct-source.stderr | 14 ------------ tests/ui/union.stderr | 14 ------------ 20 files changed, 7 insertions(+), 280 deletions(-) diff --git a/impl/src/expand.rs b/impl/src/expand.rs index 2183d4cc..08e00fcc 100644 --- a/impl/src/expand.rs +++ b/impl/src/expand.rs @@ -37,6 +37,13 @@ fn fallback(input: &DeriveInput, error: syn::Error) -> TokenStream { #[allow(unused_qualifications)] impl #impl_generics std::error::Error for #ty #ty_generics #where_clause {} + + #[allow(unused_qualifications)] + impl #impl_generics ::core::fmt::Display for #ty #ty_generics #where_clause { + fn fmt(&self, __formatter: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { + ::core::unreachable!() + } + } } } diff --git a/tests/ui/bad-field-attr.stderr b/tests/ui/bad-field-attr.stderr index 2476eb5d..5fb57441 100644 --- a/tests/ui/bad-field-attr.stderr +++ b/tests/ui/bad-field-attr.stderr @@ -3,17 +3,3 @@ error: #[error(transparent)] needs to go outside the enum or struct, not on an i | 5 | pub struct Error(#[error(transparent)] std::io::Error); | ^^^^^^^^^^^^^^^^^^^^^ - -error[E0277]: `Error` doesn't implement `std::fmt::Display` - --> tests/ui/bad-field-attr.rs:5:12 - | -5 | pub struct Error(#[error(transparent)] std::io::Error); - | ^^^^^ `Error` cannot be formatted with the default formatter - | - = help: the trait `std::fmt::Display` is not implemented for `Error` - = note: in format strings you may be able to use `{:?}` (or {:#?} for pretty-print) instead -note: required by a bound in `std::error::Error` - --> $RUST/core/src/error.rs - | - | pub trait Error: Debug + Display { - | ^^^^^^^ required by this bound in `Error` diff --git a/tests/ui/concat-display.stderr b/tests/ui/concat-display.stderr index aa49a8c2..dbecd69f 100644 --- a/tests/ui/concat-display.stderr +++ b/tests/ui/concat-display.stderr @@ -8,17 +8,3 @@ error: expected string literal | ------------------------- in this macro invocation | = note: this error originates in the macro `error_type` (in Nightly builds, run with -Z macro-backtrace for more info) - -error[E0277]: `Error` doesn't implement `std::fmt::Display` - --> tests/ui/concat-display.rs:13:13 - | -13 | error_type!(Error, "foo"); - | ^^^^^ `Error` cannot be formatted with the default formatter - | - = help: the trait `std::fmt::Display` is not implemented for `Error` - = note: in format strings you may be able to use `{:?}` (or {:#?} for pretty-print) instead -note: required by a bound in `std::error::Error` - --> $RUST/core/src/error.rs - | - | pub trait Error: Debug + Display { - | ^^^^^^^ required by this bound in `Error` diff --git a/tests/ui/duplicate-enum-source.stderr b/tests/ui/duplicate-enum-source.stderr index 6a9fc6e0..4a4b2d39 100644 --- a/tests/ui/duplicate-enum-source.stderr +++ b/tests/ui/duplicate-enum-source.stderr @@ -3,17 +3,3 @@ error: duplicate #[source] attribute | 8 | #[source] | ^^^^^^^^^ - -error[E0277]: `ErrorEnum` doesn't implement `std::fmt::Display` - --> tests/ui/duplicate-enum-source.rs:4:10 - | -4 | pub enum ErrorEnum { - | ^^^^^^^^^ `ErrorEnum` cannot be formatted with the default formatter - | - = help: the trait `std::fmt::Display` is not implemented for `ErrorEnum` - = note: in format strings you may be able to use `{:?}` (or {:#?} for pretty-print) instead -note: required by a bound in `std::error::Error` - --> $RUST/core/src/error.rs - | - | pub trait Error: Debug + Display { - | ^^^^^^^ required by this bound in `Error` diff --git a/tests/ui/duplicate-fmt.stderr b/tests/ui/duplicate-fmt.stderr index dba5ed57..532b16bd 100644 --- a/tests/ui/duplicate-fmt.stderr +++ b/tests/ui/duplicate-fmt.stderr @@ -3,17 +3,3 @@ error: only one #[error(...)] attribute is allowed | 5 | #[error("...")] | ^^^^^^^^^^^^^^^ - -error[E0277]: `Error` doesn't implement `std::fmt::Display` - --> tests/ui/duplicate-fmt.rs:6:12 - | -6 | pub struct Error; - | ^^^^^ `Error` cannot be formatted with the default formatter - | - = help: the trait `std::fmt::Display` is not implemented for `Error` - = note: in format strings you may be able to use `{:?}` (or {:#?} for pretty-print) instead -note: required by a bound in `std::error::Error` - --> $RUST/core/src/error.rs - | - | pub trait Error: Debug + Display { - | ^^^^^^^ required by this bound in `Error` diff --git a/tests/ui/duplicate-struct-source.stderr b/tests/ui/duplicate-struct-source.stderr index af9769f6..c8de5747 100644 --- a/tests/ui/duplicate-struct-source.stderr +++ b/tests/ui/duplicate-struct-source.stderr @@ -3,17 +3,3 @@ error: duplicate #[source] attribute | 7 | #[source] | ^^^^^^^^^ - -error[E0277]: `ErrorStruct` doesn't implement `std::fmt::Display` - --> tests/ui/duplicate-struct-source.rs:4:12 - | -4 | pub struct ErrorStruct { - | ^^^^^^^^^^^ `ErrorStruct` cannot be formatted with the default formatter - | - = help: the trait `std::fmt::Display` is not implemented for `ErrorStruct` - = note: in format strings you may be able to use `{:?}` (or {:#?} for pretty-print) instead -note: required by a bound in `std::error::Error` - --> $RUST/core/src/error.rs - | - | pub trait Error: Debug + Display { - | ^^^^^^^ required by this bound in `Error` diff --git a/tests/ui/duplicate-transparent.stderr b/tests/ui/duplicate-transparent.stderr index 03bda29e..a8308790 100644 --- a/tests/ui/duplicate-transparent.stderr +++ b/tests/ui/duplicate-transparent.stderr @@ -3,17 +3,3 @@ error: duplicate #[error(transparent)] attribute | 5 | #[error(transparent)] | ^^^^^^^^^^^^^^^^^^^^^ - -error[E0277]: `Error` doesn't implement `std::fmt::Display` - --> tests/ui/duplicate-transparent.rs:6:12 - | -6 | pub struct Error(anyhow::Error); - | ^^^^^ `Error` cannot be formatted with the default formatter - | - = help: the trait `std::fmt::Display` is not implemented for `Error` - = note: in format strings you may be able to use `{:?}` (or {:#?} for pretty-print) instead -note: required by a bound in `std::error::Error` - --> $RUST/core/src/error.rs - | - | pub trait Error: Debug + Display { - | ^^^^^^^ required by this bound in `Error` diff --git a/tests/ui/from-backtrace-backtrace.stderr b/tests/ui/from-backtrace-backtrace.stderr index 259aea53..5c0b9a3b 100644 --- a/tests/ui/from-backtrace-backtrace.stderr +++ b/tests/ui/from-backtrace-backtrace.stderr @@ -3,17 +3,3 @@ error: deriving From requires no fields other than source and backtrace | 9 | #[from] | ^^^^^^^ - -error[E0277]: `Error` doesn't implement `std::fmt::Display` - --> tests/ui/from-backtrace-backtrace.rs:8:12 - | -8 | pub struct Error( - | ^^^^^ `Error` cannot be formatted with the default formatter - | - = help: the trait `std::fmt::Display` is not implemented for `Error` - = note: in format strings you may be able to use `{:?}` (or {:#?} for pretty-print) instead -note: required by a bound in `std::error::Error` - --> $RUST/core/src/error.rs - | - | pub trait Error: Debug + Display { - | ^^^^^^^ required by this bound in `Error` diff --git a/tests/ui/from-not-source.stderr b/tests/ui/from-not-source.stderr index 92f58703..97136017 100644 --- a/tests/ui/from-not-source.stderr +++ b/tests/ui/from-not-source.stderr @@ -3,17 +3,3 @@ error: #[from] is only supported on the source field, not any other field | 7 | #[from] | ^^^^^^^ - -error[E0277]: `Error` doesn't implement `std::fmt::Display` - --> tests/ui/from-not-source.rs:4:12 - | -4 | pub struct Error { - | ^^^^^ `Error` cannot be formatted with the default formatter - | - = help: the trait `std::fmt::Display` is not implemented for `Error` - = note: in format strings you may be able to use `{:?}` (or {:#?} for pretty-print) instead -note: required by a bound in `std::error::Error` - --> $RUST/core/src/error.rs - | - | pub trait Error: Debug + Display { - | ^^^^^^^ required by this bound in `Error` diff --git a/tests/ui/invalid-input-impl-anyway.stderr b/tests/ui/invalid-input-impl-anyway.stderr index 1b58b6c1..b98c31e9 100644 --- a/tests/ui/invalid-input-impl-anyway.stderr +++ b/tests/ui/invalid-input-impl-anyway.stderr @@ -3,17 +3,3 @@ error: expected attribute arguments in parentheses: #[error(...)] | 4 | #[error] | ^^^^^ - -error[E0277]: `MyError` doesn't implement `std::fmt::Display` - --> tests/ui/invalid-input-impl-anyway.rs:5:12 - | -5 | pub struct MyError; - | ^^^^^^^ `MyError` cannot be formatted with the default formatter - | - = help: the trait `std::fmt::Display` is not implemented for `MyError` - = note: in format strings you may be able to use `{:?}` (or {:#?} for pretty-print) instead -note: required by a bound in `std::error::Error` - --> $RUST/core/src/error.rs - | - | pub trait Error: Debug + Display { - | ^^^^^^^ required by this bound in `Error` diff --git a/tests/ui/lifetime.stderr b/tests/ui/lifetime.stderr index b2d71380..8b58136e 100644 --- a/tests/ui/lifetime.stderr +++ b/tests/ui/lifetime.stderr @@ -9,31 +9,3 @@ error: non-static lifetimes are not allowed in the source of an error, because s | 15 | Foo(#[from] Generic<&'a str>), | ^^^^^^^^^^^^^^^^ - -error[E0277]: `Error<'a>` doesn't implement `std::fmt::Display` - --> tests/ui/lifetime.rs:6:8 - | -6 | struct Error<'a>(#[from] Inner<'a>); - | ^^^^^^^^^ `Error<'a>` cannot be formatted with the default formatter - | - = help: the trait `std::fmt::Display` is not implemented for `Error<'a>` - = note: in format strings you may be able to use `{:?}` (or {:#?} for pretty-print) instead -note: required by a bound in `std::error::Error` - --> $RUST/core/src/error.rs - | - | pub trait Error: Debug + Display { - | ^^^^^^^ required by this bound in `Error` - -error[E0277]: `Enum<'a>` doesn't implement `std::fmt::Display` - --> tests/ui/lifetime.rs:13:6 - | -13 | enum Enum<'a> { - | ^^^^^^^^ `Enum<'a>` cannot be formatted with the default formatter - | - = help: the trait `std::fmt::Display` is not implemented for `Enum<'a>` - = note: in format strings you may be able to use `{:?}` (or {:#?} for pretty-print) instead -note: required by a bound in `std::error::Error` - --> $RUST/core/src/error.rs - | - | pub trait Error: Debug + Display { - | ^^^^^^^ required by this bound in `Error` diff --git a/tests/ui/missing-fmt.stderr b/tests/ui/missing-fmt.stderr index 9f34ff1f..c0be3735 100644 --- a/tests/ui/missing-fmt.stderr +++ b/tests/ui/missing-fmt.stderr @@ -3,17 +3,3 @@ error: missing #[error("...")] display attribute | 7 | B(usize), | ^^^^^^^^ - -error[E0277]: `Error` doesn't implement `std::fmt::Display` - --> tests/ui/missing-fmt.rs:4:10 - | -4 | pub enum Error { - | ^^^^^ `Error` cannot be formatted with the default formatter - | - = help: the trait `std::fmt::Display` is not implemented for `Error` - = note: in format strings you may be able to use `{:?}` (or {:#?} for pretty-print) instead -note: required by a bound in `std::error::Error` - --> $RUST/core/src/error.rs - | - | pub trait Error: Debug + Display { - | ^^^^^^^ required by this bound in `Error` diff --git a/tests/ui/transparent-display.stderr b/tests/ui/transparent-display.stderr index e35d7320..54d958b2 100644 --- a/tests/ui/transparent-display.stderr +++ b/tests/ui/transparent-display.stderr @@ -3,17 +3,3 @@ error: cannot have both #[error(transparent)] and a display attribute | 5 | #[error("...")] | ^^^^^^^^^^^^^^^ - -error[E0277]: `Error` doesn't implement `std::fmt::Display` - --> tests/ui/transparent-display.rs:6:12 - | -6 | pub struct Error(anyhow::Error); - | ^^^^^ `Error` cannot be formatted with the default formatter - | - = help: the trait `std::fmt::Display` is not implemented for `Error` - = note: in format strings you may be able to use `{:?}` (or {:#?} for pretty-print) instead -note: required by a bound in `std::error::Error` - --> $RUST/core/src/error.rs - | - | pub trait Error: Debug + Display { - | ^^^^^^^ required by this bound in `Error` diff --git a/tests/ui/transparent-enum-many.stderr b/tests/ui/transparent-enum-many.stderr index 849a8aba..a9adfa5a 100644 --- a/tests/ui/transparent-enum-many.stderr +++ b/tests/ui/transparent-enum-many.stderr @@ -4,17 +4,3 @@ error: #[error(transparent)] requires exactly one field 5 | / #[error(transparent)] 6 | | Other(anyhow::Error, String), | |________________________________^ - -error[E0277]: `Error` doesn't implement `std::fmt::Display` - --> tests/ui/transparent-enum-many.rs:4:10 - | -4 | pub enum Error { - | ^^^^^ `Error` cannot be formatted with the default formatter - | - = help: the trait `std::fmt::Display` is not implemented for `Error` - = note: in format strings you may be able to use `{:?}` (or {:#?} for pretty-print) instead -note: required by a bound in `std::error::Error` - --> $RUST/core/src/error.rs - | - | pub trait Error: Debug + Display { - | ^^^^^^^ required by this bound in `Error` diff --git a/tests/ui/transparent-enum-source.stderr b/tests/ui/transparent-enum-source.stderr index fb33d127..ccb90677 100644 --- a/tests/ui/transparent-enum-source.stderr +++ b/tests/ui/transparent-enum-source.stderr @@ -3,17 +3,3 @@ error: transparent variant can't contain #[source] | 6 | Other(#[source] anyhow::Error), | ^^^^^^^^^ - -error[E0277]: `Error` doesn't implement `std::fmt::Display` - --> tests/ui/transparent-enum-source.rs:4:10 - | -4 | pub enum Error { - | ^^^^^ `Error` cannot be formatted with the default formatter - | - = help: the trait `std::fmt::Display` is not implemented for `Error` - = note: in format strings you may be able to use `{:?}` (or {:#?} for pretty-print) instead -note: required by a bound in `std::error::Error` - --> $RUST/core/src/error.rs - | - | pub trait Error: Debug + Display { - | ^^^^^^^ required by this bound in `Error` diff --git a/tests/ui/transparent-struct-many.stderr b/tests/ui/transparent-struct-many.stderr index add231a6..c0e3806e 100644 --- a/tests/ui/transparent-struct-many.stderr +++ b/tests/ui/transparent-struct-many.stderr @@ -3,17 +3,3 @@ error: #[error(transparent)] requires exactly one field | 4 | #[error(transparent)] | ^^^^^^^^^^^^^^^^^^^^^ - -error[E0277]: `Error` doesn't implement `std::fmt::Display` - --> tests/ui/transparent-struct-many.rs:5:12 - | -5 | pub struct Error { - | ^^^^^ `Error` cannot be formatted with the default formatter - | - = help: the trait `std::fmt::Display` is not implemented for `Error` - = note: in format strings you may be able to use `{:?}` (or {:#?} for pretty-print) instead -note: required by a bound in `std::error::Error` - --> $RUST/core/src/error.rs - | - | pub trait Error: Debug + Display { - | ^^^^^^^ required by this bound in `Error` diff --git a/tests/ui/transparent-struct-source.stderr b/tests/ui/transparent-struct-source.stderr index 54d8230e..3012ca31 100644 --- a/tests/ui/transparent-struct-source.stderr +++ b/tests/ui/transparent-struct-source.stderr @@ -3,17 +3,3 @@ error: transparent error struct can't contain #[source] | 5 | pub struct Error(#[source] anyhow::Error); | ^^^^^^^^^ - -error[E0277]: `Error` doesn't implement `std::fmt::Display` - --> tests/ui/transparent-struct-source.rs:5:12 - | -5 | pub struct Error(#[source] anyhow::Error); - | ^^^^^ `Error` cannot be formatted with the default formatter - | - = help: the trait `std::fmt::Display` is not implemented for `Error` - = note: in format strings you may be able to use `{:?}` (or {:#?} for pretty-print) instead -note: required by a bound in `std::error::Error` - --> $RUST/core/src/error.rs - | - | pub trait Error: Debug + Display { - | ^^^^^^^ required by this bound in `Error` diff --git a/tests/ui/unexpected-field-fmt.stderr b/tests/ui/unexpected-field-fmt.stderr index 65d4ff9a..bf3c24df 100644 --- a/tests/ui/unexpected-field-fmt.stderr +++ b/tests/ui/unexpected-field-fmt.stderr @@ -3,17 +3,3 @@ error: not expected here; the #[error(...)] attribute belongs on top of a struct | 6 | #[error("...")] | ^^^^^^^^^^^^^^^ - -error[E0277]: `Error` doesn't implement `std::fmt::Display` - --> tests/ui/unexpected-field-fmt.rs:4:10 - | -4 | pub enum Error { - | ^^^^^ `Error` cannot be formatted with the default formatter - | - = help: the trait `std::fmt::Display` is not implemented for `Error` - = note: in format strings you may be able to use `{:?}` (or {:#?} for pretty-print) instead -note: required by a bound in `std::error::Error` - --> $RUST/core/src/error.rs - | - | pub trait Error: Debug + Display { - | ^^^^^^^ required by this bound in `Error` diff --git a/tests/ui/unexpected-struct-source.stderr b/tests/ui/unexpected-struct-source.stderr index f075ed89..6f15841d 100644 --- a/tests/ui/unexpected-struct-source.stderr +++ b/tests/ui/unexpected-struct-source.stderr @@ -3,17 +3,3 @@ error: not expected here; the #[source] attribute belongs on a specific field | 4 | #[source] | ^^^^^^^^^ - -error[E0277]: `Error` doesn't implement `std::fmt::Display` - --> tests/ui/unexpected-struct-source.rs:5:12 - | -5 | pub struct Error; - | ^^^^^ `Error` cannot be formatted with the default formatter - | - = help: the trait `std::fmt::Display` is not implemented for `Error` - = note: in format strings you may be able to use `{:?}` (or {:#?} for pretty-print) instead -note: required by a bound in `std::error::Error` - --> $RUST/core/src/error.rs - | - | pub trait Error: Debug + Display { - | ^^^^^^^ required by this bound in `Error` diff --git a/tests/ui/union.stderr b/tests/ui/union.stderr index d8588ffa..d54931c0 100644 --- a/tests/ui/union.stderr +++ b/tests/ui/union.stderr @@ -7,20 +7,6 @@ error: union as errors are not supported 7 | | } | |_^ -error[E0277]: `U` doesn't implement `std::fmt::Display` - --> tests/ui/union.rs:4:11 - | -4 | pub union U { - | ^ `U` cannot be formatted with the default formatter - | - = help: the trait `std::fmt::Display` is not implemented for `U` - = note: in format strings you may be able to use `{:?}` (or {:#?} for pretty-print) instead -note: required by a bound in `std::error::Error` - --> $RUST/core/src/error.rs - | - | pub trait Error: Debug + Display { - | ^^^^^^^ required by this bound in `Error` - error[E0277]: `U` doesn't implement `Debug` --> tests/ui/union.rs:4:11 | From 1567f40ec3c00d2f228bd3b71e0f583ef5e52e88 Mon Sep 17 00:00:00 2001 From: David Tolnay Date: Fri, 15 Dec 2023 14:03:15 -0800 Subject: [PATCH 23/31] Try to remove "doesn't implement Debug" in fallback expansion --- impl/src/expand.rs | 5 ++++- tests/ui/union.stderr | 20 +++++++++----------- 2 files changed, 13 insertions(+), 12 deletions(-) diff --git a/impl/src/expand.rs b/impl/src/expand.rs index 08e00fcc..13c5fb3c 100644 --- a/impl/src/expand.rs +++ b/impl/src/expand.rs @@ -36,7 +36,10 @@ fn fallback(input: &DeriveInput, error: syn::Error) -> TokenStream { #error #[allow(unused_qualifications)] - impl #impl_generics std::error::Error for #ty #ty_generics #where_clause {} + impl #impl_generics std::error::Error for #ty #ty_generics #where_clause + where + #ty #ty_generics: ::core::fmt::Debug, + {} #[allow(unused_qualifications)] impl #impl_generics ::core::fmt::Display for #ty #ty_generics #where_clause { diff --git a/tests/ui/union.stderr b/tests/ui/union.stderr index d54931c0..8a07ae68 100644 --- a/tests/ui/union.stderr +++ b/tests/ui/union.stderr @@ -8,20 +8,18 @@ error: union as errors are not supported | |_^ error[E0277]: `U` doesn't implement `Debug` - --> tests/ui/union.rs:4:11 + --> tests/ui/union.rs:3:10 | -4 | pub union U { - | ^ `U` cannot be formatted using `{:?}` +3 | #[derive(Error)] + | ^^^^^ `U` cannot be formatted using `{:?}` | = help: the trait `Debug` is not implemented for `U` = note: add `#[derive(Debug)]` to `U` or manually `impl Debug for U` -note: required by a bound in `std::error::Error` - --> $RUST/core/src/error.rs - | - | pub trait Error: Debug + Display { - | ^^^^^ required by this bound in `Error` + = help: see issue #48214 + = help: add `#![feature(trivial_bounds)]` to the crate attributes to enable + = note: this error originates in the derive macro `Error` (in Nightly builds, run with -Z macro-backtrace for more info) help: consider annotating `U` with `#[derive(Debug)]` | -4 + #[derive(Debug)] -5 | pub union U { - | +4 + #[derive(Debug)] +5 | pub union U { + | From 1754825c24f51a1deec46a273b37c0fea32881f3 Mon Sep 17 00:00:00 2001 From: David Tolnay Date: Fri, 15 Dec 2023 14:04:35 -0800 Subject: [PATCH 24/31] Work around trivial bounds being unstable --- impl/src/expand.rs | 4 +++- tests/ui/union.stderr | 17 ----------------- 2 files changed, 3 insertions(+), 18 deletions(-) diff --git a/impl/src/expand.rs b/impl/src/expand.rs index 13c5fb3c..4ce2c0bb 100644 --- a/impl/src/expand.rs +++ b/impl/src/expand.rs @@ -38,7 +38,9 @@ fn fallback(input: &DeriveInput, error: syn::Error) -> TokenStream { #[allow(unused_qualifications)] impl #impl_generics std::error::Error for #ty #ty_generics #where_clause where - #ty #ty_generics: ::core::fmt::Debug, + // Work around trivial bounds being unstable. + // https://github.com/rust-lang/rust/issues/48214 + for<'workaround> #ty #ty_generics: ::core::fmt::Debug, {} #[allow(unused_qualifications)] diff --git a/tests/ui/union.stderr b/tests/ui/union.stderr index 8a07ae68..3ec4d71c 100644 --- a/tests/ui/union.stderr +++ b/tests/ui/union.stderr @@ -6,20 +6,3 @@ error: union as errors are not supported 6 | | num: usize, 7 | | } | |_^ - -error[E0277]: `U` doesn't implement `Debug` - --> tests/ui/union.rs:3:10 - | -3 | #[derive(Error)] - | ^^^^^ `U` cannot be formatted using `{:?}` - | - = help: the trait `Debug` is not implemented for `U` - = note: add `#[derive(Debug)]` to `U` or manually `impl Debug for U` - = help: see issue #48214 - = help: add `#![feature(trivial_bounds)]` to the crate attributes to enable - = note: this error originates in the derive macro `Error` (in Nightly builds, run with -Z macro-backtrace for more info) -help: consider annotating `U` with `#[derive(Debug)]` - | -4 + #[derive(Debug)] -5 | pub union U { - | From b94add8c9ba7c01c5c109413cc3fb00021a66792 Mon Sep 17 00:00:00 2001 From: David Tolnay Date: Fri, 15 Dec 2023 14:06:41 -0800 Subject: [PATCH 25/31] Add ui test where fallback impl conflicts with handwritten Display --- tests/ui/fallback-impl-with-display.rs | 14 ++++++++++++++ tests/ui/fallback-impl-with-display.stderr | 16 ++++++++++++++++ 2 files changed, 30 insertions(+) create mode 100644 tests/ui/fallback-impl-with-display.rs create mode 100644 tests/ui/fallback-impl-with-display.stderr diff --git a/tests/ui/fallback-impl-with-display.rs b/tests/ui/fallback-impl-with-display.rs new file mode 100644 index 00000000..33411873 --- /dev/null +++ b/tests/ui/fallback-impl-with-display.rs @@ -0,0 +1,14 @@ +use std::fmt::{self, Display}; +use thiserror::Error; + +#[derive(Error, Debug)] +#[error] +pub struct MyError; + +impl Display for MyError { + fn fmt(&self, _formatter: &mut fmt::Formatter) -> fmt::Result { + unimplemented!() + } +} + +fn main() {} diff --git a/tests/ui/fallback-impl-with-display.stderr b/tests/ui/fallback-impl-with-display.stderr new file mode 100644 index 00000000..6bd37307 --- /dev/null +++ b/tests/ui/fallback-impl-with-display.stderr @@ -0,0 +1,16 @@ +error: expected attribute arguments in parentheses: #[error(...)] + --> tests/ui/fallback-impl-with-display.rs:5:3 + | +5 | #[error] + | ^^^^^ + +error[E0119]: conflicting implementations of trait `std::fmt::Display` for type `MyError` + --> tests/ui/fallback-impl-with-display.rs:4:10 + | +4 | #[derive(Error, Debug)] + | ^^^^^ conflicting implementation for `MyError` +... +8 | impl Display for MyError { + | ------------------------ first implementation here + | + = note: this error originates in the derive macro `Error` (in Nightly builds, run with -Z macro-backtrace for more info) From 0555b805916067d898356fd67a5384606fbf8414 Mon Sep 17 00:00:00 2001 From: David Tolnay Date: Fri, 15 Dec 2023 14:19:23 -0800 Subject: [PATCH 26/31] Release 1.0.51 --- Cargo.toml | 4 ++-- impl/Cargo.toml | 2 +- src/lib.rs | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 86e24299..cc576d52 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "thiserror" -version = "1.0.50" +version = "1.0.51" authors = ["David Tolnay "] categories = ["rust-patterns"] description = "derive(Error)" @@ -12,7 +12,7 @@ repository = "https://github.com/dtolnay/thiserror" rust-version = "1.56" [dependencies] -thiserror-impl = { version = "=1.0.50", path = "impl" } +thiserror-impl = { version = "=1.0.51", path = "impl" } [dev-dependencies] anyhow = "1.0.73" diff --git a/impl/Cargo.toml b/impl/Cargo.toml index f96b8883..ff556b9f 100644 --- a/impl/Cargo.toml +++ b/impl/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "thiserror-impl" -version = "1.0.50" +version = "1.0.51" authors = ["David Tolnay "] description = "Implementation detail of the `thiserror` crate" edition = "2021" diff --git a/src/lib.rs b/src/lib.rs index 97406363..fa96a576 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -228,7 +228,7 @@ //! //! [`anyhow`]: https://github.com/dtolnay/anyhow -#![doc(html_root_url = "https://docs.rs/thiserror/1.0.50")] +#![doc(html_root_url = "https://docs.rs/thiserror/1.0.51")] #![allow( clippy::module_name_repetitions, clippy::needless_lifetimes, From 87466d2a2588c2fc2146f1c257c59f321d75953d Mon Sep 17 00:00:00 2001 From: David Tolnay Date: Sat, 16 Dec 2023 18:19:04 -0800 Subject: [PATCH 27/31] Update name of blocks_in_if_conditions clippy lint warning: lint `clippy::blocks_in_if_conditions` has been renamed to `clippy::blocks_in_conditions` --> impl/src/lib.rs:2:5 | 2 | clippy::blocks_in_if_conditions, | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::blocks_in_conditions` | = note: `#[warn(renamed_and_removed_lints)]` on by default --- impl/src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/impl/src/lib.rs b/impl/src/lib.rs index b6471ff3..cee125e5 100644 --- a/impl/src/lib.rs +++ b/impl/src/lib.rs @@ -1,5 +1,5 @@ #![allow( - clippy::blocks_in_if_conditions, + clippy::blocks_in_conditions, clippy::cast_lossless, clippy::cast_possible_truncation, clippy::manual_find, From c3838bd7c5682abf31b2604435d3bd585ca58c44 Mon Sep 17 00:00:00 2001 From: David Tolnay Date: Wed, 20 Dec 2023 15:53:58 -0800 Subject: [PATCH 28/31] Add a funding file --- .github/FUNDING.yml | 1 + 1 file changed, 1 insertion(+) create mode 100644 .github/FUNDING.yml diff --git a/.github/FUNDING.yml b/.github/FUNDING.yml new file mode 100644 index 00000000..75070770 --- /dev/null +++ b/.github/FUNDING.yml @@ -0,0 +1 @@ +github: dtolnay From 6b002356105e52bf6c296c833f56965b5efcafd4 Mon Sep 17 00:00:00 2001 From: David Tolnay Date: Mon, 25 Dec 2023 10:26:29 -0800 Subject: [PATCH 29/31] Leave private traits' name out of scope --- impl/src/expand.rs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/impl/src/expand.rs b/impl/src/expand.rs index 4ce2c0bb..1b44513a 100644 --- a/impl/src/expand.rs +++ b/impl/src/expand.rs @@ -89,7 +89,7 @@ fn impl_struct(input: Struct) -> TokenStream { let source_method = source_body.map(|body| { quote! { fn source(&self) -> ::core::option::Option<&(dyn std::error::Error + 'static)> { - use thiserror::__private::AsDynError; + use thiserror::__private::AsDynError as _; #body } } @@ -125,7 +125,7 @@ fn impl_struct(input: Struct) -> TokenStream { }) }; quote! { - use thiserror::__private::ThiserrorProvide; + use thiserror::__private::ThiserrorProvide as _; #source_provide #self_provide } @@ -266,7 +266,7 @@ fn impl_enum(input: Enum) -> TokenStream { }); Some(quote! { fn source(&self) -> ::core::option::Option<&(dyn std::error::Error + 'static)> { - use thiserror::__private::AsDynError; + use thiserror::__private::AsDynError as _; #[allow(deprecated)] match self { #(#arms)* @@ -316,7 +316,7 @@ fn impl_enum(input: Enum) -> TokenStream { #source: #varsource, .. } => { - use thiserror::__private::ThiserrorProvide; + use thiserror::__private::ThiserrorProvide as _; #source_provide #self_provide } @@ -340,7 +340,7 @@ fn impl_enum(input: Enum) -> TokenStream { }; quote! { #ty::#ident {#backtrace: #varsource, ..} => { - use thiserror::__private::ThiserrorProvide; + use thiserror::__private::ThiserrorProvide as _; #source_provide } } From af1665218f0158eb5ee3f258c8cc1a69fd921634 Mon Sep 17 00:00:00 2001 From: David Tolnay Date: Mon, 25 Dec 2023 12:12:03 -0800 Subject: [PATCH 30/31] Rerun build script on RUSTC_BOOTSTRAP change --- build.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/build.rs b/build.rs index 8bf19e19..3dc4bfeb 100644 --- a/build.rs +++ b/build.rs @@ -38,6 +38,8 @@ const PROBE: &str = r#" "#; fn main() { + println!("cargo:rerun-if-env-changed=RUSTC_BOOTSTRAP"); + match compile_probe() { Some(status) if status.success() => println!("cargo:rustc-cfg=error_generic_member_access"), _ => {} From be83323c0f0239f9600ed6d40d56a66ae2169c6e Mon Sep 17 00:00:00 2001 From: David Tolnay Date: Mon, 25 Dec 2023 13:01:40 -0800 Subject: [PATCH 31/31] Release 1.0.52 --- Cargo.toml | 4 ++-- impl/Cargo.toml | 2 +- src/lib.rs | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index cc576d52..ba1f7a20 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "thiserror" -version = "1.0.51" +version = "1.0.52" authors = ["David Tolnay "] categories = ["rust-patterns"] description = "derive(Error)" @@ -12,7 +12,7 @@ repository = "https://github.com/dtolnay/thiserror" rust-version = "1.56" [dependencies] -thiserror-impl = { version = "=1.0.51", path = "impl" } +thiserror-impl = { version = "=1.0.52", path = "impl" } [dev-dependencies] anyhow = "1.0.73" diff --git a/impl/Cargo.toml b/impl/Cargo.toml index ff556b9f..6c7e1c21 100644 --- a/impl/Cargo.toml +++ b/impl/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "thiserror-impl" -version = "1.0.51" +version = "1.0.52" authors = ["David Tolnay "] description = "Implementation detail of the `thiserror` crate" edition = "2021" diff --git a/src/lib.rs b/src/lib.rs index fa96a576..1e40c627 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -228,7 +228,7 @@ //! //! [`anyhow`]: https://github.com/dtolnay/anyhow -#![doc(html_root_url = "https://docs.rs/thiserror/1.0.51")] +#![doc(html_root_url = "https://docs.rs/thiserror/1.0.52")] #![allow( clippy::module_name_repetitions, clippy::needless_lifetimes,