Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ use rustc_errors::codes::*;
use rustc_errors::{Applicability, Diag, Diagnostic, EmissionGuarantee, MultiSpan, pluralize};
use rustc_hir as hir;
use rustc_middle::ty::{self as ty, AssocItem, AssocItems, TyCtxt};
use rustc_span::def_id::DefId;
use rustc_span::def_id::{DefId, LocalDefId};
use tracing::debug;

/// Handles the `wrong number of type / lifetime / ... arguments` family of error messages.
Expand All @@ -30,6 +30,9 @@ pub(crate) struct WrongNumberOfGenericArgs<'a, 'tcx> {

/// DefId of the generic type
pub(crate) def_id: DefId,

/// DefId of the generic type
pub(crate) cx_def_id: LocalDefId,
}

// Provides information about the kind of arguments that were provided for
Expand Down Expand Up @@ -83,6 +86,7 @@ pub(crate) enum GenericArgsInfo {
// if synthetic type arguments (e.g. `impl Trait`) are specified
synth_provided: bool,
},
// BadDerive,
}

impl<'a, 'tcx> WrongNumberOfGenericArgs<'a, 'tcx> {
Expand All @@ -94,6 +98,7 @@ impl<'a, 'tcx> WrongNumberOfGenericArgs<'a, 'tcx> {
params_offset: usize,
gen_args: &'a hir::GenericArgs<'a>,
def_id: DefId,
cx_def_id: LocalDefId,
) -> Self {
let angle_brackets = if gen_args.span_ext().is_none() {
if gen_args.is_empty() { AngleBrackets::Missing } else { AngleBrackets::Implied }
Expand All @@ -110,6 +115,7 @@ impl<'a, 'tcx> WrongNumberOfGenericArgs<'a, 'tcx> {
params_offset,
gen_args,
def_id,
cx_def_id,
}
}

Expand Down Expand Up @@ -542,6 +548,25 @@ impl<'a, 'tcx> WrongNumberOfGenericArgs<'a, 'tcx> {
}
}

fn bad_derive(&self, err: &mut Diag<'_, impl EmissionGuarantee>) -> bool {
if let Some(ident) = self.tcx.opt_item_ident(self.def_id)
&& self.def_id.is_local()
&& self.path_segment.ident.span.source_equal(ident.span)
&& self.tcx.is_automatically_derived(self.cx_def_id.into())
{
// Very likely this is a botched `derive` which passes the iten name straight
// through, but doesn't support type parameters.
err.span_label(
self.tcx.def_span(self.cx_def_id),
"it looks like this derive macro might not support annotating items with type \
parameters",
);
Comment on lines +561 to +563

@CenTdemeern1 CenTdemeern1 Aug 7, 2026

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

it might be more accurate to say "generic parameters" as this applies to the other types of generic parameters too (lifetimes, const params)

View changes since the review


return true;
}
false
}

/// Builds the `expected 1 type argument / supplied 2 type arguments` message.
fn notify(&self, err: &mut Diag<'_, impl EmissionGuarantee>) {
let (quantifier, bound) = self.get_quantifier_and_bound();
Expand Down Expand Up @@ -1157,6 +1182,9 @@ impl<'a, G: EmissionGuarantee> Diagnostic<'a, G> for WrongNumberOfGenericArgs<'_
err.code(E0107);
err.span(self.path_segment.ident.span);

if self.bad_derive(&mut err) {
return err;
}
self.notify(&mut err);
self.suggest(&mut err);
self.show_definition(&mut err);
Expand Down
2 changes: 2 additions & 0 deletions compiler/rustc_hir_analysis/src/hir_ty_lowering/generics.rs
Original file line number Diff line number Diff line change
Expand Up @@ -471,6 +471,7 @@ pub(crate) fn check_generic_arg_count(
has_self as usize,
gen_args,
def_id,
cx.item_def_id(),
));

Err(reported)
Expand Down Expand Up @@ -585,6 +586,7 @@ pub(crate) fn check_generic_arg_count(
params_offset,
gen_args,
def_id,
cx.item_def_id(),
))
.emit_unless_delay(all_params_are_binded)
});
Expand Down
10 changes: 10 additions & 0 deletions tests/run-make/derive-macro-unsupported-type-params/bar.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
#![no_std]
#![crate_type = "lib"]

#[macro_use]
extern crate foo;

#[derive(A)]
enum A<T> {
Variant(T),
}
26 changes: 26 additions & 0 deletions tests/run-make/derive-macro-unsupported-type-params/bar.stderr
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
error[E0425]: cannot find type `T` in this scope
--> bar.rs:9:13
|
9 | Variant(T),
| ^ not found in this scope

error[E0107]: missing generics for enum `A`
--> bar.rs:8:6
|
7 | #[derive(A)]
| - it looks like this derive macro might not support annotating items with type parameters
8 | enum A<T> {
| ^

error[E0107]: missing generics for enum `A`
--> bar.rs:8:6
|
7 | #[derive(A)]
| - it looks like this derive macro might not support annotating items with type parameters
8 | enum A<T> {
| ^

error: aborting due to 3 previous errors

Some errors have detailed explanations: E0107, E0425.
For more information about an error, try `rustc --explain E0107`.
37 changes: 37 additions & 0 deletions tests/run-make/derive-macro-unsupported-type-params/foo.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
#![crate_type = "proc-macro"]
#![feature(proc_macro_quote)]

extern crate proc_macro;

use proc_macro::{TokenStream, TokenTree, quote};

#[proc_macro_derive(A)]
pub fn derive(item: TokenStream) -> TokenStream {
let mut tokens = item.into_iter();
let _enum = tokens.next();
let name = tokens.next().unwrap();
let _ = tokens.next().unwrap();
let _ = tokens.next().unwrap();
let _ = tokens.next().unwrap();
let TokenTree::Group(group) = tokens.next().unwrap() else { panic!() };
let mut group = group.stream().into_iter();
let variant = group.next().unwrap();
let TokenTree::Group(args) = group.next().unwrap() else { panic!() };
let arg = args.stream().into_iter().next().unwrap();
let tokens = quote! {
trait X {}
#[automatically_derived]
impl X for $name {}

#[automatically_derived]
impl $name {
fn foo(&self) {
if let Self :: $variant(val) = self {
let _: $arg = val;
}
}
}

};
tokens
}
10 changes: 10 additions & 0 deletions tests/run-make/derive-macro-unsupported-type-params/rmake.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
//@ ignore-cross-compile
//@ needs-crate-type: proc-macro

use run_make_support::{diff, rustc, target};

fn main() {
rustc().input("foo.rs").edition("2024").run();
let out = rustc().input("bar.rs").edition("2024").run_fail().stderr_utf8();
diff().expected_file("bar.stderr").actual_text("actual-bar-stderr", out).run();
}
Loading