0

Files to regenerate the error

base_crate/Cargo.toml

[package]
name = "add-fields-to-struct"
version = "0.1.0"
edition = "2021"

# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html

[dependencies]
proc-macros = { path = "./proc-macros" }

base_crate/src/main.rs

fn main() {
    let mystruct = MyStruct {
        fieldaroo1: 37.,
        fieldaroo2: 42.,
    };
    println!("{}", mystruct.summity_sumaroo());
}

#[proc_macros::do_the_macro]
pub struct MyStruct {
    pub fieldaroo1: f64,
    pub fieldaroo2: f64,
}

impl MyStruct {
    fn summity_sumaroo(&self) -> f64 {
        self.fieldaroo1 + self.fieldaroo2
    }
}

base_crate/proc-macros/Cargo.toml

[package]
name = "proc-macros"
version = "0.1.0"
edition = "2021"

# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html

[dependencies]
proc-macro2 = "1.0.66"
syn = { version = "2.0.28", features = ["full"] }
proc-macro-error = "1.0.4"
quote = "1.0.18"
regex = "1.6.0"

[lib]
proc-macro = true

base_crate/proc-macros/src/lib.rs

pub(crate) use proc_macro::TokenStream;
pub(crate) use proc_macro2::TokenStream as TokenStream2;
pub(crate) use proc_macro_error::{abort, abort_call_site, emit_error, proc_macro_error};
pub(crate) use quote::{quote, ToTokens, TokenStreamExt}; // ToTokens is implicitly used as a trait
pub(crate) use regex::Regex;
pub(crate) use syn::{spanned::Spanned, DeriveInput, Field, FieldsNamed, Ident, Meta};

#[proc_macro_error]
#[proc_macro_attribute]
pub fn do_the_macro(_attr: TokenStream, item: TokenStream) -> TokenStream {
    // make a copy so there is something to return as things are built out
    let dummy_item = item.clone();

    let syn_named = TokenStream2::from(quote! {
        pub fieldaroo1: f64,
        pub fieldaroo2: f64,
    });

    let mut ast = syn::parse_macro_input!(item as syn::ItemStruct);
    if let syn::Fields::Named(FieldsNamed { named, .. }) = &mut ast.fields {
        // prints `reference: pub fieldaroo1 : f64, pub fieldaroo2 : f64,`
        println!("reference: {}", named.to_token_stream().to_string());

        // prints `test: pub fieldaroo1 : f64, pub fieldaroo2_electric_boogaloo : f64,`
        println!("test: {}", syn_named.to_token_stream().to_string());
        assert_eq!(syn_named.to_string(), named.to_token_stream().to_string());

        let parsed_named: TokenStream2 = syn::parse2(TokenStream2::from(named.to_token_stream()))
            .map_err(|e| {
                format!(
                    "[{}:{}] Parse 2 failed on named from macro input. {}",
                    file!(),
                    line!(),
                    e
                )
            })
            .unwrap();
    }

    let syn_named: FieldsNamed = syn::parse2(syn_named)
        .map_err(|e| format!("[{}:{}] `parse2` failed. {}", file!(), line!(), e))
        .unwrap();

    dummy_item
}

Output for cargo run

warning: unused imports: `abort_call_site`, `abort`, `emit_error`
 --> proc-macros/src/lib.rs:3:35
  |
3 | pub(crate) use proc_macro_error::{abort, abort_call_site, emit_error, proc_macro_error};
  |                                   ^^^^^  ^^^^^^^^^^^^^^^  ^^^^^^^^^^
  |
  = note: `#[warn(unused_imports)]` on by default

warning: unused import: `TokenStreamExt`
 --> proc-macros/src/lib.rs:4:41
  |
4 | pub(crate) use quote::{quote, ToTokens, TokenStreamExt}; // ToTokens is implicitly used as a trait
  |                                         ^^^^^^^^^^^^^^

warning: unused import: `regex::Regex`
 --> proc-macros/src/lib.rs:5:16
  |
5 | pub(crate) use regex::Regex;
  |                ^^^^^^^^^^^^

warning: unused imports: `DeriveInput`, `Field`, `Ident`, `Meta`, `spanned::Spanned`
 --> proc-macros/src/lib.rs:6:22
  |
6 | pub(crate) use syn::{spanned::Spanned, DeriveInput, Field, FieldsNamed, Ident, Meta};
  |                      ^^^^^^^^^^^^^^^^  ^^^^^^^^^^^  ^^^^^               ^^^^^  ^^^^

warning: unused variable: `parsed_named`
  --> proc-macros/src/lib.rs:28:13
   |
28 |         let parsed_named: TokenStream2 = syn::parse2(TokenStream2::from(named.to_token_stream()))
   |             ^^^^^^^^^^^^ help: if this is intentional, prefix it with an underscore: `_parsed_named`
   |
   = note: `#[warn(unused_variables)]` on by default

warning: unused variable: `syn_named`
  --> proc-macros/src/lib.rs:40:9
   |
40 |     let syn_named: FieldsNamed = syn::parse2(syn_named)
   |         ^^^^^^^^^ help: if this is intentional, prefix it with an underscore: `_syn_named`

warning: `proc-macros` (lib) generated 6 warnings (run `cargo fix --lib -p proc-macros` to apply 6 suggestions)
   Compiling add-fields-to-struct v0.1.0 (/Users/cbaker2/Documents/playground/rust/add-fields-to-struct)
reference: pub fieldaroo1 : f64, pub fieldaroo2 : f64,
test: pub fieldaroo1 : f64, pub fieldaroo2 : f64,
error: custom attribute panicked
 --> src/main.rs:9:1
  |
9 | #[proc_macros::do_the_macro]
  | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  |
  = help: message: called `Result::unwrap()` on an `Err` value: "[proc-macros/src/lib.rs:41] `parse2` failed. expected curly braces"

error[E0422]: cannot find struct, variant or union type `MyStruct` in this scope
 --> src/main.rs:2:20
  |
2 |     let mystruct = MyStruct {
  |                    ^^^^^^^^ not found in this scope

error[E0412]: cannot find type `MyStruct` in this scope
  --> src/main.rs:15:6
   |
15 | impl MyStruct {
   |      ^^^^^^^^ not found in this scope

Some errors have detailed explanations: E0412, E0422.
For more information about an error, try `rustc --explain E0412`.
error: could not compile `add-fields-to-struct` (bin "add-fields-to-struct") due to 3 previous errors

Expected outcome

This should be runnable code as best as I can tell. I'm trying to get past

= help: message: called `Result::unwrap()` on an `Err` value: "[proc-macros/src/lib.rs:41] `parse2` failed. expected curly braces"
Chad
  • 1,434
  • 1
  • 15
  • 30
  • 1
    Uhm no that should not be runnable a [`FileldsNamed` includes the `brace_token`](https://docs.rs/syn/latest/syn/struct.FieldsNamed.html) so just the `FieldsNamed::named` cannot be parsed into one. So in short you're missing a pair of `{}` in `quote!` – cafce25 Aug 14 '23 at 20:59
  • It would help if you would create a [mre] without a bunch of unused imports, that'd clean up the error message a **lot**. – cafce25 Aug 14 '23 at 21:15
  • As the other commentators said, there are quotes missing and there seems to be a lot of noise in the example code. And what's also not very clear: what are you trying to achieve? Because currently the code is just returning the input. (Well, failing to return because of the error.) – Hieron Aug 30 '23 at 16:31

0 Answers0