$crate incorrectly substituted in attribute macro invocation containing bang macro invocation · Issue #62325 · rust-lang/rust (original) (raw)
When an attribute macro input contains $ident
, it is correctly substituted both inside and outside of a function-like macro invocation i.e. both of the ident′sin‘[u8;ident's in [u8; </annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:1.0019em;vertical-align:-0.25em;"></span><span class="mord mathnormal">i</span><span class="mord mathnormal">d</span><span class="mord mathnormal">e</span><span class="mord mathnormal">n</span><span class="mord"><span class="mord mathnormal">t</span><span class="msupsub"><span class="vlist-t"><span class="vlist-r"><span class="vlist" style="height:0.7519em;"><span style="top:-3.063em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mtight">′</span></span></span></span></span></span></span></span></span><span class="mord mathnormal">s</span><span class="mord mathnormal">in</span><span class="mord">‘</span><span class="mopen">[</span><span class="mord mathnormal">u</span><span class="mord">8</span><span class="mpunct">;</span></span></span></span>ident + m!($ident)]
would be substituted as expected.
But when an attribute macro input contains $crate
, it is only substituted outside of a function-like macro. Inside, it incorrectly disintegrates into Punct('$'), Ident(crate)
when the whole bang macro invocation is passed to an attribute macro (or derive macro). In the case of [u8; <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>c</mi><mi>r</mi><mi>a</mi><mi>t</mi><mi>e</mi><mo>:</mo><mo>:</mo><mi>N</mi><mo>+</mo><mi>m</mi><mo stretchy="false">!</mo><mo stretchy="false">(</mo></mrow><annotation encoding="application/x-tex">crate::N + m!(</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.6151em;"></span><span class="mord mathnormal" style="margin-right:0.02778em;">cr</span><span class="mord mathnormal">a</span><span class="mord mathnormal">t</span><span class="mord mathnormal">e</span><span class="mspace" style="margin-right:0.2778em;"></span><span class="mrel">::</span><span class="mspace" style="margin-right:0.2778em;"></span></span><span class="base"><span class="strut" style="height:0.7667em;vertical-align:-0.0833em;"></span><span class="mord mathnormal" style="margin-right:0.10903em;">N</span><span class="mspace" style="margin-right:0.2222em;"></span><span class="mbin">+</span><span class="mspace" style="margin-right:0.2222em;"></span></span><span class="base"><span class="strut" style="height:1em;vertical-align:-0.25em;"></span><span class="mord mathnormal">m</span><span class="mclose">!</span><span class="mopen">(</span></span></span></span>crate::N)]
the first $crate would be handled correctly but the second one would be passed incorrectly as two tokens. See where I put // WRONG
in the output below.
TokenStream [ Ident { ident: "type", span: #0 bytes(0..0), }, Ident { ident: "T", span: #0 bytes(0..0), }, Punct { ch: '=', spacing: Alone, span: #0 bytes(0..0), }, Group { delimiter: Bracket, stream: TokenStream [ Ident { ident: "crate", span: #0 bytes(0..0), }, Punct { ch: ':', spacing: Joint, span: #0 bytes(0..0), }, Punct { ch: ':', spacing: Alone, span: #0 bytes(0..0), }, Ident { ident: "N", span: #0 bytes(0..0), }, Punct { ch: ';', spacing: Alone, span: #0 bytes(0..0), }, Ident { ident: "x", span: #0 bytes(0..0), }, Punct { ch: '!', spacing: Alone, span: #0 bytes(0..0), }, Group { delimiter: Parenthesis, stream: TokenStream [ Punct { // WRONG ch: '$', spacing: Alone, span: #0 bytes(0..0), }, Ident { ident: "crate", span: #0 bytes(0..0), }, Punct { ch: ':', spacing: Joint, span: #0 bytes(0..0), }, Punct { ch: ':', spacing: Alone, span: #0 bytes(0..0), }, Ident { ident: "N", span: #0 bytes(0..0), }, ], span: #0 bytes(0..0), }, ], span: #0 bytes(0..0), }, Punct { ch: ';', spacing: Alone, span: #0 bytes(0..0), }, ]