Skip to content

Commit 9be3bdd

Browse files
committed
[macro_metavar_expr_concat] Allow concat in repetitions
1 parent 6be96e3 commit 9be3bdd

File tree

4 files changed

+71
-38
lines changed

4 files changed

+71
-38
lines changed

compiler/rustc_expand/src/mbe/macro_check.rs

+4-4
Original file line numberDiff line numberDiff line change
@@ -352,10 +352,10 @@ fn check_occurrences(
352352
check_ops_is_prefix(psess, node_id, macros, binders, ops, span, name);
353353
}
354354
TokenTree::MetaVarExpr(dl, ref mve) => {
355-
let Some(name) = mve.ident().map(MacroRulesNormalizedIdent::new) else {
356-
return;
357-
};
358-
check_ops_is_prefix(psess, node_id, macros, binders, ops, dl.entire(), name);
355+
mve.metavars((), |_, ident| {
356+
let name = MacroRulesNormalizedIdent::new(*ident);
357+
check_ops_is_prefix(psess, node_id, macros, binders, ops, dl.entire(), name);
358+
});
359359
}
360360
TokenTree::Delimited(.., ref del) => {
361361
check_nested_occurrences(psess, node_id, &del.tts, macros, binders, ops, guar);

compiler/rustc_expand/src/mbe/metavar_expr.rs

+12-4
Original file line numberDiff line numberDiff line change
@@ -111,10 +111,18 @@ impl MetaVarExpr {
111111
Ok(rslt)
112112
}
113113

114-
pub(crate) fn ident(&self) -> Option<Ident> {
115-
match *self {
116-
MetaVarExpr::Count(ident, _) | MetaVarExpr::Ignore(ident) => Some(ident),
117-
MetaVarExpr::Concat { .. } | MetaVarExpr::Index(..) | MetaVarExpr::Len(..) => None,
114+
pub(crate) fn metavars<A>(&self, mut aux: A, mut cb: impl FnMut(A, &Ident) -> A) -> A {
115+
match self {
116+
MetaVarExpr::Concat(elems) => {
117+
for elem in elems {
118+
if let MetaVarExprConcatElem::Var(ident) = elem {
119+
aux = cb(aux, ident)
120+
}
121+
}
122+
aux
123+
}
124+
MetaVarExpr::Count(ident, _) | MetaVarExpr::Ignore(ident) => cb(aux, ident),
125+
MetaVarExpr::Index(..) | MetaVarExpr::Len(..) => aux,
118126
}
119127
}
120128
}

compiler/rustc_expand/src/mbe/transcribe.rs

+37-30
Original file line numberDiff line numberDiff line change
@@ -556,17 +556,13 @@ fn lockstep_iter_size(
556556
}
557557
}
558558
TokenTree::MetaVarExpr(_, expr) => {
559-
let default_rslt = LockstepIterSize::Unconstrained;
560-
let Some(ident) = expr.ident() else {
561-
return default_rslt;
562-
};
563-
let name = MacroRulesNormalizedIdent::new(ident);
564-
match lookup_cur_matched(name, interpolations, repeats) {
565-
Some(MatchedSeq(ads)) => {
566-
default_rslt.with(LockstepIterSize::Constraint(ads.len(), name))
567-
}
568-
_ => default_rslt,
569-
}
559+
expr.metavars(LockstepIterSize::Unconstrained, |lis, ident| {
560+
lis.with(lockstep_iter_size(
561+
&TokenTree::MetaVar(ident.span, *ident),
562+
interpolations,
563+
repeats,
564+
))
565+
})
570566
}
571567
TokenTree::Token(..) => LockstepIterSize::Unconstrained,
572568
}
@@ -694,7 +690,20 @@ fn transcribe_metavar_expr<'a>(
694690
let string = match element {
695691
MetaVarExprConcatElem::Ident(elem) => elem.to_string(),
696692
MetaVarExprConcatElem::Literal(elem) => elem.as_str().into(),
697-
MetaVarExprConcatElem::Var(elem) => extract_ident(dcx, *elem, interp)?,
693+
MetaVarExprConcatElem::Var(ident) => {
694+
match matched_from_ident(dcx, *ident, interp)? {
695+
NamedMatch::MatchedSeq(named_matches) => {
696+
let curr_idx = repeats.last().unwrap().0;
697+
match &named_matches[curr_idx] {
698+
MatchedSeq(_) => unimplemented!(),
699+
MatchedSingle(pnr) => extract_ident_from_pnr(dcx, ident, pnr)?,
700+
}
701+
}
702+
NamedMatch::MatchedSingle(pnr) => {
703+
extract_ident_from_pnr(dcx, ident, pnr)?
704+
}
705+
}
706+
}
698707
};
699708
concatenated.push_str(&string);
700709
}
@@ -751,28 +760,26 @@ fn transcribe_metavar_expr<'a>(
751760
}
752761

753762
/// Extracts an identifier that can be originated from a `$var:ident` variable or from a token tree.
754-
fn extract_ident<'a>(
763+
fn extract_ident_from_pnr<'a>(
755764
dcx: DiagCtxtHandle<'a>,
756-
ident: Ident,
757-
interp: &FxHashMap<MacroRulesNormalizedIdent, NamedMatch>,
765+
ident: &Ident,
766+
pnr: &ParseNtResult,
758767
) -> PResult<'a, String> {
759-
if let NamedMatch::MatchedSingle(pnr) = matched_from_ident(dcx, ident, interp)? {
760-
if let ParseNtResult::Ident(nt_ident, is_raw) = pnr {
761-
if let IdentIsRaw::Yes = is_raw {
762-
return Err(dcx.struct_span_err(ident.span, RAW_IDENT_ERR));
763-
}
764-
return Ok(nt_ident.to_string());
768+
if let ParseNtResult::Ident(nt_ident, is_raw) = pnr {
769+
if let IdentIsRaw::Yes = is_raw {
770+
return Err(dcx.struct_span_err(ident.span, RAW_IDENT_ERR));
765771
}
766-
if let ParseNtResult::Tt(TokenTree::Token(
767-
Token { kind: TokenKind::Ident(token_ident, is_raw), .. },
768-
_,
769-
)) = pnr
770-
{
771-
if let IdentIsRaw::Yes = is_raw {
772-
return Err(dcx.struct_span_err(ident.span, RAW_IDENT_ERR));
773-
}
774-
return Ok(token_ident.to_string());
772+
return Ok(nt_ident.to_string());
773+
}
774+
if let ParseNtResult::Tt(TokenTree::Token(
775+
Token { kind: TokenKind::Ident(token_ident, is_raw), .. },
776+
_,
777+
)) = pnr
778+
{
779+
if let IdentIsRaw::Yes = is_raw {
780+
return Err(dcx.struct_span_err(ident.span, RAW_IDENT_ERR));
775781
}
782+
return Ok(token_ident.to_string());
776783
}
777784
Err(dcx.struct_span_err(
778785
ident.span,
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
//@ run-pass
2+
3+
#![feature(macro_metavar_expr_concat)]
4+
5+
macro_rules! one_rep {
6+
( $($a:ident)* ) => {
7+
$(
8+
const ${concat($a, Z)}: i32 = 3;
9+
)*
10+
};
11+
}
12+
13+
fn main() {
14+
one_rep!(A B C);
15+
assert_eq!(AZ, 3);
16+
assert_eq!(BZ, 3);
17+
assert_eq!(CZ, 3);
18+
}

0 commit comments

Comments
 (0)