Repository: dtolnay/thiserror (rust)

Issue:
`allow`s are not propagated to auto-generated `impl`s
# Problem statement

Built-in derive macros (e.g., `Debug`) behave differently than `thiserror::Error` wrt propagation of `#[allow(...)]` attributes.


### Built-in macros

`allow` attributes are propagated to auto-generated `impl`s.

### `thiserror::Error`

`allow` attributes are **not** propagated to auto-generated `impl`s.

### Example

```rust
#[deprecated]
#[allow(deprecated, never_type_fallback_flowing_into_unsafe)]
#[derive(Debug, Error)]
#[error("B")]
pub struct B;
```

gets expanded into (formatted for readability):

```rust
#[deprecated]
#[allow(deprecated, never_type_fallback_flowing_into_unsafe)]
#[error("B")]
pub struct B;

#[automatically_derived]
#[allow(deprecated, never_type_fallback_flowing_into_unsafe)]
impl ::core::fmt::Debug for B {
    #[inline]
    fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
        ::core::fmt::Formatter::write_str(f, "B")
    }
}

#[allow(unused_qualifications)]
#[automatically_derived]
impl ::thiserror::__private::Error for B {}

#[allow(unused_qualifications)]
#[automatically_derived]
impl ::core::fmt::Display for B {
    #[allow(clippy::used_underscore_binding)]
    fn fmt(&self, __formatter: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
        #[allow(unused_variables, deprecated)]
        let Self {} = self;
        __formatter.write_str("B")
    }
}
```

# Proposed solution

Do propagate `allow`s to `impl`s generated by `thiserror::Error`.


Pull request:
Suppress deprecation warning on generated From impls
Closes #392.

Patch:
diff --git a/impl/src/expand.rs b/impl/src/expand.rs
index d0b302b..20ba1d2 100644
--- a/impl/src/expand.rs
+++ b/impl/src/expand.rs
@@ -170,10 +170,9 @@ fn impl_struct(input: Struct) -> TokenStream {
         let source_var = Ident::new("source", span);
         let body = from_initializer(from_field, backtrace_field, &source_var);
         quote_spanned! {span=>
-            #[allow(unused_qualifications, clippy::needless_lifetimes)]
+            #[allow(deprecated, unused_qualifications, clippy::needless_lifetimes)]
             #[automatically_derived]
             impl #impl_generics ::core::convert::From<#from> for #ty #ty_generics #where_clause {
-                #[allow(deprecated)]
                 fn from(#source_var: #from) -> Self {
                     #ty #body
                 }
@@ -435,10 +434,9 @@ fn impl_enum(input: Enum) -> TokenStream {
         let source_var = Ident::new("source", span);
         let body = from_initializer(from_field, backtrace_field, &source_var);
         Some(quote_spanned! {span=>
-            #[allow(unused_qualifications, clippy::needless_lifetimes)]
+            #[allow(deprecated, unused_qualifications, clippy::needless_lifetimes)]
             #[automatically_derived]
             impl #impl_generics ::core::convert::From<#from> for #ty #ty_generics #where_clause {
-                #[allow(deprecated)]
                 fn from(#source_var: #from) -> Self {
                     #ty::#variant #body
                 }


Test patch:
diff --git a/tests/test_lints.rs b/tests/test_lints.rs
index b46a391..d272454 100644
--- a/tests/test_lints.rs
+++ b/tests/test_lints.rs
@@ -64,6 +64,16 @@ fn test_deprecated() {
         Variant,
     }
 
+    #[derive(Error, Debug)]
+    pub enum DeprecatedFrom {
+        #[error(transparent)]
+        Variant(
+            #[from]
+            #[allow(deprecated)]
+            DeprecatedStruct,
+        ),
+    }
+
     #[allow(deprecated)]
     let _: DeprecatedStruct;
     #[allow(deprecated)]