Skip to content

Commit 82abc0d

Browse files
committed
Remember the span of the Kleene operator in macros
This is needed for having complete error messages where reporting macro variable errors. Here is what they would look like: error: meta-variable repeats with different kleene operator --> $DIR/issue-61053-different-kleene.rs:3:57 | LL | ( $( $i:ident = $($j:ident),+ );* ) => { $( $( $i = $j; )* )* }; | - expected repetition ^^ - conflicting repetition
1 parent 527dce7 commit 82abc0d

File tree

4 files changed

+33
-21
lines changed

4 files changed

+33
-21
lines changed

src/libsyntax/ext/tt/macro_parser.rs

+3-3
Original file line numberDiff line numberDiff line change
@@ -557,8 +557,8 @@ fn inner_parse_loop<'root, 'tt>(
557557
// implicitly disallowing OneOrMore from having 0 matches here. Thus, that will
558558
// result in a "no rules expected token" error by virtue of this matcher not
559559
// working.
560-
if seq.op == quoted::KleeneOp::ZeroOrMore
561-
|| seq.op == quoted::KleeneOp::ZeroOrOne
560+
if seq.kleene.op == quoted::KleeneOp::ZeroOrMore
561+
|| seq.kleene.op == quoted::KleeneOp::ZeroOrOne
562562
{
563563
let mut new_item = item.clone();
564564
new_item.match_cur += seq.num_captures;
@@ -573,7 +573,7 @@ fn inner_parse_loop<'root, 'tt>(
573573
cur_items.push(MatcherPosHandle::Box(Box::new(MatcherPos {
574574
stack: smallvec![],
575575
sep: seq.separator.clone(),
576-
seq_op: Some(seq.op),
576+
seq_op: Some(seq.kleene.op),
577577
idx: 0,
578578
matches,
579579
match_lo: item.match_cur,

src/libsyntax/ext/tt/macro_rules.rs

+8-8
Original file line numberDiff line numberDiff line change
@@ -273,7 +273,7 @@ pub fn compile(
273273
if body.legacy { token::Semi } else { token::Comma },
274274
def.span,
275275
)),
276-
op: quoted::KleeneOp::OneOrMore,
276+
kleene: quoted::KleeneToken::new(quoted::KleeneOp::OneOrMore, def.span),
277277
num_captures: 2,
278278
}),
279279
),
@@ -283,7 +283,7 @@ pub fn compile(
283283
Lrc::new(quoted::SequenceRepetition {
284284
tts: vec![quoted::TokenTree::token(token::Semi, def.span)],
285285
separator: None,
286-
op: quoted::KleeneOp::ZeroOrMore,
286+
kleene: quoted::KleeneToken::new(quoted::KleeneOp::ZeroOrMore, def.span),
287287
num_captures: 0,
288288
}),
289289
),
@@ -477,8 +477,8 @@ fn check_lhs_no_empty_seq(sess: &ParseSess, tts: &[quoted::TokenTree]) -> bool {
477477
&& seq.tts.iter().all(|seq_tt| match *seq_tt {
478478
TokenTree::MetaVarDecl(_, _, id) => id.name == sym::vis,
479479
TokenTree::Sequence(_, ref sub_seq) => {
480-
sub_seq.op == quoted::KleeneOp::ZeroOrMore
481-
|| sub_seq.op == quoted::KleeneOp::ZeroOrOne
480+
sub_seq.kleene.op == quoted::KleeneOp::ZeroOrMore
481+
|| sub_seq.kleene.op == quoted::KleeneOp::ZeroOrOne
482482
}
483483
_ => false,
484484
})
@@ -628,8 +628,8 @@ impl FirstSets {
628628

629629
// Reverse scan: Sequence comes before `first`.
630630
if subfirst.maybe_empty
631-
|| seq_rep.op == quoted::KleeneOp::ZeroOrMore
632-
|| seq_rep.op == quoted::KleeneOp::ZeroOrOne
631+
|| seq_rep.kleene.op == quoted::KleeneOp::ZeroOrMore
632+
|| seq_rep.kleene.op == quoted::KleeneOp::ZeroOrOne
633633
{
634634
// If sequence is potentially empty, then
635635
// union them (preserving first emptiness).
@@ -677,8 +677,8 @@ impl FirstSets {
677677
assert!(first.maybe_empty);
678678
first.add_all(subfirst);
679679
if subfirst.maybe_empty
680-
|| seq_rep.op == quoted::KleeneOp::ZeroOrMore
681-
|| seq_rep.op == quoted::KleeneOp::ZeroOrOne
680+
|| seq_rep.kleene.op == quoted::KleeneOp::ZeroOrMore
681+
|| seq_rep.kleene.op == quoted::KleeneOp::ZeroOrOne
682682
{
683683
// continue scanning for more first
684684
// tokens, but also make sure we

src/libsyntax/ext/tt/quoted.rs

+21-9
Original file line numberDiff line numberDiff line change
@@ -50,11 +50,23 @@ pub struct SequenceRepetition {
5050
/// The optional separator
5151
pub separator: Option<Token>,
5252
/// Whether the sequence can be repeated zero (*), or one or more times (+)
53-
pub op: KleeneOp,
53+
pub kleene: KleeneToken,
5454
/// The number of `Match`s that appear in the sequence (and subsequences)
5555
pub num_captures: usize,
5656
}
5757

58+
#[derive(Clone, PartialEq, RustcEncodable, RustcDecodable, Debug, Copy)]
59+
pub struct KleeneToken {
60+
pub span: Span,
61+
pub op: KleeneOp,
62+
}
63+
64+
impl KleeneToken {
65+
pub fn new(op: KleeneOp, span: Span) -> KleeneToken {
66+
KleeneToken { span, op }
67+
}
68+
}
69+
5870
/// A Kleene-style [repetition operator](http://en.wikipedia.org/wiki/Kleene_star)
5971
/// for token sequences.
6072
#[derive(Clone, PartialEq, RustcEncodable, RustcDecodable, Hash, Debug, Copy)]
@@ -273,15 +285,15 @@ fn parse_tree(
273285
macro_node_id,
274286
);
275287
// Get the Kleene operator and optional separator
276-
let (separator, op) = parse_sep_and_kleene_op(trees, span.entire(), sess);
288+
let (separator, kleene) = parse_sep_and_kleene_op(trees, span.entire(), sess);
277289
// Count the number of captured "names" (i.e., named metavars)
278290
let name_captures = macro_parser::count_names(&sequence);
279291
TokenTree::Sequence(
280292
span,
281293
Lrc::new(SequenceRepetition {
282294
tts: sequence,
283295
separator,
284-
op,
296+
kleene,
285297
num_captures: name_captures,
286298
}),
287299
)
@@ -379,28 +391,28 @@ fn parse_sep_and_kleene_op(
379391
input: &mut Peekable<impl Iterator<Item = tokenstream::TokenTree>>,
380392
span: Span,
381393
sess: &ParseSess,
382-
) -> (Option<Token>, KleeneOp) {
394+
) -> (Option<Token>, KleeneToken) {
383395
// We basically look at two token trees here, denoted as #1 and #2 below
384396
let span = match parse_kleene_op(input, span) {
385397
// #1 is a `?`, `+`, or `*` KleeneOp
386-
Ok(Ok((op, _))) => return (None, op),
398+
Ok(Ok((op, span))) => return (None, KleeneToken::new(op, span)),
387399

388400
// #1 is a separator followed by #2, a KleeneOp
389401
Ok(Err(token)) => match parse_kleene_op(input, token.span) {
390402
// #2 is the `?` Kleene op, which does not take a separator (error)
391-
Ok(Ok((KleeneOp::ZeroOrOne, _))) => {
403+
Ok(Ok((KleeneOp::ZeroOrOne, span))) => {
392404
// Error!
393405
sess.span_diagnostic.span_err(
394406
token.span,
395407
"the `?` macro repetition operator does not take a separator",
396408
);
397409

398410
// Return a dummy
399-
return (None, KleeneOp::ZeroOrMore);
411+
return (None, KleeneToken::new(KleeneOp::ZeroOrMore, span));
400412
}
401413

402414
// #2 is a KleeneOp :D
403-
Ok(Ok((op, _))) => return (Some(token), op),
415+
Ok(Ok((op, span))) => return (Some(token), KleeneToken::new(op, span)),
404416

405417
// #2 is a random token or not a token at all :(
406418
Ok(Err(Token { span, .. })) | Err(span) => span,
@@ -414,5 +426,5 @@ fn parse_sep_and_kleene_op(
414426
sess.span_diagnostic.span_err(span, "expected one of: `*`, `+`, or `?`");
415427

416428
// Return a dummy
417-
(None, KleeneOp::ZeroOrMore)
429+
(None, KleeneToken::new(KleeneOp::ZeroOrMore, span))
418430
}

src/libsyntax/ext/tt/transcribe.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -183,7 +183,7 @@ pub fn transcribe(
183183

184184
// Is the repetition empty?
185185
if len == 0 {
186-
if seq.op == quoted::KleeneOp::OneOrMore {
186+
if seq.kleene.op == quoted::KleeneOp::OneOrMore {
187187
// FIXME: this really ought to be caught at macro definition
188188
// time... It happens when the Kleene operator in the matcher and
189189
// the body for the same meta-variable do not match.

0 commit comments

Comments
 (0)