A generic parameter is claimed to be never used while it is

When I try to specify two generic parameters, I get a "never used" error:

pub struct Struct<Allocator, AllocatorError>
where
    Allocator: CustomAllocator<AllocatorError>,
{
    ptr: NonNull<u8>,
    allocator: Allocator,
}

Leads to

error[E0392]: parameter `AllocatorError` is never used
 --> src/main.rs:5:30
  |
5 | pub struct Struct<Allocator, AllocatorError>
  |                              ^^^^^^^^^^^^^^ unused parameter
  |
  = help: consider removing `AllocatorError`, referring to it in a field, or using a marker such as `PhantomData`
  = help: if you intended `AllocatorError` to be a const parameter, use `const AllocatorError: usize` instead

For more information about this error, try `rustc --explain E0392`.
error: could not compile `playground` (bin "playground") due to 1 previous error

Why does this happen? The type is obviously used as a pass-through type to the inner type. It is not used within the struct (as a member) - yes, but I cannot omit its specification.

Is this a bug or there is indeed a better way to write this?

Is there a reason why AllocatorError is a type parameter to CustomAllocator, and not an associated type? I don't know your design but the type of error seems like a thing you decide when you're writing a custom allocator, not when you use it.

In other words: do you ever have this scenario?

struct ErrorOne {...}

enum ErrorTwo {...}

struct MyAllocator;

impl CustomAllocator<ErrorOne> for MyAllocator {...}

impl CustomAllocator<ErrorTwo> for MyAllocator {...}

i.e., implementing CustomAllocator multiple times for the same implementor with different error types?

If not, an associated type may be more appropriate than a generic.

2 Likes

I understand what you mean. Thank you for your response!

I cannot say that as early as of now (in the development process), but I don't think I will. So I will use the associated type as you suggested, instead.

However, just to satisfy my curiosity about this particular matter, if this were the case, how would I tackle it? Really use PhantomData to just silence the warning?

1 Like

In my opinion, you should almost never write bounds on structs. There is no compelling reason to do so unless the code won't compile without such a bound (and that is normally only the case when the parameter is actually used). So I would simplify it to:

pub struct Struct<Allocator> {
    ptr: NonNull<u8>,
    allocator: Allocator,
}

You must still write the Allocator: CustomAllocator<AllocatorError> bound on the fns and impls where Allocator's methods are actually used.

6 Likes

It's not just “to silence the warning”. It's also to make that where bound somewhat useful. Note that since you are applying where bound not to Self but to other type it's just completely ignored. You would still need to write that where clause for each and every function that works with such structure… and this raises the question: why not specify it there, if it's not needed in the struct definition and doesn't help to do anything at all?

PhantomData would tell the compiler that yes, you are not doing mistake, you really want to restrict that structure and make it possible to only use it with one particular AllocatorError even if allocator support many of them (maybe there fail/success implementation for production and then separate fine-grained one for debug mode).

It just really doesn't make much sense to attach AllocatorError to the structure: either it's property of Allocator, or, alternatively, if your desin supports may of them then it should go where it's used.

2 Likes