Unused generic in struct definition is allowed when used in invariant position
@mro95 is already working on this.
Since Mar 2, 2026.
- Dominant language
- Rust
- Stars
- 119k
- Forks
- 16.1k
- PR merge metrics
- PR metrics pending
Description
I'm not sure if this is a bug or not.
The following code compiles:
struct Thing<T>(*mut Thing<T>);
I expected the above code to not compile, since the generic parameter T is used only in a recursive position. There isn't an "actual" T usage anywhere in the struct.
Note that changing the *mut to *const makes the code stop compiling. It seems that the recursion must be in an invariant position for the code to compile.
Code and error with *const
struct Thing<T>(*const Thing<T>);
error: type parameter `T` is only used recursively
--> src/lib.rs:1:30
|
1 | struct Thing<T>(*const Thing<T>);
| - ^
| |
| type parameter must be used non-recursively in the definition
|
= help: consider removing `T`, referring to it in a field, or using a marker such as `PhantomData`
= note: all type parameters must be used in a non-recursive way in order to constrain their variance
This also has some strange behavior with auto traits. For example, the following code compiles:
use std::cell::Cell;
struct Thing<T>(Box<Cell<Thing<T>>>);
fn require_send<T: Send>() {}
fn wut() {
require_send::<Thing<*mut ()>>();
}
Discovered in #152857
cc @lcnr
Meta
Reproducible on the playground with version 1.95.0-nightly (2026-02-19 7f99507f57e6c4aa0dce)
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Assessment
This issue has not been assessed yet.