Skip to content

Commit dfd751b

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 848e0a2 commit dfd751b

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
@@ -276,7 +276,7 @@ pub fn compile(
276276
if body.legacy { token::Semi } else { token::Comma },
277277
def.span,
278278
)),
279-
op: quoted::KleeneOp::OneOrMore,
279+
kleene: quoted::KleeneToken::new(quoted::KleeneOp::OneOrMore, def.span),
280280
num_captures: 2,
281281
}),
282282
),
@@ -286,7 +286,7 @@ pub fn compile(
286286
Lrc::new(quoted::SequenceRepetition {
287287
tts: vec![quoted::TokenTree::token(token::Semi, def.span)],
288288
separator: None,
289-
op: quoted::KleeneOp::ZeroOrMore,
289+
kleene: quoted::KleeneToken::new(quoted::KleeneOp::ZeroOrMore, def.span),
290290
num_captures: 0,
291291
}),
292292
),
@@ -484,8 +484,8 @@ fn check_lhs_no_empty_seq(sess: &ParseSess, tts: &[quoted::TokenTree]) -> bool {
484484
&& seq.tts.iter().all(|seq_tt| match *seq_tt {
485485
TokenTree::MetaVarDecl(_, _, id) => id.name == sym::vis,
486486
TokenTree::Sequence(_, ref sub_seq) => {
487-
sub_seq.op == quoted::KleeneOp::ZeroOrMore
488-
|| sub_seq.op == quoted::KleeneOp::ZeroOrOne
487+
sub_seq.kleene.op == quoted::KleeneOp::ZeroOrMore
488+
|| sub_seq.kleene.op == quoted::KleeneOp::ZeroOrOne
489489
}
490490
_ => false,
491491
})
@@ -635,8 +635,8 @@ impl FirstSets {
635635

636636
// Reverse scan: Sequence comes before `first`.
637637
if subfirst.maybe_empty
638-
|| seq_rep.op == quoted::KleeneOp::ZeroOrMore
639-
|| seq_rep.op == quoted::KleeneOp::ZeroOrOne
638+
|| seq_rep.kleene.op == quoted::KleeneOp::ZeroOrMore
639+
|| seq_rep.kleene.op == quoted::KleeneOp::ZeroOrOne
640640
{
641641
// If sequence is potentially empty, then
642642
// union them (preserving first emptiness).
@@ -684,8 +684,8 @@ impl FirstSets {
684684
assert!(first.maybe_empty);
685685
first.add_all(subfirst);
686686
if subfirst.maybe_empty
687-
|| seq_rep.op == quoted::KleeneOp::ZeroOrMore
688-
|| seq_rep.op == quoted::KleeneOp::ZeroOrOne
687+
|| seq_rep.kleene.op == quoted::KleeneOp::ZeroOrMore
688+
|| seq_rep.kleene.op == quoted::KleeneOp::ZeroOrOne
689689
{
690690
// continue scanning for more first
691691
// 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)