diff --git a/compiler/rustc_hir_analysis/src/diagnostics/wrong_number_of_generic_args.rs b/compiler/rustc_hir_analysis/src/diagnostics/wrong_number_of_generic_args.rs index c80c63b7c0188..e66e4fb566701 100644 --- a/compiler/rustc_hir_analysis/src/diagnostics/wrong_number_of_generic_args.rs +++ b/compiler/rustc_hir_analysis/src/diagnostics/wrong_number_of_generic_args.rs @@ -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. @@ -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 @@ -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> { @@ -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 } @@ -110,6 +115,7 @@ impl<'a, 'tcx> WrongNumberOfGenericArgs<'a, 'tcx> { params_offset, gen_args, def_id, + cx_def_id, } } @@ -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", + ); + + 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(); @@ -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); diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/generics.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/generics.rs index 45c2ed205c74d..1b27c4a9509fc 100644 --- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/generics.rs +++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/generics.rs @@ -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) @@ -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) }); diff --git a/tests/run-make/derive-macro-unsupported-type-params/bar.rs b/tests/run-make/derive-macro-unsupported-type-params/bar.rs new file mode 100644 index 0000000000000..bcf9dc0d7d2f8 --- /dev/null +++ b/tests/run-make/derive-macro-unsupported-type-params/bar.rs @@ -0,0 +1,10 @@ +#![no_std] +#![crate_type = "lib"] + +#[macro_use] +extern crate foo; + +#[derive(A)] +enum A { + Variant(T), +} diff --git a/tests/run-make/derive-macro-unsupported-type-params/bar.stderr b/tests/run-make/derive-macro-unsupported-type-params/bar.stderr new file mode 100644 index 0000000000000..6b391f860dd7d --- /dev/null +++ b/tests/run-make/derive-macro-unsupported-type-params/bar.stderr @@ -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 { + | ^ + +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 { + | ^ + +error: aborting due to 3 previous errors + +Some errors have detailed explanations: E0107, E0425. +For more information about an error, try `rustc --explain E0107`. diff --git a/tests/run-make/derive-macro-unsupported-type-params/foo.rs b/tests/run-make/derive-macro-unsupported-type-params/foo.rs new file mode 100644 index 0000000000000..5ce42a8023608 --- /dev/null +++ b/tests/run-make/derive-macro-unsupported-type-params/foo.rs @@ -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 +} diff --git a/tests/run-make/derive-macro-unsupported-type-params/rmake.rs b/tests/run-make/derive-macro-unsupported-type-params/rmake.rs new file mode 100644 index 0000000000000..b0bba4eab796f --- /dev/null +++ b/tests/run-make/derive-macro-unsupported-type-params/rmake.rs @@ -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(); +}