Missing Copy/Debug traits warnings when defining enum with `strum` traits in macro

Viewed 70

I want to define an enum using a macro. The enum needs to implement the strum traits {Display, EnumIter, EnumString}. I also want to keep the warnings missing_copy_implementations, missing_debug_implementations on. I came up with the following snippet:

#![warn(
    missing_copy_implementations,
    missing_debug_implementations,
)]

macro_rules! define_fruits {
    {$($fruit:ident -> $name:literal),* $(,)?} => {
        #[derive(Display, EnumIter, EnumString, Clone, Copy, Debug)]
        pub enum Fruits {
            $(
                #[strum(to_string = $name)]
                $fruit,
            )*
        }
    };
}

define_fruits! {
    Apple -> "green",
    Orange -> "orange",
}

The above works fine except I get the warnings:

   |
4  |     missing_copy_implementations,
   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
   = note: this warning originates in the macro `define_fruits` (in Nightly builds, run with -Z macro-backtrace for more info)

and similar for missing_debug_implementations.

These warnings go away when I remove Display, EnumIter, EnumString from my enum. They also go away if I define the same enum outside of a macro.

I cannot seem to find a way to get rid of the warnings in the above scenario, can someone help?

1 Answers

TL/DR: the problem is with derive(EnumIter), which isn't compatible with these lints. I've opened the issue on strum repository asking for possible changes.


To see what really happens, let's try to cargo expand the current code. After some simplification and stubbing out the unnecessary parts, we can see the following structure:

///An iterator over the variants of [Self]
pub struct FruitsIter {
    idx: usize,
    back_idx: usize,
    marker: PhantomData<()>,
}

This is a type you get when you call IntoEnumIterator::iter derived for your enum. There's no Copy or Debug implementation for this struct - they are neither derived nor explicitly added by strum, so the lint sees the violation and fires.

A hint on the problem source can be seen when looking at the exact error, as provided by cargo check (or at the eror highlighting from rust-analyzer):

warning: type could implement `Copy`; consider adding `impl Copy`
  --> src/lib.rs:10:27
   |
10 |           #[derive(Display, EnumIter, EnumString, Clone, Copy, Debug)]
   |  ___________________________^
11 | |         pub enum Fruits {
   | |___________^

Note that the span of the "erroneous" code starts from the EnumIter - since that's the token which the FruitsIter's span is tied to, warning on the FruitsIter is shown as a warning on the derive(EnumIter). And indeed, if we drop this derive - warning disappears.

There's nothing you can do with this, I'm afraid, aside from explicitly allowing these lints for the whole module containing your enum. This is something that should probably be fixed by the strum maintainers.

Related