Strange proc_macro bug: process did not exit currectly

I am writing a proc_macro for the first time, so I have more or less no idea how to track down where the problem is. The code is here and I am running cargo expand on the following code:

use exec_rule::rule;

#[rule(
    body = "writeLine('stdout', '*greeting1, *greeting2')",
    output = "ExecRuleOut"
)]
#[derive(Debug)]
pub struct VeryAdvancedHelloWorldRule {
    pub greeting1: String,
    pub greeting2: String,
}

fn main() {
    println!("Hello, world!");
}

Specifically, anytime this function is called, I get an error, as I verified with the print statements. The error is:

process didn't exit successfully: `/home/phillipdavis/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/bin/rustc --crate-name exec_rule_test --edition=2021 src/main.rs --error-format=json --json=diagnostic-rendered-ansi,artifacts,future-incompat --crate-type bin --emit=dep-info,metadata -C embed-bitcode=no -C debuginfo=2 -o /tmp/cargo-expand5Tf5OA/expanded -Zunpretty=expanded -C metadata=1a3cbdbde4116e72 -C extra-filename=-1a3cbdbde4116e72 --out-dir /home/phillipdavis/everyday/dev/rust/grad-proj-gen2/exec_rule_test/target/debug/deps -C incremental=/home/phillipdavis/everyday/dev/rust/grad-proj-gen2/exec_rule_test/target/debug/incremental -L dependency=/home/phillipdavis/everyday/dev/rust/grad-proj-gen2/exec_rule_test/target/debug/deps --extern exec_rule=/home/phillipdavis/everyday/dev/rust/grad-proj-gen2/exec_rule_test/target/debug/deps/libexec_rule-f04a5094cb5df7da.so --extern packe=/home/phillipdavis/everyday/dev/rust/grad-proj-gen2/exec_rule_test/target/debug/deps/libpacke-c0ea201bf258b335.rmeta --extern quick_xml=/home/phillipdavis/everyday/dev/rust/grad-proj-gen2/exec_rule_test/target/debug/deps/libquick_xml-2bc72ae7669b55ba.rmeta --extern rods_prot_msg=/home/phillipdavis/everyday/dev/rust/grad-proj-gen2/exec_rule_test/target/debug/deps/librods_prot_msg-47aeba0a4cfdc4ff.rmeta --extern tokio=/home/phillipdavis/everyday/dev/rust/grad-proj-gen2/exec_rule_test/target/debug/deps/libtokio-0f616be995a16e4d.rmeta` (signal: 11, SIGSEGV: invalid memory reference)

When I first encountered this error, I got an error saying that the stack and blown and stating explicitly that it was a bug, but my something about my debugging efforts made that message disappear and I can't seem to make it return, although I didn't change much substantial about the code. The print statement makes it clear that somehow expand_serialization_impl is being called repeatedly, despite only ever being called once. Additionally, the error only started when I refactored that function to return a result.

Sorry for the vagueness, but I'm genuinely stumped.

The recursion happens here in rule.span(): exec_rule_macro/src/serialize.rs at 374d83a5fb94add5b962f415e62bbcb67d79916d · phdavis1027/exec_rule_macro (github.com)

The reason this is a recursive call is due to the implementation of Spanned for T where T: ToTokens. It forwards to the quote::spanned module which calls into_token_stream(). That reenters your ToTokens impl.


I found this by removing the impl ToTokens for Rule and replacing it with a manual impl. Doing so gives the following error:

error[E0599]: the method `span` exists for reference `&Rule`, but its trait bounds were not satisfied
  --> src\serialize.rs:57:71
   |
57 |     let params_len = write_tag_fmt("paramLen", LitStr::new("{}", rule.span()), params.len());
   |                                                                       ^^^^ method cannot be called on `&Rule` due to unsatisfied trait bounds
   |
  ::: src\rule.rs:9:1
   |
9  | pub(crate) struct Rule {
   | ---------------------- doesn't satisfy `Rule: quote::spanned::Spanned` or `Rule: syn::spanned::Spanned`
   |
   = note: the following trait bounds were not satisfied:
           `Rule: quote::spanned::Spanned`
           which is required by `Rule: syn::spanned::Spanned`
           `&Rule: quote::spanned::Spanned`
           which is required by `&Rule: syn::spanned::Spanned`
note: the trait `quote::spanned::Spanned` must be implemented
  --> C:\Users\jay\.cargo\registry\src\index.crates.io-6f17d22bba15001f\quote-1.0.36\src\spanned.rs:6:1
   |
6  | pub trait Spanned: private::Sealed {
   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
   = help: items from traits can only be used if the trait is implemented and in scope
   = note: the following traits define an item `span`, perhaps you need to implement one of them:
           candidate #1: `IdentFragment`
           candidate #2: `syn::spanned::Spanned`

You need to provide a different span to fix the infinite recursion. Span::call_site() is what I would start with.

Thank you! That's quite hairy. You're my personal hero.

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.