From c927743b7b7bd382836dcce2d1140a7e829dc3d0 Mon Sep 17 00:00:00 2001 From: bohan Date: Tue, 6 Jun 2023 23:11:08 +0800 Subject: [PATCH 1/2] fix(expand): prevent infinity loop in macro containing only "///" --- compiler/rustc_expand/src/mbe/macro_parser.rs | 1 + compiler/rustc_expand/src/mbe/macro_rules.rs | 1 + tests/ui/macros/issue-112342-1.rs | 36 +++++++++++++++++++ tests/ui/macros/issue-112342-1.stderr | 29 +++++++++++++++ tests/ui/macros/issue-112342-2.rs | 28 +++++++++++++++ 5 files changed, 95 insertions(+) create mode 100644 tests/ui/macros/issue-112342-1.rs create mode 100644 tests/ui/macros/issue-112342-1.stderr create mode 100644 tests/ui/macros/issue-112342-2.rs diff --git a/compiler/rustc_expand/src/mbe/macro_parser.rs b/compiler/rustc_expand/src/mbe/macro_parser.rs index 1c222fb4a898c..f0e67cfd50e08 100644 --- a/compiler/rustc_expand/src/mbe/macro_parser.rs +++ b/compiler/rustc_expand/src/mbe/macro_parser.rs @@ -249,6 +249,7 @@ pub(super) fn compute_locs(matcher: &[TokenTree]) -> Vec { } /// A single matcher position, representing the state of matching. +#[derive(Debug)] struct MatcherPos { /// The index into `TtParser::locs`, which represents the "dot". idx: usize, diff --git a/compiler/rustc_expand/src/mbe/macro_rules.rs b/compiler/rustc_expand/src/mbe/macro_rules.rs index e4c65a2049bf6..576d636d489c2 100644 --- a/compiler/rustc_expand/src/mbe/macro_rules.rs +++ b/compiler/rustc_expand/src/mbe/macro_rules.rs @@ -647,6 +647,7 @@ fn check_lhs_no_empty_seq(sess: &ParseSess, tts: &[mbe::TokenTree]) -> bool { if seq.separator.is_none() && seq.tts.iter().all(|seq_tt| match seq_tt { TokenTree::MetaVarDecl(_, _, Some(NonterminalKind::Vis)) => true, + TokenTree::Token(t) => matches!(t, Token { kind: DocComment(..), .. }), TokenTree::Sequence(_, sub_seq) => { sub_seq.kleene.op == mbe::KleeneOp::ZeroOrMore || sub_seq.kleene.op == mbe::KleeneOp::ZeroOrOne diff --git a/tests/ui/macros/issue-112342-1.rs b/tests/ui/macros/issue-112342-1.rs new file mode 100644 index 0000000000000..14fe9bbd97a24 --- /dev/null +++ b/tests/ui/macros/issue-112342-1.rs @@ -0,0 +1,36 @@ +// 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! {} + +fn main() {} diff --git a/tests/ui/macros/issue-112342-1.stderr b/tests/ui/macros/issue-112342-1.stderr new file mode 100644 index 0000000000000..1ba7c0ffd3bd1 --- /dev/null +++ b/tests/ui/macros/issue-112342-1.stderr @@ -0,0 +1,29 @@ +error: repetition matches empty token tree + --> $DIR/issue-112342-1.rs:5:10 + | +LL | $( + | __________^ +LL | | /// +LL | | )* + | |_________^ + +error: repetition matches empty token tree + --> $DIR/issue-112342-1.rs:16:10 + | +LL | $( + | __________^ +LL | | /// +LL | | )+ + | |_________^ + +error: repetition matches empty token tree + --> $DIR/issue-112342-1.rs:27:10 + | +LL | $( + | __________^ +LL | | /// +LL | | )? + | |_________^ + +error: aborting due to 3 previous errors + diff --git a/tests/ui/macros/issue-112342-2.rs b/tests/ui/macros/issue-112342-2.rs new file mode 100644 index 0000000000000..1e1d953fa5269 --- /dev/null +++ b/tests/ui/macros/issue-112342-2.rs @@ -0,0 +1,28 @@ +// 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! {} + +fn main() {} From 5eafab30ba0721451f5114c5b27b37870bb3955a Mon Sep 17 00:00:00 2001 From: bohan Date: Wed, 7 Jun 2023 00:26:16 +0800 Subject: [PATCH 2/2] feat(expand): emit note for doc comment in macro matcher --- compiler/rustc_expand/src/mbe/macro_rules.rs | 46 +++++++++++++++----- tests/ui/macros/issue-112342-1.rs | 13 ++++++ tests/ui/macros/issue-112342-1.stderr | 37 +++++++++++++++- tests/ui/macros/issue-112342-2.rs | 11 +++++ tests/ui/macros/issue-112342-2.stderr | 24 ++++++++++ 5 files changed, 119 insertions(+), 12 deletions(-) create mode 100644 tests/ui/macros/issue-112342-2.stderr diff --git a/compiler/rustc_expand/src/mbe/macro_rules.rs b/compiler/rustc_expand/src/mbe/macro_rules.rs index 576d636d489c2..ee9616a0f0a9d 100644 --- a/compiler/rustc_expand/src/mbe/macro_rules.rs +++ b/compiler/rustc_expand/src/mbe/macro_rules.rs @@ -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 { @@ -644,17 +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::Token(t) => matches!(t, Token { kind: DocComment(..), .. }), - 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; diff --git a/tests/ui/macros/issue-112342-1.rs b/tests/ui/macros/issue-112342-1.rs index 14fe9bbd97a24..bd2abe7f697f4 100644 --- a/tests/ui/macros/issue-112342-1.rs +++ b/tests/ui/macros/issue-112342-1.rs @@ -33,4 +33,17 @@ macro_rules! m3 { m3! {} + +macro_rules! m4 { + ( + $( + /// + /// + )* + //~^^^^ERROR repetition matches empty token tree + ) => {}; +} + +m4! {} + fn main() {} diff --git a/tests/ui/macros/issue-112342-1.stderr b/tests/ui/macros/issue-112342-1.stderr index 1ba7c0ffd3bd1..f2d82bf599e99 100644 --- a/tests/ui/macros/issue-112342-1.stderr +++ b/tests/ui/macros/issue-112342-1.stderr @@ -1,3 +1,9 @@ +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 | @@ -7,6 +13,12 @@ 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 | @@ -16,6 +28,12 @@ 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 | @@ -25,5 +43,22 @@ LL | | /// LL | | )? | |_________^ -error: aborting due to 3 previous errors +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 diff --git a/tests/ui/macros/issue-112342-2.rs b/tests/ui/macros/issue-112342-2.rs index 1e1d953fa5269..e797aff94d2f3 100644 --- a/tests/ui/macros/issue-112342-2.rs +++ b/tests/ui/macros/issue-112342-2.rs @@ -25,4 +25,15 @@ macro_rules! m2 { m2! {} +macro_rules! m3 { + ( + $( + /// + $tt: tt, + )* + ) => {}; +} + +m3! {} + fn main() {} diff --git a/tests/ui/macros/issue-112342-2.stderr b/tests/ui/macros/issue-112342-2.stderr new file mode 100644 index 0000000000000..8c1b6f9471bce --- /dev/null +++ b/tests/ui/macros/issue-112342-2.stderr @@ -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 | /// + | ^^^ +