Skip to content

Commit 079aa83

Browse files
committed
Auto merge of #86574 - m-ou-se:or-pattern-lint-fix, r=petrochenkov
Don't lint :pat when re-parsing a macro from another crate. `compile_macro` is used both when compiling the original definition in the crate that defines it, and to compile the macro when loading it when compiling a crate that uses it. We should only emit lints in the first case. This adds a `is_definition: bool` to pass this information in, so we don't warn about things that only concern the definition site. Fixes #86567
2 parents d4e7cb3 + 06db210 commit 079aa83

File tree

5 files changed

+57
-37
lines changed

5 files changed

+57
-37
lines changed

compiler/rustc_expand/src/mbe/macro_rules.rs

+34-32
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ use crate::mbe::transcribe::transcribe;
1111
use rustc_ast as ast;
1212
use rustc_ast::token::{self, NonterminalKind, NtTT, Token, TokenKind::*};
1313
use rustc_ast::tokenstream::{DelimSpan, TokenStream};
14-
use rustc_ast::NodeId;
14+
use rustc_ast::{NodeId, DUMMY_NODE_ID};
1515
use rustc_ast_pretty::pprust;
1616
use rustc_attr::{self as attr, TransparencyError};
1717
use rustc_data_structures::fx::FxHashMap;
@@ -471,7 +471,7 @@ pub fn compile_declarative_macro(
471471
)
472472
.pop()
473473
.unwrap();
474-
valid &= check_lhs_nt_follows(&sess.parse_sess, features, &def.attrs, &tt);
474+
valid &= check_lhs_nt_follows(&sess.parse_sess, features, &def, &tt);
475475
return tt;
476476
}
477477
}
@@ -540,13 +540,13 @@ pub fn compile_declarative_macro(
540540
fn check_lhs_nt_follows(
541541
sess: &ParseSess,
542542
features: &Features,
543-
attrs: &[ast::Attribute],
543+
def: &ast::Item,
544544
lhs: &mbe::TokenTree,
545545
) -> bool {
546546
// lhs is going to be like TokenTree::Delimited(...), where the
547547
// entire lhs is those tts. Or, it can be a "bare sequence", not wrapped in parens.
548548
if let mbe::TokenTree::Delimited(_, ref tts) = *lhs {
549-
check_matcher(sess, features, attrs, &tts.tts)
549+
check_matcher(sess, features, def, &tts.tts)
550550
} else {
551551
let msg = "invalid macro matcher; matchers must be contained in balanced delimiters";
552552
sess.span_diagnostic.span_err(lhs.span(), msg);
@@ -604,13 +604,13 @@ fn check_rhs(sess: &ParseSess, rhs: &mbe::TokenTree) -> bool {
604604
fn check_matcher(
605605
sess: &ParseSess,
606606
features: &Features,
607-
attrs: &[ast::Attribute],
607+
def: &ast::Item,
608608
matcher: &[mbe::TokenTree],
609609
) -> bool {
610610
let first_sets = FirstSets::new(matcher);
611611
let empty_suffix = TokenSet::empty();
612612
let err = sess.span_diagnostic.err_count();
613-
check_matcher_core(sess, features, attrs, &first_sets, matcher, &empty_suffix);
613+
check_matcher_core(sess, features, def, &first_sets, matcher, &empty_suffix);
614614
err == sess.span_diagnostic.err_count()
615615
}
616616

@@ -857,7 +857,7 @@ impl TokenSet {
857857
fn check_matcher_core(
858858
sess: &ParseSess,
859859
features: &Features,
860-
attrs: &[ast::Attribute],
860+
def: &ast::Item,
861861
first_sets: &FirstSets,
862862
matcher: &[mbe::TokenTree],
863863
follow: &TokenSet,
@@ -903,7 +903,7 @@ fn check_matcher_core(
903903
}
904904
TokenTree::Delimited(span, ref d) => {
905905
let my_suffix = TokenSet::singleton(d.close_tt(span));
906-
check_matcher_core(sess, features, attrs, first_sets, &d.tts, &my_suffix);
906+
check_matcher_core(sess, features, def, first_sets, &d.tts, &my_suffix);
907907
// don't track non NT tokens
908908
last.replace_with_irrelevant();
909909

@@ -936,7 +936,7 @@ fn check_matcher_core(
936936
// `my_suffix` is some TokenSet that we can use
937937
// for checking the interior of `seq_rep`.
938938
let next =
939-
check_matcher_core(sess, features, attrs, first_sets, &seq_rep.tts, my_suffix);
939+
check_matcher_core(sess, features, def, first_sets, &seq_rep.tts, my_suffix);
940940
if next.maybe_empty {
941941
last.add_all(&next);
942942
} else {
@@ -956,29 +956,31 @@ fn check_matcher_core(
956956
for token in &last.tokens {
957957
if let TokenTree::MetaVarDecl(span, name, Some(kind)) = *token {
958958
for next_token in &suffix_first.tokens {
959-
// Check if the old pat is used and the next token is `|`.
960-
if let NonterminalKind::PatParam { inferred: true } = kind {
961-
if let TokenTree::Token(token) = next_token {
962-
if let BinOp(token) = token.kind {
963-
if let token::BinOpToken::Or = token {
964-
// It is suggestion to use pat_param, for example: $x:pat -> $x:pat_param.
965-
let suggestion = quoted_tt_to_string(&TokenTree::MetaVarDecl(
966-
span,
967-
name,
968-
Some(NonterminalKind::PatParam { inferred: false }),
969-
));
970-
sess.buffer_lint_with_diagnostic(
971-
&OR_PATTERNS_BACK_COMPAT,
972-
span,
973-
ast::CRATE_NODE_ID,
974-
&*format!("the meaning of the `pat` fragment specifier is changing in Rust 2021, which may affect this macro",),
975-
BuiltinLintDiagnostics::OrPatternsBackCompat(
976-
span, suggestion,
977-
),
978-
);
979-
}
980-
}
981-
}
959+
// Check if the old pat is used and the next token is `|`
960+
// to warn about incompatibility with Rust 2021.
961+
// We only emit this lint if we're parsing the original
962+
// definition of this macro_rules, not while (re)parsing
963+
// the macro when compiling another crate that is using the
964+
// macro. (See #86567.)
965+
// Macros defined in the current crate have a real node id,
966+
// whereas macros from an external crate have a dummy id.
967+
if def.id != DUMMY_NODE_ID
968+
&& matches!(kind, NonterminalKind::PatParam { inferred: true })
969+
&& matches!(next_token, TokenTree::Token(token) if token.kind == BinOp(token::BinOpToken::Or))
970+
{
971+
// It is suggestion to use pat_param, for example: $x:pat -> $x:pat_param.
972+
let suggestion = quoted_tt_to_string(&TokenTree::MetaVarDecl(
973+
span,
974+
name,
975+
Some(NonterminalKind::PatParam { inferred: false }),
976+
));
977+
sess.buffer_lint_with_diagnostic(
978+
&OR_PATTERNS_BACK_COMPAT,
979+
span,
980+
ast::CRATE_NODE_ID,
981+
"the meaning of the `pat` fragment specifier is changing in Rust 2021, which may affect this macro",
982+
BuiltinLintDiagnostics::OrPatternsBackCompat(span, suggestion),
983+
);
982984
}
983985
match is_in_follow(next_token, kind) {
984986
IsInFollow::Yes => {}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
#![crate_type = "lib"]
2+
3+
#[macro_export]
4+
macro_rules! a {
5+
($x:pat|) => ();
6+
}

src/test/ui/macros/macro-or-patterns-back-compat.fixed

+6
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,19 @@
11
// run-rustfix
2+
// aux-build:or-pattern.rs
23

34
#![deny(or_patterns_back_compat)]
45
#![allow(unused_macros)]
56

7+
#[macro_use]
8+
extern crate or_pattern;
9+
610
macro_rules! foo { ($x:pat_param | $y:pat) => {} }
711
//~^ ERROR the meaning of the `pat` fragment specifier is changing in Rust 2021, which may affect this macro
812
//~| WARN this was previously accepted
913
macro_rules! bar { ($($x:pat_param)+ | $($y:pat)+) => {} }
1014
//~^ ERROR the meaning of the `pat` fragment specifier is changing in Rust 2021, which may affect this macro
1115
//~| WARN this was previously accepted
16+
1217
macro_rules! baz { ($x:pat_param | $y:pat_param) => {} } // should be ok
1318
macro_rules! qux { ($x:pat_param | $y:pat) => {} } // should be ok
1419
macro_rules! ogg { ($x:pat_param | $y:pat_param) => {} }
@@ -30,4 +35,5 @@ fn main() {
3035
let result: Result<i64, i32> = Err(42);
3136
let int: i64 = match_any!(result, Ok(i) | Err(i) => i.into());
3237
assert_eq!(int, 42);
38+
a!(1|);
3339
}

src/test/ui/macros/macro-or-patterns-back-compat.rs

+6
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,19 @@
11
// run-rustfix
2+
// aux-build:or-pattern.rs
23

34
#![deny(or_patterns_back_compat)]
45
#![allow(unused_macros)]
56

7+
#[macro_use]
8+
extern crate or_pattern;
9+
610
macro_rules! foo { ($x:pat | $y:pat) => {} }
711
//~^ ERROR the meaning of the `pat` fragment specifier is changing in Rust 2021, which may affect this macro
812
//~| WARN this was previously accepted
913
macro_rules! bar { ($($x:pat)+ | $($y:pat)+) => {} }
1014
//~^ ERROR the meaning of the `pat` fragment specifier is changing in Rust 2021, which may affect this macro
1115
//~| WARN this was previously accepted
16+
1217
macro_rules! baz { ($x:pat_param | $y:pat_param) => {} } // should be ok
1318
macro_rules! qux { ($x:pat_param | $y:pat) => {} } // should be ok
1419
macro_rules! ogg { ($x:pat | $y:pat_param) => {} }
@@ -30,4 +35,5 @@ fn main() {
3035
let result: Result<i64, i32> = Err(42);
3136
let int: i64 = match_any!(result, Ok(i) | Err(i) => i.into());
3237
assert_eq!(int, 42);
38+
a!(1|);
3339
}

src/test/ui/macros/macro-or-patterns-back-compat.stderr

+5-5
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,19 @@
11
error: the meaning of the `pat` fragment specifier is changing in Rust 2021, which may affect this macro
2-
--> $DIR/macro-or-patterns-back-compat.rs:6:21
2+
--> $DIR/macro-or-patterns-back-compat.rs:10:21
33
|
44
LL | macro_rules! foo { ($x:pat | $y:pat) => {} }
55
| ^^^^^^ help: use pat_param to preserve semantics: `$x:pat_param`
66
|
77
note: the lint level is defined here
8-
--> $DIR/macro-or-patterns-back-compat.rs:3:9
8+
--> $DIR/macro-or-patterns-back-compat.rs:4:9
99
|
1010
LL | #![deny(or_patterns_back_compat)]
1111
| ^^^^^^^^^^^^^^^^^^^^^^^
1212
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in the 2021 edition!
1313
= note: for more information, see issue #84869 <https://github.com/rust-lang/rust/issues/84869>
1414

1515
error: the meaning of the `pat` fragment specifier is changing in Rust 2021, which may affect this macro
16-
--> $DIR/macro-or-patterns-back-compat.rs:9:23
16+
--> $DIR/macro-or-patterns-back-compat.rs:13:23
1717
|
1818
LL | macro_rules! bar { ($($x:pat)+ | $($y:pat)+) => {} }
1919
| ^^^^^^ help: use pat_param to preserve semantics: `$x:pat_param`
@@ -22,7 +22,7 @@ LL | macro_rules! bar { ($($x:pat)+ | $($y:pat)+) => {} }
2222
= note: for more information, see issue #84869 <https://github.com/rust-lang/rust/issues/84869>
2323

2424
error: the meaning of the `pat` fragment specifier is changing in Rust 2021, which may affect this macro
25-
--> $DIR/macro-or-patterns-back-compat.rs:14:21
25+
--> $DIR/macro-or-patterns-back-compat.rs:19:21
2626
|
2727
LL | macro_rules! ogg { ($x:pat | $y:pat_param) => {} }
2828
| ^^^^^^ help: use pat_param to preserve semantics: `$x:pat_param`
@@ -31,7 +31,7 @@ LL | macro_rules! ogg { ($x:pat | $y:pat_param) => {} }
3131
= note: for more information, see issue #84869 <https://github.com/rust-lang/rust/issues/84869>
3232

3333
error: the meaning of the `pat` fragment specifier is changing in Rust 2021, which may affect this macro
34-
--> $DIR/macro-or-patterns-back-compat.rs:18:26
34+
--> $DIR/macro-or-patterns-back-compat.rs:23:26
3535
|
3636
LL | ( $expr:expr , $( $( $pat:pat )|+ => $expr_arm:expr ),+ ) => {
3737
| ^^^^^^^^ help: use pat_param to preserve semantics: `$pat:pat_param`

0 commit comments

Comments
 (0)