]> git.lizzy.rs Git - rust.git/blobdiff - compiler/rustc_expand/src/expand.rs
Auto merge of #81825 - voidc:pidfd, r=joshtriplett
[rust.git] / compiler / rustc_expand / src / expand.rs
index b9d40962411428850b0252b20faddbc981594b47..09beda33483745b0c85d7b120a1265dde17a76e3 100644 (file)
@@ -12,7 +12,7 @@
 use rustc_ast::token;
 use rustc_ast::tokenstream::TokenStream;
 use rustc_ast::visit::{self, AssocCtxt, Visitor};
-use rustc_ast::{AstLike, Block, Inline, ItemKind, MacArgs};
+use rustc_ast::{AstLike, Block, Inline, ItemKind, Local, MacArgs, MacCall};
 use rustc_ast::{MacCallStmt, MacStmtStyle, MetaItemKind, ModKind, NestedMetaItem};
 use rustc_ast::{NodeId, PatKind, Path, StmtKind, Unsafe};
 use rustc_ast_pretty::pprust;
@@ -26,7 +26,7 @@
     AttemptLocalParseRecovery, ForceCollect, Parser, RecoverColon, RecoverComma,
 };
 use rustc_parse::validate_attr;
-use rustc_session::lint::builtin::UNUSED_DOC_COMMENTS;
+use rustc_session::lint::builtin::{UNUSED_ATTRIBUTES, UNUSED_DOC_COMMENTS};
 use rustc_session::lint::BuiltinLintDiagnostics;
 use rustc_session::parse::{feature_err, ParseSess};
 use rustc_session::Limit;
@@ -754,7 +754,7 @@ fn expand_invoc(
                     }
                 }
                 SyntaxExtensionKind::NonMacroAttr { mark_used } => {
-                    self.cx.sess.mark_attr_known(&attr);
+                    self.cx.expanded_inert_attrs.mark(&attr);
                     if *mark_used {
                         self.cx.sess.mark_attr_used(&attr);
                     }
@@ -1040,7 +1040,7 @@ fn take_first_attr(
         item.visit_attrs(|attrs| {
             attr = attrs
                 .iter()
-                .position(|a| !self.cx.sess.is_attr_known(a) && !is_builtin_attr(a))
+                .position(|a| !self.cx.expanded_inert_attrs.is_marked(a) && !is_builtin_attr(a))
                 .map(|attr_pos| {
                     let attr = attrs.remove(attr_pos);
                     let following_derives = attrs[attr_pos..]
@@ -1070,7 +1070,7 @@ fn configure<T: AstLike>(&mut self, node: T) -> Option<T> {
 
     // Detect use of feature-gated or invalid attributes on macro invocations
     // since they will not be detected after macro expansion.
-    fn check_attributes(&mut self, attrs: &[ast::Attribute]) {
+    fn check_attributes(&mut self, attrs: &[ast::Attribute], call: &MacCall) {
         let features = self.cx.ecfg.features.unwrap();
         let mut attrs = attrs.iter().peekable();
         let mut span: Option<Span> = None;
@@ -1085,19 +1085,73 @@ fn check_attributes(&mut self, attrs: &[ast::Attribute]) {
                 continue;
             }
 
-            if attr.doc_str().is_some() {
+            if attr.is_doc_comment() {
                 self.cx.sess.parse_sess.buffer_lint_with_diagnostic(
                     &UNUSED_DOC_COMMENTS,
                     current_span,
-                    ast::CRATE_NODE_ID,
+                    self.cx.current_expansion.lint_node_id,
                     "unused doc comment",
                     BuiltinLintDiagnostics::UnusedDocComment(attr.span),
                 );
+            } else if rustc_attr::is_builtin_attr(attr) {
+                let attr_name = attr.ident().unwrap().name;
+                // `#[cfg]` and `#[cfg_attr]` are special - they are
+                // eagerly evaluated.
+                if attr_name != sym::cfg && attr_name != sym::cfg_attr {
+                    self.cx.sess.parse_sess.buffer_lint_with_diagnostic(
+                        &UNUSED_ATTRIBUTES,
+                        attr.span,
+                        self.cx.current_expansion.lint_node_id,
+                        &format!("unused attribute `{}`", attr_name),
+                        BuiltinLintDiagnostics::UnusedBuiltinAttribute {
+                            attr_name,
+                            macro_name: pprust::path_to_string(&call.path),
+                            invoc_span: call.path.span,
+                        },
+                    );
+                }
             }
         }
     }
 }
 
+/// Wraps a call to `noop_visit_*` / `noop_flat_map_*`
+/// for an AST node that supports attributes
+/// (see the `Annotatable` enum)
+/// This method assigns a `NodeId`, and sets that `NodeId`
+/// as our current 'lint node id'. If a macro call is found
+/// inside this AST node, we will use this AST node's `NodeId`
+/// to emit lints associated with that macro (allowing
+/// `#[allow]` / `#[deny]` to be applied close to
+/// the macro invocation).
+///
+/// Do *not* call this for a macro AST node
+/// (e.g. `ExprKind::MacCall`) - we cannot emit lints
+/// at these AST nodes, since they are removed and
+/// replaced with the result of macro expansion.
+///
+/// All other `NodeId`s are assigned by `visit_id`.
+/// * `self` is the 'self' parameter for the current method,
+/// * `id` is a mutable reference to the `NodeId` field
+///    of the current AST node.
+/// * `closure` is a closure that executes the
+///   `noop_visit_*` / `noop_flat_map_*` method
+///   for the current AST node.
+macro_rules! assign_id {
+    ($self:ident, $id:expr, $closure:expr) => {{
+        let old_id = $self.cx.current_expansion.lint_node_id;
+        if $self.monotonic {
+            debug_assert_eq!(*$id, ast::DUMMY_NODE_ID);
+            let new_id = $self.cx.resolver.next_node_id();
+            *$id = new_id;
+            $self.cx.current_expansion.lint_node_id = new_id;
+        }
+        let ret = ($closure)();
+        $self.cx.current_expansion.lint_node_id = old_id;
+        ret
+    }};
+}
+
 impl<'a, 'b> MutVisitor for InvocationCollector<'a, 'b> {
     fn visit_expr(&mut self, expr: &mut P<ast::Expr>) {
         self.cfg.configure_expr(expr);
@@ -1115,15 +1169,22 @@ fn visit_expr(&mut self, expr: &mut P<ast::Expr>) {
             }
 
             if let ast::ExprKind::MacCall(mac) = expr.kind {
-                self.check_attributes(&expr.attrs);
+                self.check_attributes(&expr.attrs, &mac);
                 self.collect_bang(mac, expr.span, AstFragmentKind::Expr).make_expr().into_inner()
             } else {
-                ensure_sufficient_stack(|| noop_visit_expr(&mut expr, self));
+                assign_id!(self, &mut expr.id, || {
+                    ensure_sufficient_stack(|| noop_visit_expr(&mut expr, self));
+                });
                 expr
             }
         });
     }
 
+    // This is needed in order to set `lint_node_id` for `let` statements
+    fn visit_local(&mut self, local: &mut P<Local>) {
+        assign_id!(self, &mut local.id, || noop_visit_local(local, self));
+    }
+
     fn flat_map_arm(&mut self, arm: ast::Arm) -> SmallVec<[ast::Arm; 1]> {
         let mut arm = configure!(self, arm);
 
@@ -1133,7 +1194,7 @@ fn visit_expr(&mut self, expr: &mut P<ast::Expr>) {
                 .make_arms();
         }
 
-        noop_flat_map_arm(arm, self)
+        assign_id!(self, &mut arm.id, || noop_flat_map_arm(arm, self))
     }
 
     fn flat_map_expr_field(&mut self, field: ast::ExprField) -> SmallVec<[ast::ExprField; 1]> {
@@ -1145,7 +1206,7 @@ fn visit_expr(&mut self, expr: &mut P<ast::Expr>) {
                 .make_expr_fields();
         }
 
-        noop_flat_map_expr_field(field, self)
+        assign_id!(self, &mut field.id, || noop_flat_map_expr_field(field, self))
     }
 
     fn flat_map_pat_field(&mut self, fp: ast::PatField) -> SmallVec<[ast::PatField; 1]> {
@@ -1157,7 +1218,7 @@ fn visit_expr(&mut self, expr: &mut P<ast::Expr>) {
                 .make_pat_fields();
         }
 
-        noop_flat_map_pat_field(fp, self)
+        assign_id!(self, &mut fp.id, || noop_flat_map_pat_field(fp, self))
     }
 
     fn flat_map_param(&mut self, p: ast::Param) -> SmallVec<[ast::Param; 1]> {
@@ -1169,7 +1230,7 @@ fn visit_expr(&mut self, expr: &mut P<ast::Expr>) {
                 .make_params();
         }
 
-        noop_flat_map_param(p, self)
+        assign_id!(self, &mut p.id, || noop_flat_map_param(p, self))
     }
 
     fn flat_map_field_def(&mut self, sf: ast::FieldDef) -> SmallVec<[ast::FieldDef; 1]> {
@@ -1181,7 +1242,7 @@ fn visit_expr(&mut self, expr: &mut P<ast::Expr>) {
                 .make_field_defs();
         }
 
-        noop_flat_map_field_def(sf, self)
+        assign_id!(self, &mut sf.id, || noop_flat_map_field_def(sf, self))
     }
 
     fn flat_map_variant(&mut self, variant: ast::Variant) -> SmallVec<[ast::Variant; 1]> {
@@ -1193,7 +1254,7 @@ fn visit_expr(&mut self, expr: &mut P<ast::Expr>) {
                 .make_variants();
         }
 
-        noop_flat_map_variant(variant, self)
+        assign_id!(self, &mut variant.id, || noop_flat_map_variant(variant, self))
     }
 
     fn filter_map_expr(&mut self, expr: P<ast::Expr>) -> Option<P<ast::Expr>> {
@@ -1209,14 +1270,16 @@ fn filter_map_expr(&mut self, expr: P<ast::Expr>) -> Option<P<ast::Expr>> {
             }
 
             if let ast::ExprKind::MacCall(mac) = expr.kind {
-                self.check_attributes(&expr.attrs);
+                self.check_attributes(&expr.attrs, &mac);
                 self.collect_bang(mac, expr.span, AstFragmentKind::OptExpr)
                     .make_opt_expr()
                     .map(|expr| expr.into_inner())
             } else {
-                Some({
-                    noop_visit_expr(&mut expr, self);
-                    expr
+                assign_id!(self, &mut expr.id, || {
+                    Some({
+                        noop_visit_expr(&mut expr, self);
+                        expr
+                    })
                 })
             }
         })
@@ -1250,7 +1313,7 @@ fn visit_pat(&mut self, pat: &mut P<ast::Pat>) {
 
         if let StmtKind::MacCall(mac) = stmt.kind {
             let MacCallStmt { mac, style, attrs, tokens: _ } = mac.into_inner();
-            self.check_attributes(&attrs);
+            self.check_attributes(&attrs, &mac);
             let mut placeholder =
                 self.collect_bang(mac, stmt.span, AstFragmentKind::Stmts).make_stmts();
 
@@ -1265,12 +1328,30 @@ fn visit_pat(&mut self, pat: &mut P<ast::Pat>) {
             return placeholder;
         }
 
+        // The only way that we can end up with a `MacCall` expression statement,
+        // (as opposed to a `StmtKind::MacCall`) is if we have a macro as the
+        // traiing expression in a block (e.g. `fn foo() { my_macro!() }`).
+        // Record this information, so that we can report a more specific
+        // `SEMICOLON_IN_EXPRESSIONS_FROM_MACROS` lint if needed.
+        // See #78991 for an investigation of treating macros in this position
+        // as statements, rather than expressions, during parsing.
+        if let StmtKind::Expr(expr) = &stmt.kind {
+            if matches!(**expr, ast::Expr { kind: ast::ExprKind::MacCall(..), .. }) {
+                self.cx.current_expansion.is_trailing_mac = true;
+            }
+        }
+
         // The placeholder expander gives ids to statements, so we avoid folding the id here.
+        // We don't use `assign_id!` - it will be called when we visit statement's contents
+        // (e.g. an expression, item, or local)
         let ast::Stmt { id, kind, span } = stmt;
-        noop_flat_map_stmt_kind(kind, self)
+        let res = noop_flat_map_stmt_kind(kind, self)
             .into_iter()
             .map(|kind| ast::Stmt { id, kind, span })
-            .collect()
+            .collect();
+
+        self.cx.current_expansion.is_trailing_mac = false;
+        res
     }
 
     fn visit_block(&mut self, block: &mut P<Block>) {
@@ -1296,9 +1377,9 @@ fn visit_block(&mut self, block: &mut P<Block>) {
         let span = item.span;
 
         match item.kind {
-            ast::ItemKind::MacCall(..) => {
+            ast::ItemKind::MacCall(ref mac) => {
+                self.check_attributes(&attrs, &mac);
                 item.attrs = attrs;
-                self.check_attributes(&item.attrs);
                 item.and_then(|item| match item.kind {
                     ItemKind::MacCall(mac) => {
                         self.collect_bang(mac, span, AstFragmentKind::Items).make_items()
@@ -1377,7 +1458,7 @@ fn visit_block(&mut self, block: &mut P<Block>) {
                 let orig_dir_ownership =
                     mem::replace(&mut self.cx.current_expansion.dir_ownership, dir_ownership);
 
-                let result = noop_flat_map_item(item, self);
+                let result = assign_id!(self, &mut item.id, || noop_flat_map_item(item, self));
 
                 // Restore the module info.
                 self.cx.current_expansion.dir_ownership = orig_dir_ownership;
@@ -1387,7 +1468,12 @@ fn visit_block(&mut self, block: &mut P<Block>) {
             }
             _ => {
                 item.attrs = attrs;
-                noop_flat_map_item(item, self)
+                // The crate root is special - don't assign an ID to it.
+                if !(matches!(item.kind, ast::ItemKind::Mod(..)) && ident == Ident::invalid()) {
+                    assign_id!(self, &mut item.id, || noop_flat_map_item(item, self))
+                } else {
+                    noop_flat_map_item(item, self)
+                }
             }
         }
     }
@@ -1402,8 +1488,8 @@ fn visit_block(&mut self, block: &mut P<Block>) {
         }
 
         match item.kind {
-            ast::AssocItemKind::MacCall(..) => {
-                self.check_attributes(&item.attrs);
+            ast::AssocItemKind::MacCall(ref mac) => {
+                self.check_attributes(&item.attrs, &mac);
                 item.and_then(|item| match item.kind {
                     ast::AssocItemKind::MacCall(mac) => self
                         .collect_bang(mac, item.span, AstFragmentKind::TraitItems)
@@ -1411,7 +1497,9 @@ fn visit_block(&mut self, block: &mut P<Block>) {
                     _ => unreachable!(),
                 })
             }
-            _ => noop_flat_map_assoc_item(item, self),
+            _ => {
+                assign_id!(self, &mut item.id, || noop_flat_map_assoc_item(item, self))
+            }
         }
     }
 
@@ -1425,8 +1513,8 @@ fn visit_block(&mut self, block: &mut P<Block>) {
         }
 
         match item.kind {
-            ast::AssocItemKind::MacCall(..) => {
-                self.check_attributes(&item.attrs);
+            ast::AssocItemKind::MacCall(ref mac) => {
+                self.check_attributes(&item.attrs, &mac);
                 item.and_then(|item| match item.kind {
                     ast::AssocItemKind::MacCall(mac) => self
                         .collect_bang(mac, item.span, AstFragmentKind::ImplItems)
@@ -1434,7 +1522,9 @@ fn visit_block(&mut self, block: &mut P<Block>) {
                     _ => unreachable!(),
                 })
             }
-            _ => noop_flat_map_assoc_item(item, self),
+            _ => {
+                assign_id!(self, &mut item.id, || noop_flat_map_assoc_item(item, self))
+            }
         }
     }
 
@@ -1469,8 +1559,8 @@ fn flat_map_foreign_item(
         }
 
         match foreign_item.kind {
-            ast::ForeignItemKind::MacCall(..) => {
-                self.check_attributes(&foreign_item.attrs);
+            ast::ForeignItemKind::MacCall(ref mac) => {
+                self.check_attributes(&foreign_item.attrs, &mac);
                 foreign_item.and_then(|item| match item.kind {
                     ast::ForeignItemKind::MacCall(mac) => self
                         .collect_bang(mac, item.span, AstFragmentKind::ForeignItems)
@@ -1478,7 +1568,12 @@ fn flat_map_foreign_item(
                     _ => unreachable!(),
                 })
             }
-            _ => noop_flat_map_foreign_item(foreign_item, self),
+            _ => {
+                assign_id!(self, &mut foreign_item.id, || noop_flat_map_foreign_item(
+                    foreign_item,
+                    self
+                ))
+            }
         }
     }
 
@@ -1498,13 +1593,14 @@ fn flat_map_generic_param(
                 .make_generic_params();
         }
 
-        noop_flat_map_generic_param(param, self)
+        assign_id!(self, &mut param.id, || noop_flat_map_generic_param(param, self))
     }
 
     fn visit_id(&mut self, id: &mut ast::NodeId) {
-        if self.monotonic {
-            debug_assert_eq!(*id, ast::DUMMY_NODE_ID);
-            *id = self.cx.resolver.next_node_id()
+        // We may have already assigned a `NodeId`
+        // by calling `assign_id`
+        if self.monotonic && *id == ast::DUMMY_NODE_ID {
+            *id = self.cx.resolver.next_node_id();
         }
     }
 }