Repository: JelteF/derive_more
Pull request #289 (2023-08-10 11:14:31)

Fix `?Sized` type parameters in `Debug`
## Synopsis

At the moment, `derive_more::Debug` fails to work with `?Sized` generics:
```rust
#[derive(derive_more::Debug)]
struct UnnamedGenericStructUnsized<T: ?Sized>(T);
```
And generates the following error:
```
error[E0277]: the size for values of type `T` cannot be known at compilation time
   --> tests/debug.rs:845:14
    |
845 |     #[derive(Debug)]
    |              ^^^^^ doesn't have a size known at compile-time
846 |     struct UnnamedGenericStructUnsized<T: ?Sized>(T);
    |                                        - this type parameter needs to be `std::marker::Sized`
    |
    = note: required for the cast from `&T` to `&dyn Debug`
    = note: this error originates in the derive macro `Debug` (in Nightly builds, run with -Z macro-backtrace for more info)
help: consider borrowing the value, since `&&T` can be coerced into `&dyn Debug`
    |
845 |     #[derive(&Debug)]
    |              +
help: consider removing the `?Sized` bound to make the type parameter `Sized`
    |
846 -     struct UnnamedGenericStructUnsized<T: ?Sized>(T);
846 +     struct UnnamedGenericStructUnsized<T>(T);
    |
```

At the same moment, `std::Debug` works OK:
```rust
#[derive(std::Debug)]
struct UnnamedGenericStructUnsized<T: ?Sized>(T);
```
If we look at its expansion:
```rust
#[automatically_derived]
impl<T: ::core::fmt::Debug + ?Sized> ::core::fmt::Debug for
    UnnamedGenericStructUnsized<T> {
    fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
        ::core::fmt::Formatter::debug_tuple_field1_finish(f,
            "UnnamedGenericStructUnsized", &&self.0)
    }
}
```
We can see that `std::Debug` always uses fields as `&&self.0`, while we in our `derive_more::Debug` expansion [use `&self.0` only](https://github.com/JelteF/derive_more/blob/v1.0.0-beta.3/impl/src/fmt/debug.rs#L80).




## Solution

Simply use double-ref in the expansion, as the error suggests, and `std::Debug` does.




## Checklist

- [x] ~~Documentation is updated~~ (not required)
- [x] Tests are added/updated (if required)
- [x] ~~[CHANGELOG entry][l:1] is added~~ (not required)




[l:1]: /CHANGELOG.md


JelteF: Does the same issue exist for other derives? Especially Display seems likely to have the same bug 
tyranron: @JelteF seems no. The bug goes from the [`&dyn Debug` usage in the debug building API](https://github.com/JelteF/derive_more/blob/v1.0.0-beta.3/src/fmt.rs#L58). Other `Display`-like and other traits doesn't use such API atm.

I can add similar tests for other traits as a separate PR. Just to be sure.
tyranron: @JelteF ping.

Patch:
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 694012e..5113303 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -52,6 +52,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
   ([#206](https://github.com/JelteF/derive_more/pull/206))
 - Add support for container format in `Debug` derive with the same syntax as `Display` derives.
   ([#279](https://github.com/JelteF/derive_more/pull/279))
+- `derive_more::derive` module exporting only macros, without traits. ([#290](https://github.com/JelteF/derive_more/pull/290))
 
 ### Changed
 
diff --git a/impl/src/fmt/debug.rs b/impl/src/fmt/debug.rs
index 4c8948f..8cfc5e4 100644
--- a/impl/src/fmt/debug.rs
+++ b/impl/src/fmt/debug.rs
@@ -77,7 +77,7 @@ fn expand_struct(
             .ident
             .clone()
             .map_or_else(|| syn::Member::Unnamed(i.into()), syn::Member::Named);
-        quote! { let #var = &self.#member; }
+        quote! { let #var = &&self.#member; }
     });
 
     let body = quote! {
diff --git a/src/lib.rs b/src/lib.rs
index 8e02a91..cf4fa49 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -57,6 +57,14 @@ pub mod __private {
     pub use crate::vendor::thiserror::aserror::AsDynError;
 }
 
+/// Module containing macro definitions only, without corresponding traits.
+///
+/// Use it in your import paths, if you don't want to import traits, but only macros.
+pub mod derive {
+    #[doc(inline)]
+    pub use derive_more_impl::*;
+}
+
 // The modules containing error types and other helpers.
 
 #[cfg(feature = "add")]


Test patch:
diff --git a/tests/debug.rs b/tests/debug.rs
index 4b02412..710ed3d 100644
--- a/tests/debug.rs
+++ b/tests/debug.rs
@@ -637,7 +637,7 @@ mod enums {
 
 mod generic {
     #[cfg(not(feature = "std"))]
-    use alloc::format;
+    use alloc::{boxed::Box, format};
     use core::fmt;
 
     use derive_more::Debug;
@@ -666,6 +666,22 @@ mod generic {
         );
     }
 
+    #[derive(Debug)]
+    struct NamedGenericStructUnsized<T: ?Sized> {
+        field: T,
+    }
+    #[test]
+    fn named_generic_struct_unsized() {
+        assert_eq!(
+            format!("{:?}", NamedGenericStructUnsized { field: 1 }),
+            "NamedGenericStructUnsized { field: 1 }",
+        );
+        assert_eq!(
+            format!("{:#?}", NamedGenericStructUnsized { field: 1 }),
+            "NamedGenericStructUnsized {\n    field: 1,\n}",
+        );
+    }
+
     #[derive(Debug)]
     struct NamedGenericStructIgnored<T> {
         #[debug(ignore)]
@@ -826,6 +842,20 @@ mod generic {
         );
     }
 
+    #[derive(Debug)]
+    struct UnnamedGenericStructUnsized<T: ?Sized>(T);
+    #[test]
+    fn unnamed_generic_struct_unsized() {
+        assert_eq!(
+            format!("{:?}", UnnamedGenericStructUnsized(2)),
+            "UnnamedGenericStructUnsized(2)",
+        );
+        assert_eq!(
+            format!("{:#?}", UnnamedGenericStructUnsized(2)),
+            "UnnamedGenericStructUnsized(\n    2,\n)",
+        );
+    }
+
     #[derive(Debug)]
     struct UnnamedGenericStructIgnored<T>(#[debug(skip)] T);
     #[test]
@@ -910,11 +940,11 @@ mod generic {
     fn generic_enum() {
         assert_eq!(
             format!("{:?}", GenericEnum::A::<_, u8> { field: 1 }),
-            "A { field: 1 }"
+            "A { field: 1 }",
         );
         assert_eq!(
             format!("{:#?}", GenericEnum::A::<_, u8> { field: 1 }),
-            "A {\n    field: 1,\n}"
+            "A {\n    field: 1,\n}",
         );
         assert_eq!(format!("{:?}", GenericEnum::B::<u8, _>(2)), "B(2)");
         assert_eq!(
@@ -923,6 +953,34 @@ mod generic {
         );
     }
 
+    #[derive(derive_more::Debug)]
+    enum GenericEnumUnsized<A: ?Sized, B: ?Sized + 'static> {
+        A { field: Box<A> },
+        B(&'static B),
+    }
+    #[test]
+    fn generic_enum_unsized() {
+        assert_eq!(
+            format!("{:?}", GenericEnumUnsized::A::<i32, u8> { field: 1.into() }),
+            "A { field: 1 }",
+        );
+        assert_eq!(
+            format!(
+                "{:#?}",
+                GenericEnumUnsized::A::<i32, u8> { field: 1.into() },
+            ),
+            "A {\n    field: 1,\n}",
+        );
+        assert_eq!(
+            format!("{:?}", GenericEnumUnsized::B::<u8, i32>(&2)),
+            "B(2)",
+        );
+        assert_eq!(
+            format!("{:#?}", GenericEnumUnsized::B::<u8, i32>(&2)),
+            "B(\n    2,\n)",
+        );
+    }
+
     #[derive(Debug)]
     enum InterpolatedGenericEnum<A, B> {
         A {