Don't lint :pat when re-parsing a macro from another crate.
This commit is contained in:
parent
b6f3cb9502
commit
06db210459
5 changed files with 57 additions and 37 deletions
|
@ -11,7 +11,7 @@ use crate::mbe::transcribe::transcribe;
|
|||
use rustc_ast as ast;
|
||||
use rustc_ast::token::{self, NonterminalKind, NtTT, Token, TokenKind::*};
|
||||
use rustc_ast::tokenstream::{DelimSpan, TokenStream};
|
||||
use rustc_ast::NodeId;
|
||||
use rustc_ast::{NodeId, DUMMY_NODE_ID};
|
||||
use rustc_ast_pretty::pprust;
|
||||
use rustc_attr::{self as attr, TransparencyError};
|
||||
use rustc_data_structures::fx::FxHashMap;
|
||||
|
@ -471,7 +471,7 @@ pub fn compile_declarative_macro(
|
|||
)
|
||||
.pop()
|
||||
.unwrap();
|
||||
valid &= check_lhs_nt_follows(&sess.parse_sess, features, &def.attrs, &tt);
|
||||
valid &= check_lhs_nt_follows(&sess.parse_sess, features, &def, &tt);
|
||||
return tt;
|
||||
}
|
||||
}
|
||||
|
@ -540,13 +540,13 @@ pub fn compile_declarative_macro(
|
|||
fn check_lhs_nt_follows(
|
||||
sess: &ParseSess,
|
||||
features: &Features,
|
||||
attrs: &[ast::Attribute],
|
||||
def: &ast::Item,
|
||||
lhs: &mbe::TokenTree,
|
||||
) -> bool {
|
||||
// lhs is going to be like TokenTree::Delimited(...), where the
|
||||
// entire lhs is those tts. Or, it can be a "bare sequence", not wrapped in parens.
|
||||
if let mbe::TokenTree::Delimited(_, ref tts) = *lhs {
|
||||
check_matcher(sess, features, attrs, &tts.tts)
|
||||
check_matcher(sess, features, def, &tts.tts)
|
||||
} else {
|
||||
let msg = "invalid macro matcher; matchers must be contained in balanced delimiters";
|
||||
sess.span_diagnostic.span_err(lhs.span(), msg);
|
||||
|
@ -604,13 +604,13 @@ fn check_rhs(sess: &ParseSess, rhs: &mbe::TokenTree) -> bool {
|
|||
fn check_matcher(
|
||||
sess: &ParseSess,
|
||||
features: &Features,
|
||||
attrs: &[ast::Attribute],
|
||||
def: &ast::Item,
|
||||
matcher: &[mbe::TokenTree],
|
||||
) -> bool {
|
||||
let first_sets = FirstSets::new(matcher);
|
||||
let empty_suffix = TokenSet::empty();
|
||||
let err = sess.span_diagnostic.err_count();
|
||||
check_matcher_core(sess, features, attrs, &first_sets, matcher, &empty_suffix);
|
||||
check_matcher_core(sess, features, def, &first_sets, matcher, &empty_suffix);
|
||||
err == sess.span_diagnostic.err_count()
|
||||
}
|
||||
|
||||
|
@ -857,7 +857,7 @@ impl TokenSet {
|
|||
fn check_matcher_core(
|
||||
sess: &ParseSess,
|
||||
features: &Features,
|
||||
attrs: &[ast::Attribute],
|
||||
def: &ast::Item,
|
||||
first_sets: &FirstSets,
|
||||
matcher: &[mbe::TokenTree],
|
||||
follow: &TokenSet,
|
||||
|
@ -903,7 +903,7 @@ fn check_matcher_core(
|
|||
}
|
||||
TokenTree::Delimited(span, ref d) => {
|
||||
let my_suffix = TokenSet::singleton(d.close_tt(span));
|
||||
check_matcher_core(sess, features, attrs, first_sets, &d.tts, &my_suffix);
|
||||
check_matcher_core(sess, features, def, first_sets, &d.tts, &my_suffix);
|
||||
// don't track non NT tokens
|
||||
last.replace_with_irrelevant();
|
||||
|
||||
|
@ -936,7 +936,7 @@ fn check_matcher_core(
|
|||
// `my_suffix` is some TokenSet that we can use
|
||||
// for checking the interior of `seq_rep`.
|
||||
let next =
|
||||
check_matcher_core(sess, features, attrs, first_sets, &seq_rep.tts, my_suffix);
|
||||
check_matcher_core(sess, features, def, first_sets, &seq_rep.tts, my_suffix);
|
||||
if next.maybe_empty {
|
||||
last.add_all(&next);
|
||||
} else {
|
||||
|
@ -956,29 +956,31 @@ fn check_matcher_core(
|
|||
for token in &last.tokens {
|
||||
if let TokenTree::MetaVarDecl(span, name, Some(kind)) = *token {
|
||||
for next_token in &suffix_first.tokens {
|
||||
// Check if the old pat is used and the next token is `|`.
|
||||
if let NonterminalKind::PatParam { inferred: true } = kind {
|
||||
if let TokenTree::Token(token) = next_token {
|
||||
if let BinOp(token) = token.kind {
|
||||
if let token::BinOpToken::Or = token {
|
||||
// It is suggestion to use pat_param, for example: $x:pat -> $x:pat_param.
|
||||
let suggestion = quoted_tt_to_string(&TokenTree::MetaVarDecl(
|
||||
span,
|
||||
name,
|
||||
Some(NonterminalKind::PatParam { inferred: false }),
|
||||
));
|
||||
sess.buffer_lint_with_diagnostic(
|
||||
&OR_PATTERNS_BACK_COMPAT,
|
||||
span,
|
||||
ast::CRATE_NODE_ID,
|
||||
&*format!("the meaning of the `pat` fragment specifier is changing in Rust 2021, which may affect this macro",),
|
||||
BuiltinLintDiagnostics::OrPatternsBackCompat(
|
||||
span, suggestion,
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
// Check if the old pat is used and the next token is `|`
|
||||
// to warn about incompatibility with Rust 2021.
|
||||
// We only emit this lint if we're parsing the original
|
||||
// definition of this macro_rules, not while (re)parsing
|
||||
// the macro when compiling another crate that is using the
|
||||
// macro. (See #86567.)
|
||||
// Macros defined in the current crate have a real node id,
|
||||
// whereas macros from an external crate have a dummy id.
|
||||
if def.id != DUMMY_NODE_ID
|
||||
&& matches!(kind, NonterminalKind::PatParam { inferred: true })
|
||||
&& matches!(next_token, TokenTree::Token(token) if token.kind == BinOp(token::BinOpToken::Or))
|
||||
{
|
||||
// It is suggestion to use pat_param, for example: $x:pat -> $x:pat_param.
|
||||
let suggestion = quoted_tt_to_string(&TokenTree::MetaVarDecl(
|
||||
span,
|
||||
name,
|
||||
Some(NonterminalKind::PatParam { inferred: false }),
|
||||
));
|
||||
sess.buffer_lint_with_diagnostic(
|
||||
&OR_PATTERNS_BACK_COMPAT,
|
||||
span,
|
||||
ast::CRATE_NODE_ID,
|
||||
"the meaning of the `pat` fragment specifier is changing in Rust 2021, which may affect this macro",
|
||||
BuiltinLintDiagnostics::OrPatternsBackCompat(span, suggestion),
|
||||
);
|
||||
}
|
||||
match is_in_follow(next_token, kind) {
|
||||
IsInFollow::Yes => {}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue