Skip to content

Commit

Permalink
Rollup merge of #112345 - bvanjoi:fix-112342, r=nilstrieb,est31
Browse files Browse the repository at this point in the history
fix(expand): prevent infinity loop in macro containing only "///"

Fixes #112342

Issue #112342 was caused by an infinity loop in `parse_tt_inner`, and the state of it is as follows:

- `matcher`: `[Sequence, Token(Doc), SequenceKleeneOpNoSep(op: ZeroOrMore), Eof]`

-  loop:

| Iteration | Action |
| - | - |
| 0   |  enter `Sequence`|
| 1    |  enter `Token(Doc)` and `mp.idx += 1` had been executed |
| 2   |  enter `SequenceKleeneOpNoSep` and reset `mp.idx` to `1` |
| 3   | enter `Token(Doc)` again|

To prevent the infinite loop, a check for whether it only contains `DocComment` in `check_lhs_no_empty_seq` had been added.
  • Loading branch information
Dylan-DPC authored Jun 7, 2023
2 parents c6fda40 + 5eafab3 commit 42cf6da
Show file tree
Hide file tree
Showing 6 changed files with 212 additions and 10 deletions.
1 change: 1 addition & 0 deletions compiler/rustc_expand/src/mbe/macro_parser.rs
Original file line number Diff line number Diff line change
Expand Up @@ -249,6 +249,7 @@ pub(super) fn compute_locs(matcher: &[TokenTree]) -> Vec<MatcherLoc> {
}

/// A single matcher position, representing the state of matching.
#[derive(Debug)]
struct MatcherPos {
/// The index into `TtParser::locs`, which represents the "dot".
idx: usize,
Expand Down
45 changes: 35 additions & 10 deletions compiler/rustc_expand/src/mbe/macro_rules.rs
Original file line number Diff line number Diff line change
Expand Up @@ -628,6 +628,40 @@ fn check_lhs_nt_follows(sess: &ParseSess, def: &ast::Item, lhs: &mbe::TokenTree)
// after parsing/expansion. we can report every error in every macro this way.
}

fn is_empty_token_tree(sess: &ParseSess, seq: &mbe::SequenceRepetition) -> bool {
if seq.separator.is_some() {
false
} else {
let mut is_empty = true;
let mut iter = seq.tts.iter().peekable();
while let Some(tt) = iter.next() {
match tt {
mbe::TokenTree::MetaVarDecl(_, _, Some(NonterminalKind::Vis)) => {}
mbe::TokenTree::Token(t @ Token { kind: DocComment(..), .. }) => {
let mut now = t;
while let Some(&mbe::TokenTree::Token(
next @ Token { kind: DocComment(..), .. },
)) = iter.peek()
{
now = next;
iter.next();
}
let span = t.span.to(now.span);
sess.span_diagnostic.span_note_without_error(
span,
"doc comments are ignored in matcher position",
);
}
mbe::TokenTree::Sequence(_, sub_seq)
if (sub_seq.kleene.op == mbe::KleeneOp::ZeroOrMore
|| sub_seq.kleene.op == mbe::KleeneOp::ZeroOrOne) => {}
_ => is_empty = false,
}
}
is_empty
}
}

/// Checks that the lhs contains no repetition which could match an empty token
/// tree, because then the matcher would hang indefinitely.
fn check_lhs_no_empty_seq(sess: &ParseSess, tts: &[mbe::TokenTree]) -> bool {
Expand All @@ -644,16 +678,7 @@ fn check_lhs_no_empty_seq(sess: &ParseSess, tts: &[mbe::TokenTree]) -> bool {
}
}
TokenTree::Sequence(span, seq) => {
if seq.separator.is_none()
&& seq.tts.iter().all(|seq_tt| match seq_tt {
TokenTree::MetaVarDecl(_, _, Some(NonterminalKind::Vis)) => true,
TokenTree::Sequence(_, sub_seq) => {
sub_seq.kleene.op == mbe::KleeneOp::ZeroOrMore
|| sub_seq.kleene.op == mbe::KleeneOp::ZeroOrOne
}
_ => false,
})
{
if is_empty_token_tree(sess, seq) {
let sp = span.entire();
sess.span_diagnostic.span_err(sp, "repetition matches empty token tree");
return false;
Expand Down
49 changes: 49 additions & 0 deletions tests/ui/macros/issue-112342-1.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
// same as #95267, ignore doc comment although it's a bug.

macro_rules! m1 {
(
$(
///
)*
//~^^^ERROR repetition matches empty token tree
) => {};
}

m1! {}

macro_rules! m2 {
(
$(
///
)+
//~^^^ERROR repetition matches empty token tree
) => {};
}

m2! {}

macro_rules! m3 {
(
$(
///
)?
//~^^^ERROR repetition matches empty token tree
) => {};
}

m3! {}


macro_rules! m4 {
(
$(
///
///
)*
//~^^^^ERROR repetition matches empty token tree
) => {};
}

m4! {}

fn main() {}
64 changes: 64 additions & 0 deletions tests/ui/macros/issue-112342-1.stderr
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
note: doc comments are ignored in matcher position
--> $DIR/issue-112342-1.rs:6:13
|
LL | ///
| ^^^

error: repetition matches empty token tree
--> $DIR/issue-112342-1.rs:5:10
|
LL | $(
| __________^
LL | | ///
LL | | )*
| |_________^

note: doc comments are ignored in matcher position
--> $DIR/issue-112342-1.rs:17:13
|
LL | ///
| ^^^

error: repetition matches empty token tree
--> $DIR/issue-112342-1.rs:16:10
|
LL | $(
| __________^
LL | | ///
LL | | )+
| |_________^

note: doc comments are ignored in matcher position
--> $DIR/issue-112342-1.rs:28:13
|
LL | ///
| ^^^

error: repetition matches empty token tree
--> $DIR/issue-112342-1.rs:27:10
|
LL | $(
| __________^
LL | | ///
LL | | )?
| |_________^

note: doc comments are ignored in matcher position
--> $DIR/issue-112342-1.rs:40:13
|
LL | / ///
LL | | ///
| |_______________^

error: repetition matches empty token tree
--> $DIR/issue-112342-1.rs:39:10
|
LL | $(
| __________^
LL | | ///
LL | | ///
LL | | )*
| |_________^

error: aborting due to 4 previous errors

39 changes: 39 additions & 0 deletions tests/ui/macros/issue-112342-2.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
// check-pass

// same as #95267, ignore doc comment although it's a bug.

macro_rules! m1 {
(
$(
///
$expr: expr,
)*
) => {};
}

m1! {}

macro_rules! m2 {
(
$(
///
$expr: expr,
///
)*
) => {};
}

m2! {}

macro_rules! m3 {
(
$(
///
$tt: tt,
)*
) => {};
}

m3! {}

fn main() {}
24 changes: 24 additions & 0 deletions tests/ui/macros/issue-112342-2.stderr
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
note: doc comments are ignored in matcher position
--> $DIR/issue-112342-2.rs:8:13
|
LL | ///
| ^^^

note: doc comments are ignored in matcher position
--> $DIR/issue-112342-2.rs:19:13
|
LL | ///
| ^^^

note: doc comments are ignored in matcher position
--> $DIR/issue-112342-2.rs:21:13
|
LL | ///
| ^^^

note: doc comments are ignored in matcher position
--> $DIR/issue-112342-2.rs:31:13
|
LL | ///
| ^^^

0 comments on commit 42cf6da

Please sign in to comment.