diff --git a/compiler/rustc_resolve/src/diagnostics/impls.rs b/compiler/rustc_resolve/src/diagnostics/impls.rs index 744e7c22265ea..06c2742c489be 100644 --- a/compiler/rustc_resolve/src/diagnostics/impls.rs +++ b/compiler/rustc_resolve/src/diagnostics/impls.rs @@ -2314,6 +2314,9 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { // | ^ return; } + if span.in_derive_expansion() { + return; + } let span = self.tcx.sess.source_map().guess_head_span(def_span); let candidate_descr = suggestion.res.descr(); let candidate = suggestion.candidate; diff --git a/compiler/rustc_resolve/src/late/diagnostics.rs b/compiler/rustc_resolve/src/late/diagnostics.rs index ddde9982c0cae..c3421a735ddae 100644 --- a/compiler/rustc_resolve/src/late/diagnostics.rs +++ b/compiler/rustc_resolve/src/late/diagnostics.rs @@ -713,6 +713,7 @@ impl<'ast, 'ra, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> { self.suggest_at_operator_in_slice_pat_with_range(&mut err, path); self.suggest_range_struct_destructuring(&mut err, path, source); self.suggest_swapping_misplaced_self_ty_and_trait(&mut err, source, res, base_error.span); + self.detect_resolution_error_in_derive(&mut err, base_error.span); if let Some((span, label)) = base_error.span_label { err.span_label(span, label); @@ -1904,6 +1905,26 @@ impl<'ast, 'ra, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> { } } + /// If the name resolution error occurs in an ident that has no span context, but the enclosing + /// item is within a derive macro, point at the derive, as the error can either be because of an + /// invalid derive macro *or* a non-existing item that will already have been reported through + /// the annotated item. + fn detect_resolution_error_in_derive(&self, err: &mut Diag<'_>, span: Span) { + if let Some(item) = self.diag_metadata.current_item + && !item.span.eq_ctxt(span) + && item.span.in_derive_expansion() + { + // `item` comes from a `#[derive()]`, but the error `span` doesn't, which means that the + // derive is referencing a name coming from the annotated item. If the item exists, then + // the derive macro itself is buggy. If the item exists, then an error will have already + // been emitted while evaluating the annotated item itself, but we can't silence this + // one because one *can* write a derive macro referencing a non-existing item that is + // part of the expansion, *not* from the user's code. Because of that, at least for now, + // we just add context to the current error. + err.span_label(item.span, "in this derive macro"); + } + } + fn explain_functions_in_pattern( &self, err: &mut Diag<'_>, @@ -3681,6 +3702,9 @@ impl<'ast, 'ra, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> { (Some(Item { kind: ItemKind::Fn(fn_), .. }), _, _) if fn_.ident.name == sym::main => { // Ignore `fn main()` as we don't want to suggest `fn main()` } + (Some(Item { span, .. }), _, _) if span.in_derive_expansion() => { + return (None, None); + } ( Some(Item { kind: diff --git a/tests/ui/derives/auxiliary/derive-no-generics.rs b/tests/ui/derives/auxiliary/derive-no-generics.rs index ea9a2e5b1c89a..affa9ac44d616 100644 --- a/tests/ui/derives/auxiliary/derive-no-generics.rs +++ b/tests/ui/derives/auxiliary/derive-no-generics.rs @@ -32,3 +32,53 @@ pub fn derive(item: TokenStream) -> TokenStream { }; tokens } + +#[proc_macro_derive(B)] +pub fn derive_2(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 {} + impl X for $name {} + + impl $name { + fn foo(&self) { + if let Self :: $variant(val) = self { + let _: T = val; + } + } + } + + }; + tokens +} + +#[proc_macro_derive(C)] +pub fn derive_3(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! { + fn foo(val: $name<$arg>) { + $name :: $variant($arg) = val; + } + }; + tokens +} diff --git a/tests/ui/derives/derive-macro-unsupported-type-params.rs b/tests/ui/derives/derive-macro-unsupported-type-params.rs index d80064b4eb094..0ee096b5ad734 100644 --- a/tests/ui/derives/derive-macro-unsupported-type-params.rs +++ b/tests/ui/derives/derive-macro-unsupported-type-params.rs @@ -11,3 +11,18 @@ enum A { Variant(T), //~^ ERROR: cannot find type `T` in this scope } + +// Resolution error comes entirely from within the derive macro: +#[derive(B)] //~ ERROR: cannot find type `T` in this scope +enum B { + //~^ ERROR: missing generics for enum `B` + //~| ERROR: missing generics for enum `B` + Variant(T), +} + +#[derive(C)] +enum C { + Variant(T), + //~^ ERROR: cannot find value `T` in this scope + //~| ERROR: cannot find type `T` in this scope +} diff --git a/tests/ui/derives/derive-macro-unsupported-type-params.stderr b/tests/ui/derives/derive-macro-unsupported-type-params.stderr index e57490e79cc9f..28f844f6d39ac 100644 --- a/tests/ui/derives/derive-macro-unsupported-type-params.stderr +++ b/tests/ui/derives/derive-macro-unsupported-type-params.stderr @@ -1,6 +1,46 @@ error[E0425]: cannot find type `T` in this scope --> $DIR/derive-macro-unsupported-type-params.rs:11:13 | +LL | #[derive(A)] + | - in this derive macro +... +LL | Variant(T), + | ^ not found in this scope + +error[E0425]: cannot find type `T` in this scope + --> $DIR/derive-macro-unsupported-type-params.rs:16:10 + | +LL | #[derive(B)] + | ^ not found in this scope + | + = note: this error originates in the derive macro `B` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0425]: cannot find type `T` in this scope + --> $DIR/derive-macro-unsupported-type-params.rs:25:13 + | +LL | #[derive(C)] + | - in this derive macro +LL | enum C { +LL | Variant(T), + | ^ not found in this scope + | +note: similarly named enum `A` defined here + --> $DIR/derive-macro-unsupported-type-params.rs:8:1 + | +LL | enum A { + | ^^^^^^^^^ +help: an enum with a similar name exists + | +LL - Variant(T), +LL + Variant(A), + | + +error[E0425]: cannot find value `T` in this scope + --> $DIR/derive-macro-unsupported-type-params.rs:25:13 + | +LL | #[derive(C)] + | - in this derive macro +LL | enum C { LL | Variant(T), | ^ not found in this scope @@ -22,7 +62,25 @@ LL | enum A { | = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` -error: aborting due to 3 previous errors +error[E0107]: missing generics for enum `B` + --> $DIR/derive-macro-unsupported-type-params.rs:17:6 + | +LL | #[derive(B)] + | - this derive macro might not support items with generic parameters +LL | enum B { + | ^ + +error[E0107]: missing generics for enum `B` + --> $DIR/derive-macro-unsupported-type-params.rs:17:6 + | +LL | #[derive(B)] + | - this derive macro might not support items with generic parameters +LL | enum B { + | ^ + | + = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` + +error: aborting due to 8 previous errors Some errors have detailed explanations: E0107, E0425. For more information about an error, try `rustc --explain E0107`. diff --git a/tests/ui/macros/tokenstream-ice-issue-149954.stderr b/tests/ui/macros/tokenstream-ice-issue-149954.stderr index b1a589e76c323..45377188bff9b 100644 --- a/tests/ui/macros/tokenstream-ice-issue-149954.stderr +++ b/tests/ui/macros/tokenstream-ice-issue-149954.stderr @@ -82,13 +82,14 @@ LL | A: A<{ struct A> ; enum A } error[E0404]: expected trait, found struct `A` --> $DIR/tokenstream-ice-issue-149954.rs:10:16 | +LL | #[derive(Debug)] + | ----- in this derive macro +... LL | A: A<{ struct A> ; enum A } | ________________^ ... | LL | | >; | |_________^ not a trait - | - = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` error[E0404]: expected trait, found type parameter `A` --> $DIR/tokenstream-ice-issue-149954.rs:10:32 diff --git a/tests/ui/pattern/usefulness/issue-119493-type-error-ice.stderr b/tests/ui/pattern/usefulness/issue-119493-type-error-ice.stderr index 06e13aa2ea01d..b9def607e0b46 100644 --- a/tests/ui/pattern/usefulness/issue-119493-type-error-ice.stderr +++ b/tests/ui/pattern/usefulness/issue-119493-type-error-ice.stderr @@ -7,13 +7,10 @@ LL | struct Foo(NonExistent); error[E0425]: cannot find type `NonExistent` in this scope --> $DIR/issue-119493-type-error-ice.rs:5:16 | +LL | #[derive(Copy, Clone)] + | ----- in this derive macro LL | struct Foo(NonExistent); | ^^^^^^^^^^^ not found in this scope - | -help: you might be missing a type parameter - | -LL | struct Foo(NonExistent); - | +++++++++++++ error[E0658]: `impl Trait` in type aliases is unstable --> $DIR/issue-119493-type-error-ice.rs:9:14 diff --git a/tests/ui/pattern/usefulness/issue-119778-type-error-ice.stderr b/tests/ui/pattern/usefulness/issue-119778-type-error-ice.stderr index 7da384d613efb..9bcf4a9ce8d42 100644 --- a/tests/ui/pattern/usefulness/issue-119778-type-error-ice.stderr +++ b/tests/ui/pattern/usefulness/issue-119778-type-error-ice.stderr @@ -12,13 +12,10 @@ LL | struct Foo([u8; S]); error[E0425]: cannot find value `S` in this scope --> $DIR/issue-119778-type-error-ice.rs:5:21 | +LL | #[derive(Copy, Clone)] + | ----- in this derive macro LL | struct Foo([u8; S]); | ^ not found in this scope - | -help: you might be missing a const parameter - | -LL | struct Foo([u8; S]); - | +++++++++++++++++++++ error[E0658]: `impl Trait` in type aliases is unstable --> $DIR/issue-119778-type-error-ice.rs:9:14 diff --git a/tests/ui/traits/issue-50480.stderr b/tests/ui/traits/issue-50480.stderr index e7a93dc52579e..a8b6ff4d0d924 100644 --- a/tests/ui/traits/issue-50480.stderr +++ b/tests/ui/traits/issue-50480.stderr @@ -18,24 +18,18 @@ LL | struct Foo(N, NotDefined, ::Item, Vec, String); error[E0425]: cannot find type `N` in this scope --> $DIR/issue-50480.rs:2:12 | +LL | #[derive(Clone, Copy)] + | ----- in this derive macro LL | struct Foo(N, NotDefined, ::Item, Vec, String); | ^ not found in this scope - | -help: you might be missing a type parameter - | -LL | struct Foo(N, NotDefined, ::Item, Vec, String); - | +++ error[E0425]: cannot find type `NotDefined` in this scope --> $DIR/issue-50480.rs:2:15 | +LL | #[derive(Clone, Copy)] + | ----- in this derive macro LL | struct Foo(N, NotDefined, ::Item, Vec, String); | ^^^^^^^^^^ not found in this scope - | -help: you might be missing a type parameter - | -LL | struct Foo(N, NotDefined, ::Item, Vec, String); - | ++++++++++++ error[E0425]: cannot find type `N` in this scope --> $DIR/issue-50480.rs:12:18