Why can I not pass a captured token to a nested macro?
.everyoneloves__top-leaderboard:empty,.everyoneloves__mid-leaderboard:empty,.everyoneloves__bot-mid-leaderboard:empty{ height:90px;width:728px;box-sizing:border-box;
}
Multiple examples I've seen suggest that this should be possible, but it is apparently not:
lib.rs
:
#![feature(trace_macros)]
#[macro_export]
macro_rules! inner_macro (
(f32) => {"float"};
);
#[macro_export]
macro_rules! outer_macro {
($T:ty) => {
inner_macro!($T)
}
}
#[cfg(test)]
mod tests {
#[test]
fn test_nested() {
trace_macros!(true);
s1: String = String::from(outer_macro!(f32));
s2: String = String::from(inner_macro!(f32));
trace_macros!(false);
}
}
Running cargo test
gives the following output:
error: no rules expected the token `f32`
--> src/lib.rs:11:22
|
4 | / macro_rules! inner_macro (
5 | | (f32) => {"float"};
6 | | );
| |__- when calling this macro
...
11 | inner_macro!($T)
| ^^ no rules expected the token `f32`
...
21 | s1: String = String::from(outer_macro!(f32));
| ----------------- in this macro invocation
This is confusing, because there certainly appears to be a rule expecting the token f32
.
There are also notes from the expansion trace of the two macros. The first one does not work:
= note: expanding `outer_macro! { f32 }`
= note: to `inner_macro ! ( f32 )`
= note: expanding `inner_macro! { f32 }`
while the second one does:
= note: expanding `inner_macro! { f32 }`
= note: to `"float"`
Why does the first expansion of inner_macro!
fail, while the exact same expansion succeeds when it is not nested inside another macro?
Edit: if we perform the substitution manually, it works and gives the expected output:
macro_rules! unknown {
($T:ty) => {
inner_macro!(f32)
}
}
rust rust-macros
add a comment |
Multiple examples I've seen suggest that this should be possible, but it is apparently not:
lib.rs
:
#![feature(trace_macros)]
#[macro_export]
macro_rules! inner_macro (
(f32) => {"float"};
);
#[macro_export]
macro_rules! outer_macro {
($T:ty) => {
inner_macro!($T)
}
}
#[cfg(test)]
mod tests {
#[test]
fn test_nested() {
trace_macros!(true);
s1: String = String::from(outer_macro!(f32));
s2: String = String::from(inner_macro!(f32));
trace_macros!(false);
}
}
Running cargo test
gives the following output:
error: no rules expected the token `f32`
--> src/lib.rs:11:22
|
4 | / macro_rules! inner_macro (
5 | | (f32) => {"float"};
6 | | );
| |__- when calling this macro
...
11 | inner_macro!($T)
| ^^ no rules expected the token `f32`
...
21 | s1: String = String::from(outer_macro!(f32));
| ----------------- in this macro invocation
This is confusing, because there certainly appears to be a rule expecting the token f32
.
There are also notes from the expansion trace of the two macros. The first one does not work:
= note: expanding `outer_macro! { f32 }`
= note: to `inner_macro ! ( f32 )`
= note: expanding `inner_macro! { f32 }`
while the second one does:
= note: expanding `inner_macro! { f32 }`
= note: to `"float"`
Why does the first expansion of inner_macro!
fail, while the exact same expansion succeeds when it is not nested inside another macro?
Edit: if we perform the substitution manually, it works and gives the expected output:
macro_rules! unknown {
($T:ty) => {
inner_macro!(f32)
}
}
rust rust-macros
add a comment |
Multiple examples I've seen suggest that this should be possible, but it is apparently not:
lib.rs
:
#![feature(trace_macros)]
#[macro_export]
macro_rules! inner_macro (
(f32) => {"float"};
);
#[macro_export]
macro_rules! outer_macro {
($T:ty) => {
inner_macro!($T)
}
}
#[cfg(test)]
mod tests {
#[test]
fn test_nested() {
trace_macros!(true);
s1: String = String::from(outer_macro!(f32));
s2: String = String::from(inner_macro!(f32));
trace_macros!(false);
}
}
Running cargo test
gives the following output:
error: no rules expected the token `f32`
--> src/lib.rs:11:22
|
4 | / macro_rules! inner_macro (
5 | | (f32) => {"float"};
6 | | );
| |__- when calling this macro
...
11 | inner_macro!($T)
| ^^ no rules expected the token `f32`
...
21 | s1: String = String::from(outer_macro!(f32));
| ----------------- in this macro invocation
This is confusing, because there certainly appears to be a rule expecting the token f32
.
There are also notes from the expansion trace of the two macros. The first one does not work:
= note: expanding `outer_macro! { f32 }`
= note: to `inner_macro ! ( f32 )`
= note: expanding `inner_macro! { f32 }`
while the second one does:
= note: expanding `inner_macro! { f32 }`
= note: to `"float"`
Why does the first expansion of inner_macro!
fail, while the exact same expansion succeeds when it is not nested inside another macro?
Edit: if we perform the substitution manually, it works and gives the expected output:
macro_rules! unknown {
($T:ty) => {
inner_macro!(f32)
}
}
rust rust-macros
Multiple examples I've seen suggest that this should be possible, but it is apparently not:
lib.rs
:
#![feature(trace_macros)]
#[macro_export]
macro_rules! inner_macro (
(f32) => {"float"};
);
#[macro_export]
macro_rules! outer_macro {
($T:ty) => {
inner_macro!($T)
}
}
#[cfg(test)]
mod tests {
#[test]
fn test_nested() {
trace_macros!(true);
s1: String = String::from(outer_macro!(f32));
s2: String = String::from(inner_macro!(f32));
trace_macros!(false);
}
}
Running cargo test
gives the following output:
error: no rules expected the token `f32`
--> src/lib.rs:11:22
|
4 | / macro_rules! inner_macro (
5 | | (f32) => {"float"};
6 | | );
| |__- when calling this macro
...
11 | inner_macro!($T)
| ^^ no rules expected the token `f32`
...
21 | s1: String = String::from(outer_macro!(f32));
| ----------------- in this macro invocation
This is confusing, because there certainly appears to be a rule expecting the token f32
.
There are also notes from the expansion trace of the two macros. The first one does not work:
= note: expanding `outer_macro! { f32 }`
= note: to `inner_macro ! ( f32 )`
= note: expanding `inner_macro! { f32 }`
while the second one does:
= note: expanding `inner_macro! { f32 }`
= note: to `"float"`
Why does the first expansion of inner_macro!
fail, while the exact same expansion succeeds when it is not nested inside another macro?
Edit: if we perform the substitution manually, it works and gives the expected output:
macro_rules! unknown {
($T:ty) => {
inner_macro!(f32)
}
}
rust rust-macros
rust rust-macros
asked Nov 23 '18 at 16:15
CardanoCardano
414413
414413
add a comment |
add a comment |
1 Answer
1
active
oldest
votes
After some more reading, it turns out this is an instance of a typical stumbling block. After being captured the first time, $T
takes the value of an AST Node. Substituting $T
will not emplace a token, it will emplace that AST Node. So what I expected to be something like this:
inner_macro!(`f32` [token])
was actually
inner_macro!(<Type>f32</Type>)
Unfortunately for users, the two invocations both get stringified the same way, to inner_macro! ( f32 )
.
The correct way to do this is to capture the token-to-be-substituted as a "token tree":
macro_rules! unknown {
($T:tt) => {
inner_macro!($T)
}
}
add a comment |
Your Answer
StackExchange.ifUsing("editor", function () {
StackExchange.using("externalEditor", function () {
StackExchange.using("snippets", function () {
StackExchange.snippets.init();
});
});
}, "code-snippets");
StackExchange.ready(function() {
var channelOptions = {
tags: "".split(" "),
id: "1"
};
initTagRenderer("".split(" "), "".split(" "), channelOptions);
StackExchange.using("externalEditor", function() {
// Have to fire editor after snippets, if snippets enabled
if (StackExchange.settings.snippets.snippetsEnabled) {
StackExchange.using("snippets", function() {
createEditor();
});
}
else {
createEditor();
}
});
function createEditor() {
StackExchange.prepareEditor({
heartbeatType: 'answer',
autoActivateHeartbeat: false,
convertImagesToLinks: true,
noModals: true,
showLowRepImageUploadWarning: true,
reputationToPostImages: 10,
bindNavPrevention: true,
postfix: "",
imageUploader: {
brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
allowUrls: true
},
onDemand: true,
discardSelector: ".discard-answer"
,immediatelyShowMarkdownHelp:true
});
}
});
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53449947%2fwhy-can-i-not-pass-a-captured-token-to-a-nested-macro%23new-answer', 'question_page');
}
);
Post as a guest
Required, but never shown
1 Answer
1
active
oldest
votes
1 Answer
1
active
oldest
votes
active
oldest
votes
active
oldest
votes
After some more reading, it turns out this is an instance of a typical stumbling block. After being captured the first time, $T
takes the value of an AST Node. Substituting $T
will not emplace a token, it will emplace that AST Node. So what I expected to be something like this:
inner_macro!(`f32` [token])
was actually
inner_macro!(<Type>f32</Type>)
Unfortunately for users, the two invocations both get stringified the same way, to inner_macro! ( f32 )
.
The correct way to do this is to capture the token-to-be-substituted as a "token tree":
macro_rules! unknown {
($T:tt) => {
inner_macro!($T)
}
}
add a comment |
After some more reading, it turns out this is an instance of a typical stumbling block. After being captured the first time, $T
takes the value of an AST Node. Substituting $T
will not emplace a token, it will emplace that AST Node. So what I expected to be something like this:
inner_macro!(`f32` [token])
was actually
inner_macro!(<Type>f32</Type>)
Unfortunately for users, the two invocations both get stringified the same way, to inner_macro! ( f32 )
.
The correct way to do this is to capture the token-to-be-substituted as a "token tree":
macro_rules! unknown {
($T:tt) => {
inner_macro!($T)
}
}
add a comment |
After some more reading, it turns out this is an instance of a typical stumbling block. After being captured the first time, $T
takes the value of an AST Node. Substituting $T
will not emplace a token, it will emplace that AST Node. So what I expected to be something like this:
inner_macro!(`f32` [token])
was actually
inner_macro!(<Type>f32</Type>)
Unfortunately for users, the two invocations both get stringified the same way, to inner_macro! ( f32 )
.
The correct way to do this is to capture the token-to-be-substituted as a "token tree":
macro_rules! unknown {
($T:tt) => {
inner_macro!($T)
}
}
After some more reading, it turns out this is an instance of a typical stumbling block. After being captured the first time, $T
takes the value of an AST Node. Substituting $T
will not emplace a token, it will emplace that AST Node. So what I expected to be something like this:
inner_macro!(`f32` [token])
was actually
inner_macro!(<Type>f32</Type>)
Unfortunately for users, the two invocations both get stringified the same way, to inner_macro! ( f32 )
.
The correct way to do this is to capture the token-to-be-substituted as a "token tree":
macro_rules! unknown {
($T:tt) => {
inner_macro!($T)
}
}
answered Nov 23 '18 at 16:36
CardanoCardano
414413
414413
add a comment |
add a comment |
Thanks for contributing an answer to Stack Overflow!
- Please be sure to answer the question. Provide details and share your research!
But avoid …
- Asking for help, clarification, or responding to other answers.
- Making statements based on opinion; back them up with references or personal experience.
To learn more, see our tips on writing great answers.
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53449947%2fwhy-can-i-not-pass-a-captured-token-to-a-nested-macro%23new-answer', 'question_page');
}
);
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown