diff --git a/crates/mbe/src/mbe_expander/matcher.rs b/crates/mbe/src/mbe_expander/matcher.rs index 3f84458977..4860b242d0 100644 --- a/crates/mbe/src/mbe_expander/matcher.rs +++ b/crates/mbe/src/mbe_expander/matcher.rs @@ -356,6 +356,18 @@ impl<'a> TtIter<'a> { ExpandResult { value: _, err: Some(_) } => None, } } + + pub(crate) fn eat_char(&mut self) -> Option { + let mut fork = self.clone(); + match fork.expect_char('-') { + Ok(_) => { + let tt = self.next().cloned(); + *self = fork; + tt + } + Err(_) => None, + } + } } pub(super) fn match_repeat( @@ -447,10 +459,22 @@ fn match_meta_var(kind: &str, input: &mut TtIter) -> ExpandResult input - .expect_literal() - .map(|literal| Some(tt::Leaf::from(literal.clone()).into())) - .map_err(|()| err!()), + "literal" => { + let neg = input.eat_char(); + input + .expect_literal() + .map(|literal| { + let lit = tt::Leaf::from(literal.clone()); + match neg { + None => Some(lit.into()), + Some(neg) => Some(tt::TokenTree::Subtree(tt::Subtree { + delimiter: None, + token_trees: vec![neg, lit.into()], + })), + } + }) + .map_err(|()| err!()) + } // `vis` is optional "vis" => match input.eat_vis() { Some(vis) => Ok(Some(vis)), diff --git a/crates/mbe/src/tests.rs b/crates/mbe/src/tests.rs index 0796ceee1a..843054fe85 100644 --- a/crates/mbe/src/tests.rs +++ b/crates/mbe/src/tests.rs @@ -1008,11 +1008,20 @@ fn test_literal() { parse_macro( r#" macro_rules! foo { - ($ type:ty $ lit:literal) => { const VALUE: $ type = $ lit;}; + ($ type:ty , $ lit:literal) => { const VALUE: $ type = $ lit;}; } "#, ) - .assert_expand_items(r#"foo!(u8 0);"#, r#"const VALUE : u8 = 0 ;"#); + .assert_expand_items(r#"foo!(u8,0);"#, r#"const VALUE : u8 = 0 ;"#); + + parse_macro( + r#" + macro_rules! foo { + ($ type:ty , $ lit:literal) => { const VALUE: $ type = $ lit;}; + } +"#, + ) + .assert_expand_items(r#"foo!(i32,-1);"#, r#"const VALUE : i32 = - 1 ;"#); } #[test]