Skip to content

Unused generic in struct definition is allowed when used in invariant position #152884

@theemathas

Description

@theemathas

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)

Metadata

Metadata

Assignees

Labels

A-type-systemArea: Type systemA-varianceArea: Variance (https://doc.rust-lang.org/nomicon/subtyping.html)C-bugCategory: This is a bug.T-langRelevant to the language teamT-typesRelevant to the types team, which will review and decide on the PR/issue.

Type

No type
No fields configured for issues without a type.

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions