From 5eafab30ba0721451f5114c5b27b37870bb3955a Mon Sep 17 00:00:00 2001 From: bohan Date: Wed, 7 Jun 2023 00:26:16 +0800 Subject: [PATCH] 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 576d636d489..ee9616a0f0a 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 14fe9bbd97a..bd2abe7f697 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 1ba7c0ffd3b..f2d82bf599e 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 1e1d953fa52..e797aff94d2 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 00000000000..8c1b6f9471b --- /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 | /// + | ^^^ +