-
-
Notifications
You must be signed in to change notification settings - Fork 14.1k
Open
Labels
A-diagnosticsArea: Messages for errors, warnings, and lintsArea: Messages for errors, warnings, and lintsT-compilerRelevant to the compiler team, which will review and decide on the PR/issue.Relevant to the compiler team, which will review and decide on the PR/issue.
Description
Code
#[proc_macro_derive(MyFrom)]
pub fn my_derive(input: TokenStream) -> TokenStream {
let derived_input = parse_macro_input!(input as DeriveInput);
let ident = &derived_input.ident;
if let Data::Struct(data) = derived_input.data {
match data.fields {
Fields::Named(fields) => {
if fields.named.len() != 1 {
return syn::Error::new(fields.span(), "#[derive(MyFrom)] cannot be implemented on anything other than a struct with one field").to_compile_error().into();
}
let field = fields.named.first().unwrap();
let name = field.ident.as_ref().unwrap();
let field_type = field.ty.clone();
if derived_input.generics.params.is_empty() {
quote! {
impl From<#field_type> for #ident {
fn from(value: #field_type) -> Self {
Self {
#name: value
}
}
}
}.into()
} else {
let generics = derived_input.generics.params;
if let Some(where_clause) = derived_input.generics.where_clause {
quote! {
impl<#generics> From<#field_type> for #ident<#generics> #where_clause {
fn from(value: #field_type) -> Self {
Self {
#name: value
}
}
}
}.into()
} else {
quote! {
impl<#generics> From<#field_type> for #ident<#generics> {
fn from(value: #field_type) -> Self {
Self {
#name: value
}
}
}
}.into()
}
}
},
Fields::Unnamed(fields) => {
if fields.unnamed.len() != 1 {
return syn::Error::new(fields.span(), "#[derive(MyFrom)] cannot be implemented on anything other than a struct with one field").to_compile_error().into();
}
let field = fields.unnamed.first().unwrap();
let field_type = field.ty.clone();
if derived_input.generics.params.is_empty() {
quote! {
impl From<#field_type> for #ident {
fn from(value: #field_type) -> Self {
Self(value)
}
}
}.into()
} else {
let generics = derived_input.generics.params;
if let Some(where_clause) = derived_input.generics.where_clause {
quote! {
impl<#generics> From<#field_type> for #ident<#generics> #where_clause {
fn from(value: #field_type) -> Self {
Self(value)
}
}
}.into()
} else {
quote! {
impl<#generics> From<#field_type> for #ident<#generics> {
fn from(value: #field_type) -> Self {
Self(value)
}
}
}.into()
}
}
},
Fields::Unit => {
syn::Error::new(ident.span(), "#[derive(MyFrom)] cannot be implemented on anything other than a struct with one field").to_compile_error().into()
}
}
} else {
syn::Error::new(ident.span(), "#[derive(MyFrom)] cannot be implemented on anything other than a struct with one field").to_compile_error().into()
}
}
and
#[derive(MyFrom)]
struct MyTupleGeneric<T> {
name: T
}Current output
error[E0107]: missing generics for struct `MyTupleGeneric`
--> derive_from\tests\from_works.rs:12:8
|
12 | struct MyTupleGeneric<T> {
| ^^^^^^^^^^^^^^ expected 1 generic argument
|
note: struct defined here, with 1 generic parameter: `T`
--> derive_from\tests\from_works.rs:12:8
|
12 | struct MyTupleGeneric<T> {
| ^^^^^^^^^^^^^^ -
help: add missing generic argument
|
12 | struct MyTupleGeneric<T><T> {Desired output
error[E0107]: missing generics for struct `MyTupleGeneric`
--> derive_from\tests\from_works.rs:12:8
|
12 | struct MyTupleGeneric<T> {
| ^^^^^^^^^^^^^^ expected 1 generic argument
|
note: struct defined here, with 1 generic parameter: `T`
--> derive_from\tests\from_works.rs:12:8
|
12 | struct MyTupleGeneric<T> {
| ^^^^^^^^^^^^^^ -
help: add missing generic parameter to trait impl
|
| impl Tr
|Rationale and extra context
In proc_macros, when a generic argument is missing, the code errors and erroneously suggests that the user of the macro is responsible.
I believe this must be changed to ensure that the proc_macro itself is shown to be in error.
Other cases
Rust Version
rustc 1.92.0 (ded5c06cf 2025-12-08)
binary: rustc
commit-hash: ded5c06cf21d2b93bffd5d884aa6e96934ee4234
commit-date: 2025-12-08
host: x86_64-pc-windows-msvc
release: 1.92.0
LLVM version: 21.1.3Anything else?
I wish that this code doesn't produce the erroneous output but rather a complete explanation of where the code errors.
Metadata
Metadata
Assignees
Labels
A-diagnosticsArea: Messages for errors, warnings, and lintsArea: Messages for errors, warnings, and lintsT-compilerRelevant to the compiler team, which will review and decide on the PR/issue.Relevant to the compiler team, which will review and decide on the PR/issue.