From 06acaad5b3020401e64bbb21027c5b7363835d9a Mon Sep 17 00:00:00 2001 From: Kai Ren Date: Thu, 29 Aug 2024 16:43:25 +0200 Subject: [PATCH] Add `#[allow(unreachable_code)]` to generated impls for `!` type (#404, #400) ## Synopsis For `!` never type used in trait signatures, `rustc` emits `unreachable_code` warning ignoring the `#[automatically_derived]` attribute. ## Solution Add `#[allow(unreachable_code)]` to generated `impl`s to suppress such warnings for `!` and similar types. --- CHANGELOG.md | 2 ++ impl/src/as/mod.rs | 1 + impl/src/constructor.rs | 1 + impl/src/deref.rs | 1 + impl/src/deref_mut.rs | 1 + impl/src/fmt/debug.rs | 1 + impl/src/fmt/display.rs | 1 + impl/src/from.rs | 10 +++++--- impl/src/is_variant.rs | 1 + impl/src/not_like.rs | 1 + impl/src/try_unwrap.rs | 1 + impl/src/unwrap.rs | 1 + tests/as_mut.rs | 38 +++++++++++++++++++++++++++++ tests/as_ref.rs | 38 +++++++++++++++++++++++++++++ tests/constructor.rs | 23 ++++++++++++++++++ tests/debug.rs | 50 ++++++++++++++++++++++++++++++++++++++ tests/deref.rs | 14 +++++++++++ tests/deref_mut.rs | 32 ++++++++++++++++++++++++ tests/display.rs | 54 +++++++++++++++++++++++++++++++++++++++++ tests/from.rs | 26 ++++++++++++++++++++ tests/is_variant.rs | 14 +++++++++++ tests/not.rs | 31 +++++++++++++++++++++++ tests/try_unwrap.rs | 12 +++++++++ tests/unwrap.rs | 12 +++++++++ 24 files changed, 363 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 49e08e00..5029725c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -12,6 +12,8 @@ and this project adheres to [Semantic Versioning](http://semver.org/). - Associated types of type parameters not being treated as generics in `Debug` and `Display` expansions. ([#399](https://github.com/JelteF/derive_more/pull/399)) +- `unreachable_code` warnings on generated code when `!` (never type) is used. + ([#404](https://github.com/JelteF/derive_more/pull/404)) ## 1.0.0 - 2024-08-07 diff --git a/impl/src/as/mod.rs b/impl/src/as/mod.rs index fd631aa3..5157fe86 100644 --- a/impl/src/as/mod.rs +++ b/impl/src/as/mod.rs @@ -280,6 +280,7 @@ impl<'a> ToTokens for Expansion<'a> { }; quote! { + #[allow(unreachable_code)] // omit warnings for `!` and other unreachable types #[automatically_derived] impl #impl_gens #trait_ty for #ty_ident #ty_gens #where_clause { #[inline] diff --git a/impl/src/constructor.rs b/impl/src/constructor.rs index 284b0643..c1c77cb3 100644 --- a/impl/src/constructor.rs +++ b/impl/src/constructor.rs @@ -26,6 +26,7 @@ pub fn expand(input: &DeriveInput, _: &str) -> TokenStream { let original_types = &get_field_types(&fields); quote! { #[allow(missing_docs)] + #[allow(unreachable_code)] // omit warnings for `!` and other unreachable types #[automatically_derived] impl #impl_generics #input_type #ty_generics #where_clause { #[inline] diff --git a/impl/src/deref.rs b/impl/src/deref.rs index f87c64cc..cbfc5bdc 100644 --- a/impl/src/deref.rs +++ b/impl/src/deref.rs @@ -42,6 +42,7 @@ pub fn expand(input: &DeriveInput, trait_name: &'static str) -> Result Result syn::Result { }; Ok(quote! { + #[allow(unreachable_code)] // omit warnings for `!` and other unreachable types #[automatically_derived] impl #impl_gens derive_more::Debug for #ident #ty_gens #where_clause { #[inline] diff --git a/impl/src/fmt/display.rs b/impl/src/fmt/display.rs index b217a779..41320df5 100644 --- a/impl/src/fmt/display.rs +++ b/impl/src/fmt/display.rs @@ -62,6 +62,7 @@ pub fn expand(input: &syn::DeriveInput, trait_name: &str) -> syn::Result Expansion<'a> { }); Ok(quote! { + #[allow(unreachable_code)] // omit warnings for `!` and unreachable types #[automatically_derived] impl #impl_gens derive_more::From<#ty> for #ident #ty_gens #where_clause { #[inline] @@ -192,6 +193,7 @@ impl<'a> Expansion<'a> { }); Ok(quote! { + #[allow(unreachable_code)] // omit warnings for `!` and other unreachable types #[automatically_derived] impl #impl_gens derive_more::From<(#( #field_tys ),*)> for #ident #ty_gens #where_clause { #[inline] @@ -222,9 +224,10 @@ impl<'a> Expansion<'a> { let generics = { let mut generics = self.generics.clone(); for (ty, ident) in field_tys.iter().zip(&gen_idents) { - generics.make_where_clause().predicates.push( - parse_quote! { #ty: derive_more::From<#ident> }, - ); + generics + .make_where_clause() + .predicates + .push(parse_quote! { #ty: derive_more::From<#ident> }); generics .params .push(syn::TypeParam::from(ident.clone()).into()); @@ -234,6 +237,7 @@ impl<'a> Expansion<'a> { let (impl_gens, _, where_clause) = generics.split_for_impl(); Ok(quote! { + #[allow(unreachable_code)] // omit warnings for `!` and other unreachable types #[automatically_derived] impl #impl_gens derive_more::From<(#( #gen_idents ),*)> for #ident #ty_gens #where_clause { #[inline] diff --git a/impl/src/is_variant.rs b/impl/src/is_variant.rs index 12f7db1e..86d1de49 100644 --- a/impl/src/is_variant.rs +++ b/impl/src/is_variant.rs @@ -53,6 +53,7 @@ pub fn expand(input: &DeriveInput, trait_name: &'static str) -> Result TokenStream { }; quote! { + #[allow(unreachable_code)] // omit warnings for `!` and other unreachable types #[automatically_derived] impl #impl_generics derive_more::#trait_ident for #input_type #ty_generics #where_clause { type Output = #output_type; diff --git a/impl/src/try_unwrap.rs b/impl/src/try_unwrap.rs index b90ba714..28187962 100644 --- a/impl/src/try_unwrap.rs +++ b/impl/src/try_unwrap.rs @@ -123,6 +123,7 @@ pub fn expand(input: &DeriveInput, trait_name: &'static str) -> Result Result &Self::Target { + self.0 + } + } + + #[derive(DerefMut)] + struct Struct { + field: !, + } + + // `Deref` implementation is required for `DerefMut`. + impl ::core::ops::Deref for Struct { + type Target = !; + #[inline] + fn deref(&self) -> &Self::Target { + self.field + } + } +} diff --git a/tests/display.rs b/tests/display.rs index c3cf1c14..a7257237 100644 --- a/tests/display.rs +++ b/tests/display.rs @@ -1,4 +1,5 @@ #![cfg_attr(not(feature = "std"), no_std)] +#![cfg_attr(nightly, feature(never_type))] #![allow(dead_code)] // some code is tested for type checking only #[cfg(not(feature = "std"))] @@ -528,6 +529,19 @@ mod structs { } } } + + #[cfg(nightly)] + mod never { + use super::*; + + #[derive(Display)] + struct Tuple(!); + + #[derive(Display)] + struct Struct { + field: !, + } + } } mod multi_field { @@ -682,6 +696,22 @@ mod structs { } } } + + #[cfg(nightly)] + mod never { + use super::*; + + #[derive(Display)] + #[display("{_0}")] + struct Tuple(i32, !); + + #[derive(Display)] + #[display("{field}")] + struct Struct { + field: !, + other: i32, + } + } } } @@ -1154,6 +1184,17 @@ mod enums { } } } + + #[cfg(nightly)] + mod never { + use super::*; + + #[derive(Display)] + enum Enum { + Unnamed(!), + Named { field: ! }, + } + } } mod multi_field_variant { @@ -1314,6 +1355,19 @@ mod enums { } } + #[cfg(nightly)] + mod never { + use super::*; + + #[derive(Display)] + enum Enum { + #[display("{_0}")] + Unnamed(i32, !), + #[display("{field}")] + Named { field: !, other: i32 }, + } + } + mod shared_format { use super::*; diff --git a/tests/from.rs b/tests/from.rs index 48f745fb..51cc6374 100644 --- a/tests/from.rs +++ b/tests/from.rs @@ -1,4 +1,5 @@ #![cfg_attr(not(feature = "std"), no_std)] +#![cfg_attr(nightly, feature(never_type))] #![allow(dead_code)] // some code is tested for type checking only #[cfg(not(feature = "std"))] @@ -455,6 +456,20 @@ mod structs { } } } + + #[cfg(nightly)] + mod never { + use super::*; + + #[derive(From)] + struct Tuple(i32, !); + + #[derive(From)] + struct Struct { + field1: !, + field2: i16, + } + } } } @@ -1787,5 +1802,16 @@ mod enums { ); } } + + #[cfg(nightly)] + mod never { + use super::*; + + #[derive(From)] + enum Enum { + Tuple(i8, !), + Struct { field1: !, field2: i16 }, + } + } } } diff --git a/tests/is_variant.rs b/tests/is_variant.rs index 62ce2c83..d901258c 100644 --- a/tests/is_variant.rs +++ b/tests/is_variant.rs @@ -1,4 +1,5 @@ #![cfg_attr(not(feature = "std"), no_std)] +#![cfg_attr(nightly, feature(never_type))] #![allow(dead_code)] // some code is tested for type checking only use derive_more::IsVariant; @@ -161,3 +162,16 @@ const _: () = { assert!(!ks.is_never_mind()); assert!(ks.is_nothing_to_see_here()); }; + +#[cfg(nightly)] +mod never { + use super::*; + + #[derive(IsVariant)] + enum Enum { + Tuple(!), + Struct { field: ! }, + TupleMulti(i32, !), + StructMulti { field: !, other: i32 }, + } +} diff --git a/tests/not.rs b/tests/not.rs index 96b4bb3a..31453bde 100644 --- a/tests/not.rs +++ b/tests/not.rs @@ -1,4 +1,5 @@ #![cfg_attr(not(feature = "std"), no_std)] +#![cfg_attr(nightly, feature(never_type))] #![allow(dead_code)] // some code is tested for type checking only use derive_more::Not; @@ -27,3 +28,33 @@ enum EnumWithUnit { SmallInt(i32), Unit, } + +#[cfg(nightly)] +mod never { + use super::*; + + #[derive(Not)] + struct Tuple(!); + + #[derive(Not)] + struct Struct { + field: !, + } + + #[derive(Not)] + struct TupleMulti(i32, !); + + #[derive(Not)] + struct StructMulti { + field: !, + other: i32, + } + + #[derive(Not)] + enum Enum { + Tuple(!), + Struct { field: ! }, + TupleMulti(i32, !), + StructMulti { field: !, other: i32 }, + } +} diff --git a/tests/try_unwrap.rs b/tests/try_unwrap.rs index e8a2dd8b..03ce7bd1 100644 --- a/tests/try_unwrap.rs +++ b/tests/try_unwrap.rs @@ -1,4 +1,5 @@ #![cfg_attr(not(feature = "std"), no_std)] +#![cfg_attr(nightly, feature(never_type))] #![allow(dead_code)] // some code is tested for type checking only #[cfg(not(feature = "std"))] @@ -128,3 +129,14 @@ pub fn test_try_unwrap_mut_2() { assert_eq!(value, Tuple::Double(255, 256)); } + +#[cfg(nightly)] +mod never { + use super::*; + + #[derive(TryUnwrap)] + enum Enum { + Tuple(!), + TupleMulti(i32, !), + } +} diff --git a/tests/unwrap.rs b/tests/unwrap.rs index ebff8667..018e6acb 100644 --- a/tests/unwrap.rs +++ b/tests/unwrap.rs @@ -1,4 +1,5 @@ #![cfg_attr(not(feature = "std"), no_std)] +#![cfg_attr(nightly, feature(never_type))] #![allow(dead_code)] // some code is tested for type checking only use derive_more::Unwrap; @@ -117,3 +118,14 @@ pub fn test_unwrap_mut_2() { assert_eq!(value, Tuple::Single(256)); } + +#[cfg(nightly)] +mod never { + use super::*; + + #[derive(Unwrap)] + enum Enum { + Tuple(!), + TupleMulti(i32, !), + } +}