about summary refs log tree commit diff
path: root/src/tools/rust-analyzer/crates/hir-def
diff options
context:
space:
mode:
authorLaurențiu Nicola <lnicola@dend.ro>2024-02-18 09:41:20 +0200
committerLaurențiu Nicola <lnicola@dend.ro>2024-02-18 09:41:20 +0200
commitb72ae2c9ea7781ce34fe8f8af706d0431e51adc3 (patch)
tree8c17fcfd5aaba570e40ff1ea59def1c6ad04322f /src/tools/rust-analyzer/crates/hir-def
parentd3df8ff85121146f2ac5e863e0c9eaba4bf35d32 (diff)
parentac998a74b3c8ff4b81c3eeb9a18811d4cc76226d (diff)
downloadrust-b72ae2c9ea7781ce34fe8f8af706d0431e51adc3.tar.gz
rust-b72ae2c9ea7781ce34fe8f8af706d0431e51adc3.zip
Merge commit 'ac998a74b3c8ff4b81c3eeb9a18811d4cc76226d' into sync-from-ra
Diffstat (limited to 'src/tools/rust-analyzer/crates/hir-def')
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/attr.rs42
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/body/lower.rs11
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/body/pretty.rs6
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/body/scope.rs1
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/data.rs12
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/expander.rs6
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/find_path.rs63
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/hir.rs9
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/macro_expansion_tests/mbe/matching.rs2
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/macro_expansion_tests/mbe/meta_syntax.rs42
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/macro_expansion_tests/mbe/metavar_expr.rs6
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/macro_expansion_tests/mbe/regression.rs54
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/macro_expansion_tests/mbe/tt_conversion.rs4
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/macro_expansion_tests/mod.rs1
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/nameres/collector.rs95
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/nameres/diagnostics.rs3
16 files changed, 257 insertions, 100 deletions
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/attr.rs b/src/tools/rust-analyzer/crates/hir-def/src/attr.rs
index c91a5497262..519706c65f2 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/attr.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/attr.rs
@@ -377,27 +377,39 @@ impl AttrsWithOwner {
             AttrDefId::GenericParamId(it) => match it {
                 GenericParamId::ConstParamId(it) => {
                     let src = it.parent().child_source(db);
-                    RawAttrs::from_attrs_owner(
-                        db.upcast(),
-                        src.with_value(&src.value[it.local_id()]),
-                        db.span_map(src.file_id).as_ref(),
-                    )
+                    // FIXME: We should be never getting `None` here.
+                    match src.value.get(it.local_id()) {
+                        Some(val) => RawAttrs::from_attrs_owner(
+                            db.upcast(),
+                            src.with_value(val),
+                            db.span_map(src.file_id).as_ref(),
+                        ),
+                        None => RawAttrs::EMPTY,
+                    }
                 }
                 GenericParamId::TypeParamId(it) => {
                     let src = it.parent().child_source(db);
-                    RawAttrs::from_attrs_owner(
-                        db.upcast(),
-                        src.with_value(&src.value[it.local_id()]),
-                        db.span_map(src.file_id).as_ref(),
-                    )
+                    // FIXME: We should be never getting `None` here.
+                    match src.value.get(it.local_id()) {
+                        Some(val) => RawAttrs::from_attrs_owner(
+                            db.upcast(),
+                            src.with_value(val),
+                            db.span_map(src.file_id).as_ref(),
+                        ),
+                        None => RawAttrs::EMPTY,
+                    }
                 }
                 GenericParamId::LifetimeParamId(it) => {
                     let src = it.parent.child_source(db);
-                    RawAttrs::from_attrs_owner(
-                        db.upcast(),
-                        src.with_value(&src.value[it.local_id]),
-                        db.span_map(src.file_id).as_ref(),
-                    )
+                    // FIXME: We should be never getting `None` here.
+                    match src.value.get(it.local_id) {
+                        Some(val) => RawAttrs::from_attrs_owner(
+                            db.upcast(),
+                            src.with_value(val),
+                            db.span_map(src.file_id).as_ref(),
+                        ),
+                        None => RawAttrs::EMPTY,
+                    }
                 }
             },
             AttrDefId::ExternBlockId(it) => attrs_from_item_tree_loc(db, it),
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/body/lower.rs b/src/tools/rust-analyzer/crates/hir-def/src/body/lower.rs
index 29ac666277d..5dc5fedd230 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/body/lower.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/body/lower.rs
@@ -416,6 +416,11 @@ impl ExprCollector<'_> {
                 let expr = e.expr().map(|e| self.collect_expr(e));
                 self.alloc_expr(Expr::Return { expr }, syntax_ptr)
             }
+            ast::Expr::BecomeExpr(e) => {
+                let expr =
+                    e.expr().map(|e| self.collect_expr(e)).unwrap_or_else(|| self.missing_expr());
+                self.alloc_expr(Expr::Become { expr }, syntax_ptr)
+            }
             ast::Expr::YieldExpr(e) => {
                 self.is_lowering_coroutine = true;
                 let expr = e.expr().map(|e| self.collect_expr(e));
@@ -1000,10 +1005,6 @@ impl ExprCollector<'_> {
                         krate: *krate,
                     });
                 }
-                Some(ExpandError::RecursionOverflowPoisoned) => {
-                    // Recursion limit has been reached in the macro expansion tree, but not in
-                    // this very macro call. Don't add diagnostics to avoid duplication.
-                }
                 Some(err) => {
                     self.source_map.diagnostics.push(BodyDiagnostic::MacroError {
                         node: InFile::new(outer_file, syntax_ptr),
@@ -1112,7 +1113,7 @@ impl ExprCollector<'_> {
                     statements.push(Statement::Expr { expr, has_semi });
                 }
             }
-            ast::Stmt::Item(_item) => (),
+            ast::Stmt::Item(_item) => statements.push(Statement::Item),
         }
     }
 
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/body/pretty.rs b/src/tools/rust-analyzer/crates/hir-def/src/body/pretty.rs
index 4afb4086517..7007dea638e 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/body/pretty.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/body/pretty.rs
@@ -261,6 +261,11 @@ impl Printer<'_> {
                     self.print_expr(*expr);
                 }
             }
+            Expr::Become { expr } => {
+                w!(self, "become");
+                self.whitespace();
+                self.print_expr(*expr);
+            }
             Expr::Yield { expr } => {
                 w!(self, "yield");
                 if let Some(expr) = expr {
@@ -623,6 +628,7 @@ impl Printer<'_> {
                 }
                 wln!(self);
             }
+            Statement::Item => (),
         }
     }
 
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/body/scope.rs b/src/tools/rust-analyzer/crates/hir-def/src/body/scope.rs
index ab623250d40..69b82ae871a 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/body/scope.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/body/scope.rs
@@ -197,6 +197,7 @@ fn compute_block_scopes(
             Statement::Expr { expr, .. } => {
                 compute_expr_scopes(*expr, body, scopes, scope);
             }
+            Statement::Item => (),
         }
     }
     if let Some(expr) = tail {
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/data.rs b/src/tools/rust-analyzer/crates/hir-def/src/data.rs
index 7ce05b64d02..f506864902c 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/data.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/data.rs
@@ -634,7 +634,6 @@ impl<'a> AssocItemCollector<'a> {
                     attr,
                 ) {
                     Ok(ResolvedAttr::Macro(call_id)) => {
-                        self.attr_calls.push((ast_id, call_id));
                         // If proc attribute macro expansion is disabled, skip expanding it here
                         if !self.db.expand_proc_attr_macros() {
                             continue 'attrs;
@@ -647,10 +646,21 @@ impl<'a> AssocItemCollector<'a> {
                             // disabled. This is analogous to the handling in
                             // `DefCollector::collect_macros`.
                             if exp.is_dummy() {
+                                self.diagnostics.push(DefDiagnostic::unresolved_proc_macro(
+                                    self.module_id.local_id,
+                                    loc.kind,
+                                    loc.def.krate,
+                                ));
+
+                                continue 'attrs;
+                            }
+                            if exp.is_disabled() {
                                 continue 'attrs;
                             }
                         }
 
+                        self.attr_calls.push((ast_id, call_id));
+
                         let res =
                             self.expander.enter_expand_id::<ast::MacroItems>(self.db, call_id);
                         self.collect_macro_items(res, &|| loc.kind.clone());
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/expander.rs b/src/tools/rust-analyzer/crates/hir-def/src/expander.rs
index b83feeedc34..b99df1ed593 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/expander.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/expander.rs
@@ -140,13 +140,11 @@ impl Expander {
             // The overflow error should have been reported when it occurred (see the next branch),
             // so don't return overflow error here to avoid diagnostics duplication.
             cov_mark::hit!(overflow_but_not_me);
-            return ExpandResult::only_err(ExpandError::RecursionOverflowPoisoned);
+            return ExpandResult::ok(None);
         } else if self.recursion_limit.check(self.recursion_depth as usize + 1).is_err() {
             self.recursion_depth = u32::MAX;
             cov_mark::hit!(your_stack_belongs_to_me);
-            return ExpandResult::only_err(ExpandError::other(
-                "reached recursion limit during macro expansion",
-            ));
+            return ExpandResult::only_err(ExpandError::RecursionOverflow);
         }
 
         let ExpandResult { value, err } = op(self);
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/find_path.rs b/src/tools/rust-analyzer/crates/hir-def/src/find_path.rs
index 2e137f67b4c..26247ba5b50 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/find_path.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/find_path.rs
@@ -447,18 +447,25 @@ fn select_best_path(
     }
     const STD_CRATES: [Name; 3] = [known::std, known::core, known::alloc];
 
-    let choose = |new_path: (ModPath, _), old_path: (ModPath, _)| {
-        let new_has_prelude = new_path.0.segments().iter().any(|seg| seg == &known::prelude);
-        let old_has_prelude = old_path.0.segments().iter().any(|seg| seg == &known::prelude);
+    let choose = |new: (ModPath, _), old: (ModPath, _)| {
+        let (new_path, _) = &new;
+        let (old_path, _) = &old;
+        let new_has_prelude = new_path.segments().iter().any(|seg| seg == &known::prelude);
+        let old_has_prelude = old_path.segments().iter().any(|seg| seg == &known::prelude);
         match (new_has_prelude, old_has_prelude, prefer_prelude) {
-            (true, false, true) | (false, true, false) => new_path,
-            (true, false, false) | (false, true, true) => old_path,
-            // no prelude difference in the paths, so pick the smaller one
+            (true, false, true) | (false, true, false) => new,
+            (true, false, false) | (false, true, true) => old,
+            // no prelude difference in the paths, so pick the shorter one
             (true, true, _) | (false, false, _) => {
-                if new_path.0.len() < old_path.0.len() {
-                    new_path
+                let new_path_is_shorter = new_path
+                    .len()
+                    .cmp(&old_path.len())
+                    .then_with(|| new_path.textual_len().cmp(&old_path.textual_len()))
+                    .is_lt();
+                if new_path_is_shorter {
+                    new
                 } else {
-                    old_path
+                    old
                 }
             }
         }
@@ -469,8 +476,8 @@ fn select_best_path(
             let rank = match prefer_no_std {
                 false => |name: &Name| match name {
                     name if name == &known::core => 0,
-                    name if name == &known::alloc => 0,
-                    name if name == &known::std => 1,
+                    name if name == &known::alloc => 1,
+                    name if name == &known::std => 2,
                     _ => unreachable!(),
                 },
                 true => |name: &Name| match name {
@@ -1539,4 +1546,38 @@ pub mod foo {
             "krate::prelude::Foo",
         );
     }
+
+    #[test]
+    fn respect_segment_length() {
+        check_found_path(
+            r#"
+//- /main.rs crate:main deps:petgraph
+$0
+//- /petgraph.rs crate:petgraph
+pub mod graph {
+    pub use crate::graph_impl::{
+        NodeIndex
+    };
+}
+
+mod graph_impl {
+    pub struct NodeIndex<Ix>(Ix);
+}
+
+pub mod stable_graph {
+    #[doc(no_inline)]
+    pub use crate::graph::{NodeIndex};
+}
+
+pub mod prelude {
+    #[doc(no_inline)]
+    pub use crate::graph::{NodeIndex};
+}
+"#,
+            "petgraph::graph::NodeIndex",
+            "petgraph::graph::NodeIndex",
+            "petgraph::graph::NodeIndex",
+            "petgraph::graph::NodeIndex",
+        );
+    }
 }
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/hir.rs b/src/tools/rust-analyzer/crates/hir-def/src/hir.rs
index ac44d379415..34b2910b4f5 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/hir.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/hir.rs
@@ -182,6 +182,7 @@ pub enum Expr {
         tail: Option<ExprId>,
     },
     Const(ConstBlockId),
+    // FIXME: Fold this into Block with an unsafe flag?
     Unsafe {
         id: Option<BlockId>,
         statements: Box<[Statement]>,
@@ -216,6 +217,9 @@ pub enum Expr {
     Return {
         expr: Option<ExprId>,
     },
+    Become {
+        expr: ExprId,
+    },
     Yield {
         expr: Option<ExprId>,
     },
@@ -349,6 +353,9 @@ pub enum Statement {
         expr: ExprId,
         has_semi: bool,
     },
+    // At the moment, we only use this to figure out if a return expression
+    // is really the last statement of a block. See #16566
+    Item,
 }
 
 impl Expr {
@@ -382,6 +389,7 @@ impl Expr {
                             }
                         }
                         Statement::Expr { expr: expression, .. } => f(*expression),
+                        Statement::Item => (),
                     }
                 }
                 if let &Some(expr) = tail {
@@ -410,6 +418,7 @@ impl Expr {
                     f(expr);
                 }
             }
+            Expr::Become { expr } => f(*expr),
             Expr::RecordLit { fields, spread, .. } => {
                 for field in fields.iter() {
                     f(field.expr);
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/macro_expansion_tests/mbe/matching.rs b/src/tools/rust-analyzer/crates/hir-def/src/macro_expansion_tests/mbe/matching.rs
index 0909d8c8354..63f211022c9 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/macro_expansion_tests/mbe/matching.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/macro_expansion_tests/mbe/matching.rs
@@ -33,7 +33,7 @@ m!(&k");
 "#,
         expect![[r#"
 macro_rules! m { ($i:literal) => {}; }
-/* error: invalid token tree */"#]],
+/* error: mismatched delimiters */"#]],
     );
 }
 
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/macro_expansion_tests/mbe/meta_syntax.rs b/src/tools/rust-analyzer/crates/hir-def/src/macro_expansion_tests/mbe/meta_syntax.rs
index e875950e4e5..2d289b76833 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/macro_expansion_tests/mbe/meta_syntax.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/macro_expansion_tests/mbe/meta_syntax.rs
@@ -68,26 +68,26 @@ m2!();
 "#,
         expect![[r#"
 macro_rules! i1 { invalid }
-/* error: invalid macro definition: expected subtree */
+/* error: macro definition has parse errors */
 
 macro_rules! e1 { $i:ident => () }
-/* error: invalid macro definition: expected subtree */
+/* error: macro definition has parse errors */
 macro_rules! e2 { ($i:ident) () }
-/* error: invalid macro definition: expected `=` */
+/* error: macro definition has parse errors */
 macro_rules! e3 { ($(i:ident)_) => () }
-/* error: invalid macro definition: invalid repeat */
+/* error: macro definition has parse errors */
 
 macro_rules! f1 { ($i) => ($i) }
-/* error: invalid macro definition: missing fragment specifier */
+/* error: macro definition has parse errors */
 macro_rules! f2 { ($i:) => ($i) }
-/* error: invalid macro definition: missing fragment specifier */
+/* error: macro definition has parse errors */
 macro_rules! f3 { ($i:_) => () }
-/* error: invalid macro definition: missing fragment specifier */
+/* error: macro definition has parse errors */
 
 macro_rules! m1 { ($$i) => () }
-/* error: invalid macro definition: `$$` is not allowed on the pattern side */
+/* error: macro definition has parse errors */
 macro_rules! m2 { () => ( ${invalid()} ) }
-/* error: invalid macro definition: invalid metavariable expression */
+/* error: macro definition has parse errors */
 "#]],
     )
 }
@@ -137,18 +137,18 @@ macro_rules! m9 { ($($($($i:ident)?)*)+) => {}; }
 macro_rules! mA { ($($($($i:ident)+)?)*) => {}; }
 macro_rules! mB { ($($($($i:ident)+)*)?) => {}; }
 
-/* error: invalid macro definition: empty token tree in repetition */
-/* error: invalid macro definition: empty token tree in repetition */
-/* error: invalid macro definition: empty token tree in repetition */
-/* error: invalid macro definition: empty token tree in repetition */
-/* error: invalid macro definition: empty token tree in repetition */
-/* error: invalid macro definition: empty token tree in repetition */
-/* error: invalid macro definition: empty token tree in repetition */
-/* error: invalid macro definition: empty token tree in repetition */
-/* error: invalid macro definition: empty token tree in repetition */
-/* error: invalid macro definition: empty token tree in repetition */
-/* error: invalid macro definition: empty token tree in repetition */
-/* error: invalid macro definition: empty token tree in repetition */
+/* error: macro definition has parse errors */
+/* error: macro definition has parse errors */
+/* error: macro definition has parse errors */
+/* error: macro definition has parse errors */
+/* error: macro definition has parse errors */
+/* error: macro definition has parse errors */
+/* error: macro definition has parse errors */
+/* error: macro definition has parse errors */
+/* error: macro definition has parse errors */
+/* error: macro definition has parse errors */
+/* error: macro definition has parse errors */
+/* error: macro definition has parse errors */
     "#]],
     );
 }
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/macro_expansion_tests/mbe/metavar_expr.rs b/src/tools/rust-analyzer/crates/hir-def/src/macro_expansion_tests/mbe/metavar_expr.rs
index 6560d0ec466..bf701198387 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/macro_expansion_tests/mbe/metavar_expr.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/macro_expansion_tests/mbe/metavar_expr.rs
@@ -275,9 +275,9 @@ macro_rules! depth_too_large {
 }
 
 fn test() {
-    /* error: invalid macro definition: invalid metavariable expression */;
-    /* error: invalid macro definition: invalid metavariable expression */;
-    /* error: invalid macro definition: invalid metavariable expression */;
+    /* error: macro definition has parse errors */;
+    /* error: macro definition has parse errors */;
+    /* error: macro definition has parse errors */;
 }
 "#]],
     );
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/macro_expansion_tests/mbe/regression.rs b/src/tools/rust-analyzer/crates/hir-def/src/macro_expansion_tests/mbe/regression.rs
index 6717ee1aa5f..4aad53c3bd7 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/macro_expansion_tests/mbe/regression.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/macro_expansion_tests/mbe/regression.rs
@@ -1090,3 +1090,57 @@ fn main() {
 "#]],
     );
 }
+
+#[test]
+fn regression_16529() {
+    check(
+        r#"
+mod any {
+    #[macro_export]
+    macro_rules! nameable {
+        {
+            struct $name:ident[$a:lifetime]
+        } => {
+            $crate::any::nameable! {
+                struct $name[$a]
+                a
+            }
+        };
+        {
+            struct $name:ident[$a:lifetime]
+            a
+        } => {};
+    }
+    pub use nameable;
+
+    nameable! {
+        Name['a]
+    }
+}
+"#,
+        expect![[r#"
+mod any {
+    #[macro_export]
+    macro_rules! nameable {
+        {
+            struct $name:ident[$a:lifetime]
+        } => {
+            $crate::any::nameable! {
+                struct $name[$a]
+                a
+            }
+        };
+        {
+            struct $name:ident[$a:lifetime]
+            a
+        } => {};
+    }
+    pub use nameable;
+
+    /* error: unexpected token in input */$crate::any::nameable! {
+        struct $name[$a]a
+    }
+}
+"#]],
+    );
+}
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/macro_expansion_tests/mbe/tt_conversion.rs b/src/tools/rust-analyzer/crates/hir-def/src/macro_expansion_tests/mbe/tt_conversion.rs
index ae56934f632..362c189f6a7 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/macro_expansion_tests/mbe/tt_conversion.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/macro_expansion_tests/mbe/tt_conversion.rs
@@ -97,8 +97,8 @@ m2!(x
 macro_rules! m1 { ($x:ident) => { ($x } }
 macro_rules! m2 { ($x:ident) => {} }
 
-/* error: invalid macro definition: expected subtree */
-/* error: invalid token tree */
+/* error: macro definition has parse errors */
+/* error: mismatched delimiters */
 "#]],
     )
 }
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/macro_expansion_tests/mod.rs b/src/tools/rust-analyzer/crates/hir-def/src/macro_expansion_tests/mod.rs
index fc5a6e80a42..23b10cfd8e6 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/macro_expansion_tests/mod.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/macro_expansion_tests/mod.rs
@@ -58,6 +58,7 @@ pub fn identity_when_valid(_attr: TokenStream, item: TokenStream) -> TokenStream
             name: "identity_when_valid".into(),
             kind: ProcMacroKind::Attr,
             expander: sync::Arc::new(IdentityWhenValidProcMacroExpander),
+            disabled: false,
         },
     )];
     let db = TestDB::with_files_extra_proc_macros(ra_fixture, extra_proc_macros);
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/nameres/collector.rs b/src/tools/rust-analyzer/crates/hir-def/src/nameres/collector.rs
index 21cc28f1b3d..88838f58fe7 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/nameres/collector.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/nameres/collector.rs
@@ -11,7 +11,7 @@ use either::Either;
 use hir_expand::{
     ast_id_map::FileAstId,
     attrs::{Attr, AttrId},
-    builtin_attr_macro::find_builtin_attr,
+    builtin_attr_macro::{find_builtin_attr, BuiltinAttrExpander},
     builtin_derive_macro::find_builtin_derive,
     builtin_fn_macro::find_builtin_macro,
     name::{name, AsName, Name},
@@ -98,9 +98,13 @@ pub(super) fn collect_defs(db: &dyn DefDatabase, def_map: DefMap, tree_id: TreeI
                         };
                         (
                             name.as_name(),
-                            CustomProcMacroExpander::new(hir_expand::proc_macro::ProcMacroId(
-                                idx as u32,
-                            )),
+                            if it.disabled {
+                                CustomProcMacroExpander::disabled()
+                            } else {
+                                CustomProcMacroExpander::new(
+                                    hir_expand::proc_macro::ProcMacroId::new(idx as u32),
+                                )
+                            },
                         )
                     })
                     .collect())
@@ -604,9 +608,6 @@ impl DefCollector<'_> {
         id: ItemTreeId<item_tree::Function>,
         fn_id: FunctionId,
     ) {
-        if self.def_map.block.is_some() {
-            return;
-        }
         let kind = def.kind.to_basedb_kind();
         let (expander, kind) =
             match self.proc_macros.as_ref().map(|it| it.iter().find(|(n, _)| n == &def.name)) {
@@ -1120,9 +1121,16 @@ impl DefCollector<'_> {
         let mut push_resolved = |directive: &MacroDirective, call_id| {
             resolved.push((directive.module_id, directive.depth, directive.container, call_id));
         };
+
+        #[derive(PartialEq, Eq)]
+        enum Resolved {
+            Yes,
+            No,
+        }
+
         let mut res = ReachedFixedPoint::Yes;
         // Retain unresolved macros after this round of resolution.
-        macros.retain(|directive| {
+        let mut retain = |directive: &MacroDirective| {
             let subns = match &directive.kind {
                 MacroDirectiveKind::FnLike { .. } => MacroSubNs::Bang,
                 MacroDirectiveKind::Attr { .. } | MacroDirectiveKind::Derive { .. } => {
@@ -1156,10 +1164,11 @@ impl DefCollector<'_> {
                         self.def_map.modules[directive.module_id]
                             .scope
                             .add_macro_invoc(ast_id.ast_id, call_id);
+
                         push_resolved(directive, call_id);
 
                         res = ReachedFixedPoint::No;
-                        return false;
+                        return Resolved::Yes;
                     }
                 }
                 MacroDirectiveKind::Derive { ast_id, derive_attr, derive_pos, call_site } => {
@@ -1198,7 +1207,7 @@ impl DefCollector<'_> {
 
                         push_resolved(directive, call_id);
                         res = ReachedFixedPoint::No;
-                        return false;
+                        return Resolved::Yes;
                     }
                 }
                 MacroDirectiveKind::Attr { ast_id: file_ast_id, mod_item, attr, tree } => {
@@ -1221,7 +1230,7 @@ impl DefCollector<'_> {
                         }
                         .collect(&[*mod_item], directive.container);
                         res = ReachedFixedPoint::No;
-                        false
+                        Resolved::Yes
                     };
 
                     if let Some(ident) = path.as_ident() {
@@ -1237,13 +1246,18 @@ impl DefCollector<'_> {
 
                     let def = match resolver_def_id(path.clone()) {
                         Some(def) if def.is_attribute() => def,
-                        _ => return true,
+                        _ => return Resolved::No,
                     };
-                    if matches!(
-                        def,
-                        MacroDefId { kind: MacroDefKind::BuiltInAttr(expander, _),.. }
-                        if expander.is_derive()
-                    ) {
+
+                    if let MacroDefId {
+                        kind:
+                            MacroDefKind::BuiltInAttr(
+                                BuiltinAttrExpander::Derive | BuiltinAttrExpander::DeriveConst,
+                                _,
+                            ),
+                        ..
+                    } = def
+                    {
                         // Resolved to `#[derive]`, we don't actually expand this attribute like
                         // normal (as that would just be an identity expansion with extra output)
                         // Instead we treat derive attributes special and apply them separately.
@@ -1316,16 +1330,6 @@ impl DefCollector<'_> {
                     let call_id =
                         attr_macro_as_call_id(self.db, file_ast_id, attr, self.def_map.krate, def);
 
-                    // If proc attribute macro expansion is disabled, skip expanding it here
-                    if !self.db.expand_proc_attr_macros() {
-                        self.def_map.diagnostics.push(DefDiagnostic::unresolved_proc_macro(
-                            directive.module_id,
-                            self.db.lookup_intern_macro_call(call_id).kind,
-                            def.krate,
-                        ));
-                        return recollect_without(self);
-                    }
-
                     // Skip #[test]/#[bench] expansion, which would merely result in more memory usage
                     // due to duplicating functions into macro expansions
                     if matches!(
@@ -1337,17 +1341,29 @@ impl DefCollector<'_> {
                     }
 
                     if let MacroDefKind::ProcMacro(exp, ..) = def.kind {
-                        if exp.is_dummy() {
-                            // If there's no expander for the proc macro (e.g.
-                            // because proc macros are disabled, or building the
-                            // proc macro crate failed), report this and skip
-                            // expansion like we would if it was disabled
+                        // If proc attribute macro expansion is disabled, skip expanding it here
+                        if !self.db.expand_proc_attr_macros() {
                             self.def_map.diagnostics.push(DefDiagnostic::unresolved_proc_macro(
                                 directive.module_id,
                                 self.db.lookup_intern_macro_call(call_id).kind,
                                 def.krate,
                             ));
+                            return recollect_without(self);
+                        }
 
+                        // If there's no expander for the proc macro (e.g.
+                        // because proc macros are disabled, or building the
+                        // proc macro crate failed), report this and skip
+                        // expansion like we would if it was disabled
+                        if exp.is_dummy() {
+                            self.def_map.diagnostics.push(DefDiagnostic::unresolved_proc_macro(
+                                directive.module_id,
+                                self.db.lookup_intern_macro_call(call_id).kind,
+                                def.krate,
+                            ));
+                            return recollect_without(self);
+                        }
+                        if exp.is_disabled() {
                             return recollect_without(self);
                         }
                     }
@@ -1358,12 +1374,13 @@ impl DefCollector<'_> {
 
                     push_resolved(directive, call_id);
                     res = ReachedFixedPoint::No;
-                    return false;
+                    return Resolved::Yes;
                 }
             }
 
-            true
-        });
+            Resolved::No
+        };
+        macros.retain(|it| retain(it) == Resolved::No);
         // Attribute resolution can add unresolved macro invocations, so concatenate the lists.
         macros.extend(mem::take(&mut self.unresolved_macros));
         self.unresolved_macros = macros;
@@ -1673,7 +1690,11 @@ impl ModCollector<'_, '_> {
                         FunctionLoc { container, id: ItemTreeId::new(self.tree_id, id) }.intern(db);
 
                     let vis = resolve_vis(def_map, &self.item_tree[it.visibility]);
-                    if self.def_collector.is_proc_macro && self.module_id == DefMap::ROOT {
+
+                    if self.def_collector.def_map.block.is_none()
+                        && self.def_collector.is_proc_macro
+                        && self.module_id == DefMap::ROOT
+                    {
                         if let Some(proc_macro) = attrs.parse_proc_macro_decl(&it.name) {
                             self.def_collector.export_proc_macro(
                                 proc_macro,
@@ -2333,7 +2354,7 @@ impl ModCollector<'_, '_> {
                 resolved_res.resolved_def.take_macros().map(|it| db.macro_def(it))
             },
         ) {
-            // FIXME: if there were errors, this mightve been in the eager expansion from an
+            // FIXME: if there were errors, this might've been in the eager expansion from an
             // unresolved macro, so we need to push this into late macro resolution. see fixme above
             if res.err.is_none() {
                 // Legacy macros need to be expanded immediately, so that any macros they produce
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/nameres/diagnostics.rs b/src/tools/rust-analyzer/crates/hir-def/src/nameres/diagnostics.rs
index 0a3f7bf7ec3..161b2c05990 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/nameres/diagnostics.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/nameres/diagnostics.rs
@@ -103,6 +103,9 @@ impl DefDiagnostic {
     }
 
     // FIXME: Whats the difference between this and unresolved_macro_call
+    // FIXME: This is used for a lot of things, unresolved proc macros, disabled proc macros, etc
+    // yet the diagnostic handler in ide-diagnostics has to figure out what happened because this
+    // struct loses all that information!
     pub(crate) fn unresolved_proc_macro(
         container: LocalModuleId,
         ast: MacroCallKind,