Rust-GCC / Rust-GCC/gccrs

Store macro matchers properly

Open
#945 0 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

enhancement
Dominant language
C++
Stars
2.9k
Forks
231
Avg merge
19h 55m
Merged PRs (30d)
67

Description

When forwarding a matched fragment to another macro-by-example, matchers in the second macro will see an opaque AST of the fragment type. The second macro can't use literal tokens to match the fragments in the matcher, only a fragment specifier of the same type. The ident, lifetime, and tt fragment types are an exception, and can be matched by literal tokens. The following illustrates this restriction

macro_rules! foo {
    ($l:expr) => { bar!($l); }
// ERROR:               ^^ no rules expected this token in macro call
}

macro_rules! bar {
    (3) => {}
}

foo!(3);

The following illustrates how tokens can be directly matched after matching a tt fragment:

// compiles OK
macro_rules! foo {
    ($l:tt) => { bar!($l); }
}

macro_rules! bar {
    (3) => {}
}

foo!(3);

From https://doc.rust-lang.org/reference/macros-by-example.html

  • We need to be able to store the macro matcher properly, either as an opaque Expr or equivalent or as a specific case
  • We need to be able to match recursively on ident, lifetime and tt fragments
Small resolver stress test
macro_rules! foo0 {
    ($a:tt) => {
        foo1!($a)
    }
}
macro_rules! foo1 {
    ($a:tt) => {
        foo2!($a)
    }
}
macro_rules! foo2 {
    ($a:tt) => {
        foo3!($a)
    }
}
macro_rules! foo3 {
    ($a:tt) => {
        foo4!($a)
    }
}
macro_rules! foo4 {
    ($a:tt) => {
        foo5!($a)
    }
}
macro_rules! foo5 {
    ($a:tt) => {
        foo6!($a)
    }
}
macro_rules! foo6 {
    ($a:tt) => {
        foo7!($a)
    }
}
macro_rules! foo7 {
    ($a:tt) => {
        foo8!($a)
    }
}
macro_rules! foo8 {
    ($a:tt) => {
        foo9!($a)
    }
}
macro_rules! foo9 {
    ($a:tt) => {
        foo10!($a)
    }
}
macro_rules! foo10 {
    ($a:tt) => {
        foo11!($a)
    }
}
macro_rules! foo11 {
    ($a:tt) => {
        foo12!($a)
    }
}
macro_rules! foo12 {
    ($a:tt) => {
        foo13!($a)
    }
}
macro_rules! foo13 {
    ($a:tt) => {
        foo14!($a)
    }
}
macro_rules! foo14 {
    ($a:tt) => {
        foo15!($a)
    }
}
macro_rules! foo15 {
    ($a:tt) => {
        foo16!($a)
    }
}
macro_rules! foo16 {
    ($a:tt) => {
        foo17!($a)
    }
}
macro_rules! foo17 {
    ($a:tt) => {
        foo18!($a)
    }
}
macro_rules! foo18 {
    ($a:tt) => {
        foo19!($a)
    }
}
macro_rules! foo19 {
    ($a:tt) => {
        foo20!($a)
    }
}
macro_rules! foo20 {
    ($a:tt) => {
        foo21!($a)
    }
}
macro_rules! foo21 {
    ($a:tt) => {
        foo22!($a)
    }
}
macro_rules! foo22 {
    ($a:tt) => {
        foo23!($a)
    }
}
macro_rules! foo23 {
    ($a:tt) => {
        foo24!($a)
    }
}
macro_rules! foo24 {
    ($a:tt) => {
        foo25!($a)
    }
}
macro_rules! foo25 {
    ($a:tt) => {
        foo26!($a)
    }
}
macro_rules! foo26 {
    ($a:tt) => {
        foo27!($a)
    }
}
macro_rules! foo27 {
    ($a:tt) => {
        foo28!($a)
    }
}
macro_rules! foo28 {
    ($a:tt) => {
        foo29!($a)
    }
}
macro_rules! foo29 {
    ($a:tt) => {
        foo30!($a)
    }
}
macro_rules! foo30 {
    ($a:tt) => {
        foo31!($a)
    }
}
macro_rules! foo31 {
    ($a:tt) => {
        foo32!($a)
    }
}
macro_rules! foo32 {
    ($a:tt) => {
        foo33!($a)
    }
}
macro_rules! foo33 {
    ($a:tt) => {
        foo34!($a)
    }
}
macro_rules! foo34 {
    ($a:tt) => {
        foo35!($a)
    }
}
macro_rules! foo35 {
    ($a:tt) => {
        foo36!($a)
    }
}
macro_rules! foo36 {
    ($a:tt) => {
        foo37!($a)
    }
}
macro_rules! foo37 {
    ($a:tt) => {
        foo38!($a)
    }
}
macro_rules! foo38 {
    ($a:tt) => {
        foo39!($a)
    }
}
macro_rules! foo39 {
    ($a:tt) => {
        foo40!($a)
    }
}
macro_rules! foo40 {
    ($a:tt) => {
        foo41!($a)
    }
}
macro_rules! foo41 {
    ($a:tt) => {
        foo42!($a)
    }
}
macro_rules! foo42 {
    ($a:tt) => {
        foo43!($a)
    }
}
macro_rules! foo43 {
    ($a:tt) => {
        foo44!($a)
    }
}
macro_rules! foo44 {
    ($a:tt) => {
        foo45!($a)
    }
}
macro_rules! foo45 {
    ($a:tt) => {
        foo46!($a)
    }
}
macro_rules! foo46 {
    ($a:tt) => {
        foo47!($a)
    }
}
macro_rules! foo47 {
    ($a:tt) => {
        foo48!($a)
    }
}
macro_rules! foo48 {
    ($a:tt) => {
        foo49!($a)
    }
}
macro_rules! foo49 {
    ($a:tt) => {
        foo50!($a)
    }
}
macro_rules! foo50 {
    ($a:tt) => {
        foo51!($a)
    }
}
macro_rules! foo51 {
    ($a:tt) => {
        foo52!($a)
    }
}
macro_rules! foo52 {
    ($a:tt) => {
        foo53!($a)
    }
}
macro_rules! foo53 {
    ($a:tt) => {
        foo54!($a)
    }
}
macro_rules! foo54 {
    ($a:tt) => {
        foo55!($a)
    }
}
macro_rules! foo55 {
    ($a:tt) => {
        foo56!($a)
    }
}
macro_rules! foo56 {
    ($a:tt) => {
        foo57!($a)
    }
}
macro_rules! foo57 {
    ($a:tt) => {
        foo58!($a)
    }
}
macro_rules! foo58 {
    ($a:tt) => {
        foo59!($a)
    }
}
macro_rules! foo59 {
    ($a:tt) => {
        foo60!($a)
    }
}
macro_rules! foo60 {
    ($a:tt) => {
        foo61!($a)
    }
}
macro_rules! foo61 {
    ($a:tt) => {
        foo62!($a)
    }
}
macro_rules! foo62 {
    ($a:tt) => {
        foo63!($a)
    }
}
macro_rules! foo63 {
    ($a:tt) => {
        foo64!($a)
    }
}
macro_rules! foo64 {
    ($a:tt) => {
        foo65!($a)
    }
}
macro_rules! foo65 {
    ($a:tt) => {
        foo66!($a)
    }
}
macro_rules! foo66 {
    ($a:tt) => {
        foo67!($a)
    }
}
macro_rules! foo67 {
    ($a:tt) => {
        foo68!($a)
    }
}
macro_rules! foo68 {
    ($a:tt) => {
        foo69!($a)
    }
}
macro_rules! foo69 {
    ($a:tt) => {
        foo70!($a)
    }
}
macro_rules! foo70 {
    ($a:tt) => {
        foo71!($a)
    }
}
macro_rules! foo71 {
    ($a:tt) => {
        foo72!($a)
    }
}
macro_rules! foo72 {
    ($a:tt) => {
        foo73!($a)
    }
}
macro_rules! foo73 {
    ($a:tt) => {
        foo74!($a)
    }
}
macro_rules! foo74 {
    ($a:tt) => {
        foo75!($a)
    }
}
macro_rules! foo75 {
    ($a:tt) => {
        foo76!($a)
    }
}
macro_rules! foo76 {
    ($a:tt) => {
        foo77!($a)
    }
}
macro_rules! foo77 {
    ($a:tt) => {
        foo78!($a)
    }
}
macro_rules! foo78 {
    ($a:tt) => {
        foo79!($a)
    }
}
macro_rules! foo79 {
    ($a:tt) => {
        foo80!($a)
    }
}
macro_rules! foo80 {
    ($a:tt) => {
        foo81!($a)
    }
}
macro_rules! foo81 {
    ($a:tt) => {
        foo82!($a)
    }
}
macro_rules! foo82 {
    ($a:tt) => {
        foo83!($a)
    }
}
macro_rules! foo83 {
    ($a:tt) => {
        foo84!($a)
    }
}
macro_rules! foo84 {
    ($a:tt) => {
        foo85!($a)
    }
}
macro_rules! foo85 {
    ($a:tt) => {
        foo86!($a)
    }
}
macro_rules! foo86 {
    ($a:tt) => {
        foo87!($a)
    }
}
macro_rules! foo87 {
    ($a:tt) => {
        foo88!($a)
    }
}
macro_rules! foo88 {
    ($a:tt) => {
        foo89!($a)
    }
}
macro_rules! foo89 {
    ($a:tt) => {
        last!($a)
    }
}

macro_rules! last {
    (3) => {
        println!("fizz")
    };
    (5) => {
        println!("buzz")
    };
    ($any:tt) => {
        println!(" :) ")
    }
}

fn main() {
    foo0!(3);
    foo0!(5);
    foo0!(6);
}

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Use the macro_rules examples and the 90-level resolver stress test in this issue as reproductions. Start by tracing gccrs's macro matcher storage and recursive matching paths, comparing expr with tt behavior and the ident, lifetime, and tt exceptions. Done when forwarded fragments support the described literal matches and the stress test preserves the 3, 5, and 6 cases.

Written by the indexing model from the issue text.

Assessment

Tech stack
cpp, rust
Domain
compilers
Issue type
Bug
Difficulty
5/5
Estimated time
Over a week
Activity status
Stale
Clarity
Mostly clear
Newbie friendliness
25/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.