Skip to content

Commit c3b1543

Browse files
Merge pull request #20000 from tadeokondrak/lifetime-repeat-macro
Allow lifetime repeats in macros: $($x)'a*
2 parents e557333 + 68d841e commit c3b1543

File tree

8 files changed

+63
-14
lines changed

8 files changed

+63
-14
lines changed

src/tools/rust-analyzer/crates/hir-def/src/macro_expansion_tests/mbe.rs

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2029,3 +2029,25 @@ fn f() {
20292029
"#]],
20302030
);
20312031
}
2032+
2033+
#[test]
2034+
fn lifetime_repeat() {
2035+
check(
2036+
r#"
2037+
macro_rules! m {
2038+
($($x:expr)'a*) => (stringify!($($x)'b*));
2039+
}
2040+
fn f() {
2041+
let _ = m!(0 'a 1 'a 2);
2042+
}
2043+
"#,
2044+
expect![[r#"
2045+
macro_rules! m {
2046+
($($x:expr)'a*) => (stringify!($($x)'b*));
2047+
}
2048+
fn f() {
2049+
let _ = stringify!(0 'b 1 'b 2);
2050+
}
2051+
"#]],
2052+
);
2053+
}

src/tools/rust-analyzer/crates/hir-def/src/macro_expansion_tests/mbe/meta_syntax.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,8 @@ macro_rules! m {
1313
($(x),*) => ();
1414
($(x)_*) => ();
1515
($(x)i*) => ();
16+
($(x)'a*) => ();
17+
($(x)'_*) => ();
1618
($($i:ident)*) => ($_);
1719
($($true:ident)*) => ($true);
1820
($($false:ident)*) => ($false);
@@ -28,6 +30,8 @@ macro_rules! m {
2830
($(x),*) => ();
2931
($(x)_*) => ();
3032
($(x)i*) => ();
33+
($(x)'a*) => ();
34+
($(x)'_*) => ();
3135
($($i:ident)*) => ($_);
3236
($($true:ident)*) => ($true);
3337
($($false:ident)*) => ($false);

src/tools/rust-analyzer/crates/hir-def/src/macro_expansion_tests/mbe/regression.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -784,7 +784,7 @@ macro_rules! delegate_impl {
784784
}
785785
}
786786
}
787-
impl <> Data for &'amut G where G: Data {}
787+
impl <> Data for &'a mut G where G: Data {}
788788
"#]],
789789
);
790790
}

src/tools/rust-analyzer/crates/hir-def/src/macro_expansion_tests/mod.rs

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -302,14 +302,15 @@ fn pretty_print_macro_expansion(
302302
(_, T!['{']) => " ",
303303
(T![;] | T!['{'] | T!['}'], _) => "\n",
304304
(_, T!['}']) => "\n",
305-
(IDENT | LIFETIME_IDENT, IDENT | LIFETIME_IDENT) => " ",
306-
_ if prev_kind.is_keyword(Edition::CURRENT)
307-
&& curr_kind.is_keyword(Edition::CURRENT) =>
305+
_ if (prev_kind.is_any_identifier()
306+
|| prev_kind == LIFETIME_IDENT
307+
|| prev_kind.is_literal())
308+
&& (curr_kind.is_any_identifier()
309+
|| curr_kind == LIFETIME_IDENT
310+
|| curr_kind.is_literal()) =>
308311
{
309312
" "
310313
}
311-
(IDENT, _) if curr_kind.is_keyword(Edition::CURRENT) => " ",
312-
(_, IDENT) if prev_kind.is_keyword(Edition::CURRENT) => " ",
313314
(T![>], IDENT) => " ",
314315
(T![>], _) if curr_kind.is_keyword(Edition::CURRENT) => " ",
315316
(T![->], _) | (_, T![->]) => " ",

src/tools/rust-analyzer/crates/mbe/src/benchmark.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -197,6 +197,10 @@ fn invocation_fixtures(
197197
builder.push(tt::Leaf::Punct(*it))
198198
}
199199
}
200+
Separator::Lifetime(punct, ident) => {
201+
builder.push(tt::Leaf::Punct(*punct));
202+
builder.push(tt::Leaf::Ident(ident.clone()));
203+
}
200204
};
201205
}
202206
}

src/tools/rust-analyzer/crates/mbe/src/expander/matcher.rs

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -823,7 +823,7 @@ fn match_meta_var<'t>(
823823
"expected token tree",
824824
)
825825
}),
826-
MetaVarKind::Lifetime => expect_lifetime(input).map_err(|()| {
826+
MetaVarKind::Lifetime => expect_lifetime(input).map(drop).map_err(|()| {
827827
ExpandError::binding_error(
828828
span.unwrap_or(delim_span.close),
829829
"expected lifetime",
@@ -963,6 +963,10 @@ fn expect_separator<S: Copy>(iter: &mut TtIter<'_, S>, separator: &Separator) ->
963963
}
964964
Err(_) => false,
965965
},
966+
Separator::Lifetime(_punct, ident) => match expect_lifetime(&mut fork) {
967+
Ok(lifetime) => lifetime.sym == ident.sym,
968+
Err(_) => false,
969+
},
966970
};
967971
if ok {
968972
*iter = fork;
@@ -983,13 +987,12 @@ fn expect_tt<S: Copy>(iter: &mut TtIter<'_, S>) -> Result<(), ()> {
983987
Ok(())
984988
}
985989

986-
fn expect_lifetime<S: Copy>(iter: &mut TtIter<'_, S>) -> Result<(), ()> {
990+
fn expect_lifetime<'a, S: Copy>(iter: &mut TtIter<'a, S>) -> Result<&'a tt::Ident<S>, ()> {
987991
let punct = iter.expect_single_punct()?;
988992
if punct.char != '\'' {
989993
return Err(());
990994
}
991-
iter.expect_ident_or_underscore()?;
992-
Ok(())
995+
iter.expect_ident_or_underscore()
993996
}
994997

995998
fn eat_char<S: Copy>(iter: &mut TtIter<'_, S>, c: char) {

src/tools/rust-analyzer/crates/mbe/src/expander/transcriber.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -497,6 +497,10 @@ fn expand_repeat(
497497
builder.push(tt::Leaf::from(punct));
498498
}
499499
}
500+
Separator::Lifetime(punct, ident) => {
501+
builder.push(tt::Leaf::from(*punct));
502+
builder.push(tt::Leaf::from(ident.clone()));
503+
}
500504
};
501505
}
502506

src/tools/rust-analyzer/crates/mbe/src/parser.rs

Lines changed: 15 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -155,6 +155,7 @@ pub(crate) enum Separator {
155155
Literal(tt::Literal<Span>),
156156
Ident(tt::Ident<Span>),
157157
Puncts(ArrayVec<tt::Punct<Span>, MAX_GLUED_PUNCT_LEN>),
158+
Lifetime(tt::Punct<Span>, tt::Ident<Span>),
158159
}
159160

160161
// Note that when we compare a Separator, we just care about its textual value.
@@ -170,6 +171,7 @@ impl PartialEq for Separator {
170171
let b_iter = b.iter().map(|b| b.char);
171172
a_iter.eq(b_iter)
172173
}
174+
(Lifetime(_, a), Lifetime(_, b)) => a.sym == b.sym,
173175
_ => false,
174176
}
175177
}
@@ -350,10 +352,19 @@ fn parse_repeat(src: &mut TtIter<'_, Span>) -> Result<(Option<Separator>, Repeat
350352
_ => true,
351353
};
352354
match tt {
353-
tt::Leaf::Ident(_) | tt::Leaf::Literal(_) if has_sep => {
354-
return Err(ParseError::InvalidRepeat);
355-
}
356-
tt::Leaf::Ident(ident) => separator = Separator::Ident(ident.clone()),
355+
tt::Leaf::Ident(ident) => match separator {
356+
Separator::Puncts(puncts) if puncts.is_empty() => {
357+
separator = Separator::Ident(ident.clone());
358+
}
359+
Separator::Puncts(puncts) => match puncts.as_slice() {
360+
[tt::Punct { char: '\'', .. }] => {
361+
separator = Separator::Lifetime(puncts[0], ident.clone());
362+
}
363+
_ => return Err(ParseError::InvalidRepeat),
364+
},
365+
_ => return Err(ParseError::InvalidRepeat),
366+
},
367+
tt::Leaf::Literal(_) if has_sep => return Err(ParseError::InvalidRepeat),
357368
tt::Leaf::Literal(lit) => separator = Separator::Literal(lit.clone()),
358369
tt::Leaf::Punct(punct) => {
359370
let repeat_kind = match punct.char {

0 commit comments

Comments
 (0)