]> git.proxmox.com Git - rustc.git/blobdiff - compiler/rustc_expand/src/mbe/macro_rules.rs
New upstream version 1.55.0+dfsg1
[rustc.git] / compiler / rustc_expand / src / mbe / macro_rules.rs
index abad190b072ab3081cc8ce064bdd659c147e55c8..7f985af364d7dbf34369be8461e25bb690d69a91 100644 (file)
@@ -11,14 +11,16 @@ 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;
 use rustc_data_structures::sync::Lrc;
 use rustc_errors::{Applicability, DiagnosticBuilder};
 use rustc_feature::Features;
-use rustc_lint_defs::builtin::{OR_PATTERNS_BACK_COMPAT, SEMICOLON_IN_EXPRESSIONS_FROM_MACROS};
+use rustc_lint_defs::builtin::{
+    RUST_2021_INCOMPATIBLE_OR_PATTERNS, SEMICOLON_IN_EXPRESSIONS_FROM_MACROS,
+};
 use rustc_lint_defs::BuiltinLintDiagnostics;
 use rustc_parse::parser::Parser;
 use rustc_session::parse::ParseSess;
@@ -287,7 +289,6 @@ fn generic_extension<'cx>(
 
                 let mut p = Parser::new(sess, tts, false, None);
                 p.last_type_ascription = cx.current_expansion.prior_type_ascription;
-                let lint_node_id = cx.resolver.lint_node_id(cx.current_expansion.id);
 
                 // Let the context choose how to interpret the result.
                 // Weird, but useful for X-macros.
@@ -299,7 +300,7 @@ fn generic_extension<'cx>(
                     // macro leaves unparsed tokens.
                     site_span: sp,
                     macro_ident: name,
-                    lint_node_id,
+                    lint_node_id: cx.current_expansion.lint_node_id,
                     arm_span,
                 });
             }
@@ -471,7 +472,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 +541,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 +605,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 +858,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 +904,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 +937,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 +957,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(
+                            &RUST_2021_INCOMPATIBLE_OR_PATTERNS,
+                            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 => {}