about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--crates/hir-def/src/body/lower.rs11
-rw-r--r--crates/hir-def/src/data.rs3
-rw-r--r--crates/hir-def/src/find_path.rs1
-rw-r--r--crates/hir-def/src/generics.rs3
-rw-r--r--crates/hir-def/src/macro_expansion_tests/builtin_fn_macro.rs12
-rw-r--r--crates/hir-def/src/macro_expansion_tests/mbe.rs4
-rw-r--r--crates/hir-def/src/macro_expansion_tests/mbe/matching.rs2
-rw-r--r--crates/hir-def/src/macro_expansion_tests/mbe/regression.rs20
-rw-r--r--crates/hir-def/src/macro_expansion_tests/mod.rs14
-rw-r--r--crates/hir-def/src/nameres.rs68
-rw-r--r--crates/hir-def/src/nameres/attr_resolution.rs5
-rw-r--r--crates/hir-def/src/nameres/collector.rs211
-rw-r--r--crates/hir-def/src/nameres/path_resolution.rs58
-rw-r--r--crates/hir-def/src/nameres/tests/macros.rs111
-rw-r--r--crates/hir-def/src/resolver.rs20
-rw-r--r--crates/hir-expand/src/builtin_fn_macro.rs6
-rw-r--r--crates/hir-ty/src/lower.rs13
-rw-r--r--crates/hir-ty/src/tests/macros.rs6
-rw-r--r--crates/hir/src/attrs.rs6
-rw-r--r--crates/hir/src/semantics.rs3
-rw-r--r--crates/hir/src/source_analyzer.rs17
21 files changed, 425 insertions, 169 deletions
diff --git a/crates/hir-def/src/body/lower.rs b/crates/hir-def/src/body/lower.rs
index 80aa1af057c..d92698a938a 100644
--- a/crates/hir-def/src/body/lower.rs
+++ b/crates/hir-def/src/body/lower.rs
@@ -37,7 +37,7 @@ use crate::{
     item_scope::BuiltinShadowMode,
     lang_item::LangItem,
     lower::LowerCtx,
-    nameres::DefMap,
+    nameres::{DefMap, MacroSubNs},
     path::{GenericArgs, Path},
     type_ref::{Mutability, Rawness, TypeRef},
     AdtId, BlockId, BlockLoc, ModuleDefId, UnresolvedMacro,
@@ -800,7 +800,13 @@ impl ExprCollector<'_> {
         let module = self.expander.module.local_id;
         let res = self.expander.enter_expand(self.db, mcall, |path| {
             self.def_map
-                .resolve_path(self.db, module, &path, crate::item_scope::BuiltinShadowMode::Other)
+                .resolve_path(
+                    self.db,
+                    module,
+                    &path,
+                    crate::item_scope::BuiltinShadowMode::Other,
+                    Some(MacroSubNs::Bang),
+                )
                 .0
                 .take_macros()
         });
@@ -1056,6 +1062,7 @@ impl ExprCollector<'_> {
                         self.expander.module.local_id,
                         &name.clone().into(),
                         BuiltinShadowMode::Other,
+                        None,
                     );
                     match resolved.take_values() {
                         Some(ModuleDefId::ConstId(_)) => (None, Pat::Path(name.into())),
diff --git a/crates/hir-def/src/data.rs b/crates/hir-def/src/data.rs
index de67f0b23cf..40e6a430878 100644
--- a/crates/hir-def/src/data.rs
+++ b/crates/hir-def/src/data.rs
@@ -22,7 +22,7 @@ use crate::{
         attr_resolution::ResolvedAttr,
         diagnostics::DefDiagnostic,
         proc_macro::{parse_macro_name_and_helper_attrs, ProcMacroKind},
-        DefMap,
+        DefMap, MacroSubNs,
     },
     type_ref::{TraitRef, TypeBound, TypeRef},
     visibility::RawVisibility,
@@ -673,6 +673,7 @@ impl<'a> AssocItemCollector<'a> {
                             module,
                             &path,
                             crate::item_scope::BuiltinShadowMode::Other,
+                            Some(MacroSubNs::Bang),
                         )
                         .0
                         .take_macros()
diff --git a/crates/hir-def/src/find_path.rs b/crates/hir-def/src/find_path.rs
index 30d6d019309..b401762255e 100644
--- a/crates/hir-def/src/find_path.rs
+++ b/crates/hir-def/src/find_path.rs
@@ -543,6 +543,7 @@ mod tests {
                 module.local_id,
                 &mod_path,
                 crate::item_scope::BuiltinShadowMode::Module,
+                None,
             )
             .0
             .take_types()
diff --git a/crates/hir-def/src/generics.rs b/crates/hir-def/src/generics.rs
index c79c1709630..f19c3f028f4 100644
--- a/crates/hir-def/src/generics.rs
+++ b/crates/hir-def/src/generics.rs
@@ -22,7 +22,7 @@ use crate::{
     dyn_map::{keys, DynMap},
     expander::Expander,
     lower::LowerCtx,
-    nameres::DefMap,
+    nameres::{DefMap, MacroSubNs},
     src::{HasChildSource, HasSource},
     type_ref::{LifetimeRef, TypeBound, TypeRef},
     AdtId, ConstParamId, GenericDefId, HasModule, LifetimeParamId, LocalLifetimeParamId,
@@ -361,6 +361,7 @@ impl GenericParams {
                             module,
                             &path,
                             crate::item_scope::BuiltinShadowMode::Other,
+                            Some(MacroSubNs::Bang),
                         )
                         .0
                         .take_macros()
diff --git a/crates/hir-def/src/macro_expansion_tests/builtin_fn_macro.rs b/crates/hir-def/src/macro_expansion_tests/builtin_fn_macro.rs
index 0b72ca1eec1..6cb741dac71 100644
--- a/crates/hir-def/src/macro_expansion_tests/builtin_fn_macro.rs
+++ b/crates/hir-def/src/macro_expansion_tests/builtin_fn_macro.rs
@@ -13,12 +13,12 @@ macro_rules! column {() => {}}
 
 fn main() { column!(); }
 "#,
-        expect![[r##"
+        expect![[r#"
 #[rustc_builtin_macro]
 macro_rules! column {() => {}}
 
-fn main() { 0; }
-"##]],
+fn main() { 0 as u32; }
+"#]],
     );
 }
 
@@ -31,12 +31,12 @@ macro_rules! line {() => {}}
 
 fn main() { line!() }
 "#,
-        expect![[r##"
+        expect![[r#"
 #[rustc_builtin_macro]
 macro_rules! line {() => {}}
 
-fn main() { 0 }
-"##]],
+fn main() { 0 as u32 }
+"#]],
     );
 }
 
diff --git a/crates/hir-def/src/macro_expansion_tests/mbe.rs b/crates/hir-def/src/macro_expansion_tests/mbe.rs
index 99c405fb917..c056c077a56 100644
--- a/crates/hir-def/src/macro_expansion_tests/mbe.rs
+++ b/crates/hir-def/src/macro_expansion_tests/mbe.rs
@@ -922,7 +922,7 @@ macro_rules! m {
 
 fn bar() -> &'a Baz<u8> {}
 
-fn bar() -> extern "Rust"fn() -> Ret {}
+fn bar() -> extern "Rust" fn() -> Ret {}
 "#]],
     );
 }
@@ -1333,7 +1333,7 @@ macro_rules! matches {
 }
 fn main() {
     match 0 {
-        0|1if true =>true , _=>false
+        0|1 if true =>true , _=>false
     };
 }
  "#]],
diff --git a/crates/hir-def/src/macro_expansion_tests/mbe/matching.rs b/crates/hir-def/src/macro_expansion_tests/mbe/matching.rs
index e5fb15b6be4..0909d8c8354 100644
--- a/crates/hir-def/src/macro_expansion_tests/mbe/matching.rs
+++ b/crates/hir-def/src/macro_expansion_tests/mbe/matching.rs
@@ -73,7 +73,7 @@ fn main() {
 macro_rules! asi { ($($stmt:stmt)*) => ($($stmt)*); }
 
 fn main() {
-    let a = 2let b = 5drop(b-a)println!("{}", a+b)
+    let a = 2 let b = 5 drop(b-a)println!("{}", a+b)
 }
 "#]],
     )
diff --git a/crates/hir-def/src/macro_expansion_tests/mbe/regression.rs b/crates/hir-def/src/macro_expansion_tests/mbe/regression.rs
index b663a291789..d8e4a4dcc7c 100644
--- a/crates/hir-def/src/macro_expansion_tests/mbe/regression.rs
+++ b/crates/hir-def/src/macro_expansion_tests/mbe/regression.rs
@@ -297,55 +297,55 @@ macro_rules! impl_fn_for_zst  {
 
 #[derive(Clone)] struct CharEscapeDebugContinue;
 impl Fn<(char, )> for CharEscapeDebugContinue {
-    #[inline] extern "rust-call"fn call(&self , (c, ): (char, )) -> char::EscapeDebug { {
+    #[inline] extern "rust-call" fn call(&self , (c, ): (char, )) -> char::EscapeDebug { {
             c.escape_debug_ext(false )
         }
     }
 }
 impl FnMut<(char, )> for CharEscapeDebugContinue {
-    #[inline] extern "rust-call"fn call_mut(&mut self , (c, ): (char, )) -> char::EscapeDebug {
+    #[inline] extern "rust-call" fn call_mut(&mut self , (c, ): (char, )) -> char::EscapeDebug {
         Fn::call(&*self , (c, ))
     }
 }
 impl FnOnce<(char, )> for CharEscapeDebugContinue {
     type Output = char::EscapeDebug;
-    #[inline] extern "rust-call"fn call_once(self , (c, ): (char, )) -> char::EscapeDebug {
+    #[inline] extern "rust-call" fn call_once(self , (c, ): (char, )) -> char::EscapeDebug {
         Fn::call(&self , (c, ))
     }
 }
 #[derive(Clone)] struct CharEscapeUnicode;
 impl Fn<(char, )> for CharEscapeUnicode {
-    #[inline] extern "rust-call"fn call(&self , (c, ): (char, )) -> char::EscapeUnicode { {
+    #[inline] extern "rust-call" fn call(&self , (c, ): (char, )) -> char::EscapeUnicode { {
             c.escape_unicode()
         }
     }
 }
 impl FnMut<(char, )> for CharEscapeUnicode {
-    #[inline] extern "rust-call"fn call_mut(&mut self , (c, ): (char, )) -> char::EscapeUnicode {
+    #[inline] extern "rust-call" fn call_mut(&mut self , (c, ): (char, )) -> char::EscapeUnicode {
         Fn::call(&*self , (c, ))
     }
 }
 impl FnOnce<(char, )> for CharEscapeUnicode {
     type Output = char::EscapeUnicode;
-    #[inline] extern "rust-call"fn call_once(self , (c, ): (char, )) -> char::EscapeUnicode {
+    #[inline] extern "rust-call" fn call_once(self , (c, ): (char, )) -> char::EscapeUnicode {
         Fn::call(&self , (c, ))
     }
 }
 #[derive(Clone)] struct CharEscapeDefault;
 impl Fn<(char, )> for CharEscapeDefault {
-    #[inline] extern "rust-call"fn call(&self , (c, ): (char, )) -> char::EscapeDefault { {
+    #[inline] extern "rust-call" fn call(&self , (c, ): (char, )) -> char::EscapeDefault { {
             c.escape_default()
         }
     }
 }
 impl FnMut<(char, )> for CharEscapeDefault {
-    #[inline] extern "rust-call"fn call_mut(&mut self , (c, ): (char, )) -> char::EscapeDefault {
+    #[inline] extern "rust-call" fn call_mut(&mut self , (c, ): (char, )) -> char::EscapeDefault {
         Fn::call(&*self , (c, ))
     }
 }
 impl FnOnce<(char, )> for CharEscapeDefault {
     type Output = char::EscapeDefault;
-    #[inline] extern "rust-call"fn call_once(self , (c, ): (char, )) -> char::EscapeDefault {
+    #[inline] extern "rust-call" fn call_once(self , (c, ): (char, )) -> char::EscapeDefault {
         Fn::call(&self , (c, ))
     }
 }
@@ -833,7 +833,7 @@ macro_rules! rgb_color {
 /* parse error: expected SEMICOLON */
 /* parse error: expected expression, item or let statement */
 pub fn new() {
-    let _ = 0as u32<<(8+8);
+    let _ = 0 as u32<<(8+8);
 }
 // MACRO_ITEMS@0..31
 //   FN@0..31
diff --git a/crates/hir-def/src/macro_expansion_tests/mod.rs b/crates/hir-def/src/macro_expansion_tests/mod.rs
index c48c0c1aee5..40849d4a66d 100644
--- a/crates/hir-def/src/macro_expansion_tests/mod.rs
+++ b/crates/hir-def/src/macro_expansion_tests/mod.rs
@@ -33,8 +33,13 @@ use syntax::{
 use tt::token_id::{Subtree, TokenId};
 
 use crate::{
-    db::DefDatabase, macro_id_to_def_id, nameres::ModuleSource, resolver::HasResolver,
-    src::HasSource, test_db::TestDB, AdtId, AsMacroCall, Lookup, ModuleDefId,
+    db::DefDatabase,
+    macro_id_to_def_id,
+    nameres::{MacroSubNs, ModuleSource},
+    resolver::HasResolver,
+    src::HasSource,
+    test_db::TestDB,
+    AdtId, AsMacroCall, Lookup, ModuleDefId,
 };
 
 #[track_caller]
@@ -127,7 +132,9 @@ pub fn identity_when_valid(_attr: TokenStream, item: TokenStream) -> TokenStream
         let macro_call = InFile::new(source.file_id, &macro_call);
         let res = macro_call
             .as_call_id_with_errors(&db, krate, |path| {
-                resolver.resolve_path_as_macro(&db, &path).map(|it| macro_id_to_def_id(&db, it))
+                resolver
+                    .resolve_path_as_macro(&db, &path, Some(MacroSubNs::Bang))
+                    .map(|it| macro_id_to_def_id(&db, it))
             })
             .unwrap();
         let macro_call_id = res.value.unwrap();
@@ -280,6 +287,7 @@ fn pretty_print_macro_expansion(expn: SyntaxNode, map: Option<&TokenMap>) -> Str
         let curr_kind = token.kind();
         let space = match (prev_kind, curr_kind) {
             _ if prev_kind.is_trivia() || curr_kind.is_trivia() => "",
+            _ if prev_kind.is_literal() && !curr_kind.is_punct() => " ",
             (T!['{'], T!['}']) => "",
             (T![=], _) | (_, T![=]) => " ",
             (_, T!['{']) => " ",
diff --git a/crates/hir-def/src/nameres.rs b/crates/hir-def/src/nameres.rs
index 803342fdab5..39a56814ed8 100644
--- a/crates/hir-def/src/nameres.rs
+++ b/crates/hir-def/src/nameres.rs
@@ -59,7 +59,7 @@ mod tests;
 
 use std::{cmp::Ord, ops::Deref};
 
-use base_db::{CrateId, Edition, FileId};
+use base_db::{CrateId, Edition, FileId, ProcMacroKind};
 use hir_expand::{name::Name, InFile, MacroCallId, MacroDefId};
 use itertools::Itertools;
 use la_arena::Arena;
@@ -77,7 +77,8 @@ use crate::{
     path::ModPath,
     per_ns::PerNs,
     visibility::Visibility,
-    AstId, BlockId, BlockLoc, FunctionId, LocalModuleId, MacroId, ModuleId, ProcMacroId,
+    AstId, BlockId, BlockLoc, FunctionId, LocalModuleId, Lookup, MacroExpander, MacroId, ModuleId,
+    ProcMacroId,
 };
 
 /// Contains the results of (early) name resolution.
@@ -105,6 +106,9 @@ pub struct DefMap {
     prelude: Option<ModuleId>,
     /// The extern prelude is only populated for non-block DefMaps
     extern_prelude: FxHashMap<Name, ModuleId>,
+    /// `macro_use` prelude that contains macros from `#[macro_use]`'d external crates. Note that
+    /// this contains all kinds of macro, not just `macro_rules!` macro.
+    macro_use_prelude: FxHashMap<Name, MacroId>,
 
     /// Side table for resolving derive helpers.
     exported_derives: FxHashMap<MacroDefId, Box<[Name]>>,
@@ -277,6 +281,7 @@ impl DefMap {
             edition,
             recursion_limit: None,
             extern_prelude: FxHashMap::default(),
+            macro_use_prelude: FxHashMap::default(),
             exported_derives: FxHashMap::default(),
             fn_proc_macro_mapping: FxHashMap::default(),
             proc_macro_loading_error: None,
@@ -376,9 +381,16 @@ impl DefMap {
         original_module: LocalModuleId,
         path: &ModPath,
         shadow: BuiltinShadowMode,
+        expected_macro_subns: Option<MacroSubNs>,
     ) -> (PerNs, Option<usize>) {
-        let res =
-            self.resolve_path_fp_with_macro(db, ResolveMode::Other, original_module, path, shadow);
+        let res = self.resolve_path_fp_with_macro(
+            db,
+            ResolveMode::Other,
+            original_module,
+            path,
+            shadow,
+            expected_macro_subns,
+        );
         (res.resolved_def, res.segment_index)
     }
 
@@ -395,6 +407,7 @@ impl DefMap {
             original_module,
             path,
             shadow,
+            None, // Currently this function isn't used for macro resolution.
         );
         (res.resolved_def, res.segment_index)
     }
@@ -489,6 +502,7 @@ impl DefMap {
             _c: _,
             exported_derives,
             extern_prelude,
+            macro_use_prelude,
             diagnostics,
             modules,
             registered_attrs,
@@ -507,6 +521,7 @@ impl DefMap {
         } = self;
 
         extern_prelude.shrink_to_fit();
+        macro_use_prelude.shrink_to_fit();
         exported_derives.shrink_to_fit();
         diagnostics.shrink_to_fit();
         modules.shrink_to_fit();
@@ -562,3 +577,48 @@ pub enum ModuleSource {
     Module(ast::Module),
     BlockExpr(ast::BlockExpr),
 }
+
+/// See `sub_namespace_match()`.
+#[derive(Clone, Copy, PartialEq, Eq)]
+pub enum MacroSubNs {
+    /// Function-like macros, suffixed with `!`.
+    Bang,
+    /// Macros inside attributes, i.e. attribute macros and derive macros.
+    Attr,
+}
+
+impl MacroSubNs {
+    fn from_id(db: &dyn DefDatabase, macro_id: MacroId) -> Self {
+        let expander = match macro_id {
+            MacroId::Macro2Id(it) => it.lookup(db).expander,
+            MacroId::MacroRulesId(it) => it.lookup(db).expander,
+            MacroId::ProcMacroId(it) => {
+                return match it.lookup(db).kind {
+                    ProcMacroKind::CustomDerive | ProcMacroKind::Attr => Self::Attr,
+                    ProcMacroKind::FuncLike => Self::Bang,
+                };
+            }
+        };
+
+        // Eager macros aren't *guaranteed* to be bang macros, but they *are* all bang macros currently.
+        match expander {
+            MacroExpander::Declarative
+            | MacroExpander::BuiltIn(_)
+            | MacroExpander::BuiltInEager(_) => Self::Bang,
+            MacroExpander::BuiltInAttr(_) | MacroExpander::BuiltInDerive(_) => Self::Attr,
+        }
+    }
+}
+
+/// Quoted from [rustc]:
+/// Macro namespace is separated into two sub-namespaces, one for bang macros and
+/// one for attribute-like macros (attributes, derives).
+/// We ignore resolutions from one sub-namespace when searching names in scope for another.
+///
+/// [rustc]: https://github.com/rust-lang/rust/blob/1.69.0/compiler/rustc_resolve/src/macros.rs#L75
+fn sub_namespace_match(candidate: Option<MacroSubNs>, expected: Option<MacroSubNs>) -> bool {
+    match (candidate, expected) {
+        (Some(candidate), Some(expected)) => candidate == expected,
+        _ => true,
+    }
+}
diff --git a/crates/hir-def/src/nameres/attr_resolution.rs b/crates/hir-def/src/nameres/attr_resolution.rs
index 84271ef51d8..6567bda709d 100644
--- a/crates/hir-def/src/nameres/attr_resolution.rs
+++ b/crates/hir-def/src/nameres/attr_resolution.rs
@@ -14,7 +14,7 @@ use crate::{
     AstIdWithPath, LocalModuleId, UnresolvedMacro,
 };
 
-use super::DefMap;
+use super::{DefMap, MacroSubNs};
 
 pub enum ResolvedAttr {
     /// Attribute resolved to an attribute macro.
@@ -43,9 +43,12 @@ impl DefMap {
             original_module,
             &ast_id.path,
             BuiltinShadowMode::Module,
+            Some(MacroSubNs::Attr),
         );
         let def = match resolved_res.resolved_def.take_macros() {
             Some(def) => {
+                // `MacroSubNs` is just a hint, so the path may still resolve to a custom derive
+                // macro, or even function-like macro when the path is qualified.
                 if def.is_attribute(db) {
                     def
                 } else {
diff --git a/crates/hir-def/src/nameres/collector.rs b/crates/hir-def/src/nameres/collector.rs
index 3ec33f663a3..177edcbb7f2 100644
--- a/crates/hir-def/src/nameres/collector.rs
+++ b/crates/hir-def/src/nameres/collector.rs
@@ -44,7 +44,7 @@ use crate::{
         mod_resolution::ModDir,
         path_resolution::ReachedFixedPoint,
         proc_macro::{parse_macro_name_and_helper_attrs, ProcMacroDef, ProcMacroKind},
-        BuiltinShadowMode, DefMap, ModuleData, ModuleOrigin, ResolveMode,
+        BuiltinShadowMode, DefMap, MacroSubNs, ModuleData, ModuleOrigin, ResolveMode,
     },
     path::{ImportAlias, ModPath, PathKind},
     per_ns::PerNs,
@@ -289,80 +289,84 @@ impl DefCollector<'_> {
         let module_id = self.def_map.root;
 
         let attrs = item_tree.top_level_attrs(self.db, self.def_map.krate);
-        if attrs.cfg().map_or(true, |cfg| self.cfg_options.check(&cfg) != Some(false)) {
-            self.inject_prelude(&attrs);
-
-            // Process other crate-level attributes.
-            for attr in &*attrs {
-                let attr_name = match attr.path.as_ident() {
-                    Some(name) => name,
-                    None => continue,
-                };
+        if let Some(cfg) = attrs.cfg() {
+            if self.cfg_options.check(&cfg) == Some(false) {
+                return;
+            }
+        }
 
-                if *attr_name == hir_expand::name![recursion_limit] {
-                    if let Some(limit) = attr.string_value() {
-                        if let Ok(limit) = limit.parse() {
-                            self.def_map.recursion_limit = Some(limit);
-                        }
-                    }
-                    continue;
-                }
+        self.inject_prelude(&attrs);
 
-                if *attr_name == hir_expand::name![crate_type] {
-                    if let Some("proc-macro") = attr.string_value().map(SmolStr::as_str) {
-                        self.is_proc_macro = true;
-                    }
-                    continue;
-                }
+        // Process other crate-level attributes.
+        for attr in &*attrs {
+            let attr_name = match attr.path.as_ident() {
+                Some(name) => name,
+                None => continue,
+            };
 
-                if attr_name.as_text().as_deref() == Some("rustc_coherence_is_core") {
-                    self.def_map.rustc_coherence_is_core = true;
-                    continue;
+            if *attr_name == hir_expand::name![recursion_limit] {
+                if let Some(limit) = attr.string_value() {
+                    if let Ok(limit) = limit.parse() {
+                        self.def_map.recursion_limit = Some(limit);
+                    }
                 }
+                continue;
+            }
 
-                if *attr_name == hir_expand::name![feature] {
-                    let hygiene = &Hygiene::new_unhygienic();
-                    let features = attr
-                        .parse_path_comma_token_tree(self.db.upcast(), hygiene)
-                        .into_iter()
-                        .flatten()
-                        .filter_map(|feat| match feat.segments() {
-                            [name] => Some(name.to_smol_str()),
-                            _ => None,
-                        });
-                    self.def_map.unstable_features.extend(features);
+            if *attr_name == hir_expand::name![crate_type] {
+                if let Some("proc-macro") = attr.string_value().map(SmolStr::as_str) {
+                    self.is_proc_macro = true;
                 }
+                continue;
+            }
 
-                let attr_is_register_like = *attr_name == hir_expand::name![register_attr]
-                    || *attr_name == hir_expand::name![register_tool];
-                if !attr_is_register_like {
-                    continue;
-                }
+            if attr_name.as_text().as_deref() == Some("rustc_coherence_is_core") {
+                self.def_map.rustc_coherence_is_core = true;
+                continue;
+            }
 
-                let registered_name = match attr.single_ident_value() {
-                    Some(ident) => ident.as_name(),
-                    _ => continue,
-                };
+            if *attr_name == hir_expand::name![feature] {
+                let hygiene = &Hygiene::new_unhygienic();
+                let features = attr
+                    .parse_path_comma_token_tree(self.db.upcast(), hygiene)
+                    .into_iter()
+                    .flatten()
+                    .filter_map(|feat| match feat.segments() {
+                        [name] => Some(name.to_smol_str()),
+                        _ => None,
+                    });
+                self.def_map.unstable_features.extend(features);
+            }
 
-                if *attr_name == hir_expand::name![register_attr] {
-                    self.def_map.registered_attrs.push(registered_name.to_smol_str());
-                    cov_mark::hit!(register_attr);
-                } else {
-                    self.def_map.registered_tools.push(registered_name.to_smol_str());
-                    cov_mark::hit!(register_tool);
-                }
+            let attr_is_register_like = *attr_name == hir_expand::name![register_attr]
+                || *attr_name == hir_expand::name![register_tool];
+            if !attr_is_register_like {
+                continue;
             }
 
-            ModCollector {
-                def_collector: self,
-                macro_depth: 0,
-                module_id,
-                tree_id: TreeId::new(file_id.into(), None),
-                item_tree: &item_tree,
-                mod_dir: ModDir::root(),
+            let registered_name = match attr.single_ident_value() {
+                Some(ident) => ident.as_name(),
+                _ => continue,
+            };
+
+            if *attr_name == hir_expand::name![register_attr] {
+                self.def_map.registered_attrs.push(registered_name.to_smol_str());
+                cov_mark::hit!(register_attr);
+            } else {
+                self.def_map.registered_tools.push(registered_name.to_smol_str());
+                cov_mark::hit!(register_tool);
             }
-            .collect_in_top_module(item_tree.top_level_items());
         }
+
+        ModCollector {
+            def_collector: self,
+            macro_depth: 0,
+            module_id,
+            tree_id: TreeId::new(file_id.into(), None),
+            item_tree: &item_tree,
+            mod_dir: ModDir::root(),
+        }
+        .collect_in_top_module(item_tree.top_level_items());
     }
 
     fn seed_with_inner(&mut self, tree_id: TreeId) {
@@ -543,33 +547,26 @@ impl DefCollector<'_> {
             Edition::Edition2015 => PathKind::Plain,
             _ => PathKind::Abs,
         };
-        let path =
-            ModPath::from_segments(path_kind, [krate.clone(), name![prelude], edition].into_iter());
-        // Fall back to the older `std::prelude::v1` for compatibility with Rust <1.52.0
-        // FIXME remove this fallback
-        let fallback_path =
-            ModPath::from_segments(path_kind, [krate, name![prelude], name![v1]].into_iter());
-
-        for path in &[path, fallback_path] {
-            let (per_ns, _) = self.def_map.resolve_path(
-                self.db,
-                self.def_map.root,
-                path,
-                BuiltinShadowMode::Other,
-            );
+        let path = ModPath::from_segments(path_kind, [krate, name![prelude], edition]);
+
+        let (per_ns, _) = self.def_map.resolve_path(
+            self.db,
+            self.def_map.root,
+            &path,
+            BuiltinShadowMode::Other,
+            None,
+        );
 
-            match per_ns.types {
-                Some((ModuleDefId::ModuleId(m), _)) => {
-                    self.def_map.prelude = Some(m);
-                    break;
-                }
-                types => {
-                    tracing::debug!(
-                        "could not resolve prelude path `{}` to module (resolved to {:?})",
-                        path,
-                        types
-                    );
-                }
+        match per_ns.types {
+            Some((ModuleDefId::ModuleId(m), _)) => {
+                self.def_map.prelude = Some(m);
+            }
+            types => {
+                tracing::debug!(
+                    "could not resolve prelude path `{}` to module (resolved to {:?})",
+                    path,
+                    types
+                );
             }
         }
     }
@@ -715,6 +712,7 @@ impl DefCollector<'_> {
     }
 
     /// Import macros from `#[macro_use] extern crate`.
+    // FIXME: Support `#[macro_rules(macro_name, ...)]`.
     fn import_macros_from_extern_crate(
         &mut self,
         current_module_id: LocalModuleId,
@@ -733,7 +731,7 @@ impl DefCollector<'_> {
             }
 
             cov_mark::hit!(macro_rules_from_other_crates_are_visible_with_macro_use);
-            self.import_all_macros_exported(current_module_id, m.krate);
+            self.import_all_macros_exported(m.krate);
         }
     }
 
@@ -742,11 +740,12 @@ impl DefCollector<'_> {
     /// Exported macros are just all macros in the root module scope.
     /// Note that it contains not only all `#[macro_export]` macros, but also all aliases
     /// created by `use` in the root module, ignoring the visibility of `use`.
-    fn import_all_macros_exported(&mut self, current_module_id: LocalModuleId, krate: CrateId) {
+    fn import_all_macros_exported(&mut self, krate: CrateId) {
         let def_map = self.db.crate_def_map(krate);
         for (name, def) in def_map[def_map.root].scope.macros() {
-            // `#[macro_use]` brings macros into legacy scope. Yes, even non-`macro_rules!` macros.
-            self.define_legacy_macro(current_module_id, name.clone(), def);
+            // `#[macro_use]` brings macros into macro_use prelude. Yes, even non-`macro_rules!`
+            // macros.
+            self.def_map.macro_use_prelude.insert(name.clone(), def);
         }
     }
 
@@ -802,6 +801,7 @@ impl DefCollector<'_> {
                 module_id,
                 &import.path,
                 BuiltinShadowMode::Module,
+                None, // An import may resolve to any kind of macro.
             );
 
             let def = res.resolved_def;
@@ -1099,7 +1099,14 @@ impl DefCollector<'_> {
             resolved.push((directive.module_id, directive.depth, directive.container, call_id));
         };
         let mut res = ReachedFixedPoint::Yes;
+        // Retain unresolved macros after this round of resolution.
         macros.retain(|directive| {
+            let subns = match &directive.kind {
+                MacroDirectiveKind::FnLike { .. } => MacroSubNs::Bang,
+                MacroDirectiveKind::Attr { .. } | MacroDirectiveKind::Derive { .. } => {
+                    MacroSubNs::Attr
+                }
+            };
             let resolver = |path| {
                 let resolved_res = self.def_map.resolve_path_fp_with_macro(
                     self.db,
@@ -1107,6 +1114,7 @@ impl DefCollector<'_> {
                     directive.module_id,
                     &path,
                     BuiltinShadowMode::Module,
+                    Some(subns),
                 );
                 resolved_res
                     .resolved_def
@@ -1425,6 +1433,7 @@ impl DefCollector<'_> {
                                 directive.module_id,
                                 &path,
                                 BuiltinShadowMode::Module,
+                                Some(MacroSubNs::Bang),
                             );
                             resolved_res
                                 .resolved_def
@@ -1517,6 +1526,7 @@ impl ModCollector<'_, '_> {
 
     fn collect(&mut self, items: &[ModItem], container: ItemContainerId) {
         let krate = self.def_collector.def_map.krate;
+        let is_crate_root = self.module_id == self.def_collector.def_map.root;
 
         // Note: don't assert that inserted value is fresh: it's simply not true
         // for macros.
@@ -1524,19 +1534,24 @@ impl ModCollector<'_, '_> {
 
         // Prelude module is always considered to be `#[macro_use]`.
         if let Some(prelude_module) = self.def_collector.def_map.prelude {
-            if prelude_module.krate != krate {
+            if prelude_module.krate != krate && is_crate_root {
                 cov_mark::hit!(prelude_is_macro_use);
-                self.def_collector.import_all_macros_exported(self.module_id, prelude_module.krate);
+                self.def_collector.import_all_macros_exported(prelude_module.krate);
             }
         }
 
         // This should be processed eagerly instead of deferred to resolving.
         // `#[macro_use] extern crate` is hoisted to imports macros before collecting
         // any other items.
-        for &item in items {
-            let attrs = self.item_tree.attrs(self.def_collector.db, krate, item.into());
-            if attrs.cfg().map_or(true, |cfg| self.is_cfg_enabled(&cfg)) {
-                if let ModItem::ExternCrate(id) = item {
+        //
+        // If we're not at the crate root, `macro_use`d extern crates are an error so let's just
+        // ignore them.
+        // FIXME: Support `#[macro_rules(macro_name, ...)]`.
+        if is_crate_root {
+            for &item in items {
+                let ModItem::ExternCrate(id) = item else { continue; };
+                let attrs = self.item_tree.attrs(self.def_collector.db, krate, item.into());
+                if attrs.cfg().map_or(true, |cfg| self.is_cfg_enabled(&cfg)) {
                     let import = &self.item_tree[id];
                     let attrs = self.item_tree.attrs(
                         self.def_collector.db,
diff --git a/crates/hir-def/src/nameres/path_resolution.rs b/crates/hir-def/src/nameres/path_resolution.rs
index 8299d9684bb..4740fd7f449 100644
--- a/crates/hir-def/src/nameres/path_resolution.rs
+++ b/crates/hir-def/src/nameres/path_resolution.rs
@@ -16,7 +16,7 @@ use hir_expand::name::Name;
 use crate::{
     db::DefDatabase,
     item_scope::BUILTIN_SCOPE,
-    nameres::{BuiltinShadowMode, DefMap},
+    nameres::{sub_namespace_match, BuiltinShadowMode, DefMap, MacroSubNs},
     path::{ModPath, PathKind},
     per_ns::PerNs,
     visibility::{RawVisibility, Visibility},
@@ -58,6 +58,17 @@ impl ResolvePathResult {
     }
 }
 
+impl PerNs {
+    fn filter_macro(mut self, db: &dyn DefDatabase, expected: Option<MacroSubNs>) -> Self {
+        self.macros = self.macros.filter(|&(id, _)| {
+            let this = MacroSubNs::from_id(db, id);
+            sub_namespace_match(Some(this), expected)
+        });
+
+        self
+    }
+}
+
 impl DefMap {
     pub(super) fn resolve_name_in_extern_prelude(
         &self,
@@ -83,7 +94,7 @@ impl DefMap {
         let mut vis = match visibility {
             RawVisibility::Module(path) => {
                 let (result, remaining) =
-                    self.resolve_path(db, original_module, path, BuiltinShadowMode::Module);
+                    self.resolve_path(db, original_module, path, BuiltinShadowMode::Module, None);
                 if remaining.is_some() {
                     return None;
                 }
@@ -124,6 +135,9 @@ impl DefMap {
         mut original_module: LocalModuleId,
         path: &ModPath,
         shadow: BuiltinShadowMode,
+        // Pass `MacroSubNs` if we know we're resolving macro names and which kind of macro we're
+        // resolving them to. Pass `None` otherwise, e.g. when we're resolving import paths.
+        expected_macro_subns: Option<MacroSubNs>,
     ) -> ResolvePathResult {
         let mut result = ResolvePathResult::empty(ReachedFixedPoint::No);
 
@@ -136,6 +150,7 @@ impl DefMap {
                 original_module,
                 path,
                 shadow,
+                expected_macro_subns,
             );
 
             // Merge `new` into `result`.
@@ -169,6 +184,7 @@ impl DefMap {
         original_module: LocalModuleId,
         path: &ModPath,
         shadow: BuiltinShadowMode,
+        expected_macro_subns: Option<MacroSubNs>,
     ) -> ResolvePathResult {
         let graph = db.crate_graph();
         let _cx = stdx::panic_context::enter(format!(
@@ -220,7 +236,13 @@ impl DefMap {
                     if path.segments().len() == 1 { shadow } else { BuiltinShadowMode::Module };
 
                 tracing::debug!("resolving {:?} in module", segment);
-                self.resolve_name_in_module(db, original_module, segment, prefer_module)
+                self.resolve_name_in_module(
+                    db,
+                    original_module,
+                    segment,
+                    prefer_module,
+                    expected_macro_subns,
+                )
             }
             PathKind::Super(lvl) => {
                 let mut module = original_module;
@@ -245,6 +267,7 @@ impl DefMap {
                                     block.parent.local_id,
                                     &new_path,
                                     shadow,
+                                    expected_macro_subns,
                                 );
                             }
                             None => {
@@ -303,7 +326,12 @@ impl DefMap {
                         );
                         tracing::debug!("resolving {:?} in other crate", path);
                         let defp_map = module.def_map(db);
-                        let (def, s) = defp_map.resolve_path(db, module.local_id, &path, shadow);
+                        // Macro sub-namespaces only matter when resolving single-segment paths
+                        // because `macro_use` and other preludes should be taken into account. At
+                        // this point, we know we're resolving a multi-segment path so macro kind
+                        // expectation is discarded.
+                        let (def, s) =
+                            defp_map.resolve_path(db, module.local_id, &path, shadow, None);
                         return ResolvePathResult::with(
                             def,
                             ReachedFixedPoint::Yes,
@@ -381,19 +409,24 @@ impl DefMap {
         module: LocalModuleId,
         name: &Name,
         shadow: BuiltinShadowMode,
+        expected_macro_subns: Option<MacroSubNs>,
     ) -> PerNs {
         // Resolve in:
         //  - legacy scope of macro
         //  - current module / scope
-        //  - extern prelude
+        //  - extern prelude / macro_use prelude
         //  - std prelude
         let from_legacy_macro = self[module]
             .scope
             .get_legacy_macro(name)
             // FIXME: shadowing
             .and_then(|it| it.last())
-            .map_or_else(PerNs::none, |&m| PerNs::macros(m, Visibility::Public));
-        let from_scope = self[module].scope.get(name);
+            .copied()
+            .filter(|&id| {
+                sub_namespace_match(Some(MacroSubNs::from_id(db, id)), expected_macro_subns)
+            })
+            .map_or_else(PerNs::none, |m| PerNs::macros(m, Visibility::Public));
+        let from_scope = self[module].scope.get(name).filter_macro(db, expected_macro_subns);
         let from_builtin = match self.block {
             Some(_) => {
                 // Only resolve to builtins in the root `DefMap`.
@@ -414,9 +447,18 @@ impl DefMap {
                 .get(name)
                 .map_or(PerNs::none(), |&it| PerNs::types(it.into(), Visibility::Public))
         };
+        let macro_use_prelude = || {
+            self.macro_use_prelude
+                .get(name)
+                .map_or(PerNs::none(), |&it| PerNs::macros(it.into(), Visibility::Public))
+        };
         let prelude = || self.resolve_in_prelude(db, name);
 
-        from_legacy_macro.or(from_scope_or_builtin).or_else(extern_prelude).or_else(prelude)
+        from_legacy_macro
+            .or(from_scope_or_builtin)
+            .or_else(extern_prelude)
+            .or_else(macro_use_prelude)
+            .or_else(prelude)
     }
 
     fn resolve_name_in_crate_root_or_extern_prelude(
diff --git a/crates/hir-def/src/nameres/tests/macros.rs b/crates/hir-def/src/nameres/tests/macros.rs
index 6ee56c9368e..e795b7b9b7e 100644
--- a/crates/hir-def/src/nameres/tests/macros.rs
+++ b/crates/hir-def/src/nameres/tests/macros.rs
@@ -1216,17 +1216,112 @@ fn proc_attr(a: TokenStream, b: TokenStream) -> TokenStream { a }
     "#,
     );
 
-    let root = &def_map[def_map.root()].scope;
-    let actual = root
-        .legacy_macros()
-        .sorted_by(|a, b| std::cmp::Ord::cmp(&a.0, &b.0))
-        .map(|(name, _)| format!("{name}\n"))
-        .collect::<String>();
+    let root_module = &def_map[def_map.root()].scope;
+    assert!(
+        root_module.legacy_macros().count() == 0,
+        "`#[macro_use]` shouldn't bring macros into textual macro scope",
+    );
+
+    let actual = def_map.macro_use_prelude.iter().map(|(name, _)| name).sorted().join("\n");
 
     expect![[r#"
         legacy
         macro20
-        proc_attr
-    "#]]
+        proc_attr"#]]
     .assert_eq(&actual);
 }
+
+#[test]
+fn non_prelude_macros_take_precedence_over_macro_use_prelude() {
+    check(
+        r#"
+//- /lib.rs edition:2021 crate:lib deps:dep,core
+#[macro_use]
+extern crate dep;
+
+macro foo() { struct Ok; }
+macro bar() { fn ok() {} }
+
+foo!();
+bar!();
+
+//- /dep.rs crate:dep
+#[macro_export]
+macro_rules! foo {
+    () => { struct NotOk; }
+}
+
+//- /core.rs crate:core
+pub mod prelude {
+    pub mod rust_2021 {
+        #[macro_export]
+        macro_rules! bar {
+            () => { fn not_ok() {} }
+        }
+    }
+}
+        "#,
+        expect![[r#"
+            crate
+            Ok: t v
+            bar: m
+            dep: t
+            foo: m
+            ok: v
+        "#]],
+    );
+}
+
+#[test]
+fn macro_sub_namespace() {
+    let map = compute_crate_def_map(
+        r#"
+//- minicore: derive, clone
+macro_rules! Clone { () => {} }
+macro_rules! derive { () => {} }
+
+#[derive(Clone)]
+struct S;
+    "#,
+    );
+    assert_eq!(map.modules[map.root].scope.impls().len(), 1);
+}
+
+#[test]
+fn macro_sub_namespace2() {
+    check(
+        r#"
+//- /main.rs edition:2021 crate:main deps:proc,core
+use proc::{foo, bar};
+
+foo!();
+bar!();
+
+//- /proc.rs crate:proc
+#![crate_type="proc-macro"]
+#[proc_macro_derive(foo)]
+pub fn foo() {}
+#[proc_macro_attribute]
+pub fn bar() {}
+
+//- /core.rs crate:core
+pub mod prelude {
+    pub mod rust_2021 {
+        pub macro foo() {
+            struct Ok;
+        }
+        pub macro bar() {
+            fn ok() {}
+        }
+    }
+}
+    "#,
+        expect![[r#"
+            crate
+            Ok: t v
+            bar: m
+            foo: m
+            ok: v
+        "#]],
+    );
+}
diff --git a/crates/hir-def/src/resolver.rs b/crates/hir-def/src/resolver.rs
index 45ec454b9eb..4bec2b4dea4 100644
--- a/crates/hir-def/src/resolver.rs
+++ b/crates/hir-def/src/resolver.rs
@@ -17,7 +17,7 @@ use crate::{
     hir::{BindingId, ExprId, LabelId},
     item_scope::{BuiltinShadowMode, BUILTIN_SCOPE},
     lang_item::LangItemTarget,
-    nameres::DefMap,
+    nameres::{DefMap, MacroSubNs},
     path::{ModPath, Path, PathKind},
     per_ns::PerNs,
     visibility::{RawVisibility, Visibility},
@@ -155,7 +155,8 @@ impl Resolver {
         path: &ModPath,
     ) -> Option<PerNs> {
         let (item_map, module) = self.item_scope();
-        let (module_res, idx) = item_map.resolve_path(db, module, path, BuiltinShadowMode::Module);
+        let (module_res, idx) =
+            item_map.resolve_path(db, module, path, BuiltinShadowMode::Module, None);
         match module_res.take_types()? {
             ModuleDefId::TraitId(it) => {
                 let idx = idx?;
@@ -385,9 +386,17 @@ impl Resolver {
         }
     }
 
-    pub fn resolve_path_as_macro(&self, db: &dyn DefDatabase, path: &ModPath) -> Option<MacroId> {
+    pub fn resolve_path_as_macro(
+        &self,
+        db: &dyn DefDatabase,
+        path: &ModPath,
+        expected_macro_kind: Option<MacroSubNs>,
+    ) -> Option<MacroId> {
         let (item_map, module) = self.item_scope();
-        item_map.resolve_path(db, module, path, BuiltinShadowMode::Other).0.take_macros()
+        item_map
+            .resolve_path(db, module, path, BuiltinShadowMode::Other, expected_macro_kind)
+            .0
+            .take_macros()
     }
 
     /// Returns a set of names available in the current scope.
@@ -626,7 +635,8 @@ impl Resolver {
         shadow: BuiltinShadowMode,
     ) -> PerNs {
         let (item_map, module) = self.item_scope();
-        let (module_res, segment_index) = item_map.resolve_path(db, module, path, shadow);
+        // This method resolves `path` just like import paths, so no expected macro subns is given.
+        let (module_res, segment_index) = item_map.resolve_path(db, module, path, shadow, None);
         if segment_index.is_some() {
             return PerNs::none();
         }
diff --git a/crates/hir-expand/src/builtin_fn_macro.rs b/crates/hir-expand/src/builtin_fn_macro.rs
index 9a25141d8f1..9c8dc4ed1fc 100644
--- a/crates/hir-expand/src/builtin_fn_macro.rs
+++ b/crates/hir-expand/src/builtin_fn_macro.rs
@@ -135,9 +135,8 @@ fn line_expand(
     _tt: &tt::Subtree,
 ) -> ExpandResult<tt::Subtree> {
     // dummy implementation for type-checking purposes
-    let line_num = 0;
     let expanded = quote! {
-        #line_num
+        0 as u32
     };
 
     ExpandResult::ok(expanded)
@@ -179,9 +178,8 @@ fn column_expand(
     _tt: &tt::Subtree,
 ) -> ExpandResult<tt::Subtree> {
     // dummy implementation for type-checking purposes
-    let col_num = 0;
     let expanded = quote! {
-        #col_num
+        0 as u32
     };
 
     ExpandResult::ok(expanded)
diff --git a/crates/hir-ty/src/lower.rs b/crates/hir-ty/src/lower.rs
index 0f823580cba..0c68891fe49 100644
--- a/crates/hir-ty/src/lower.rs
+++ b/crates/hir-ty/src/lower.rs
@@ -24,6 +24,7 @@ use hir_def::{
         TypeOrConstParamData, TypeParamProvenance, WherePredicate, WherePredicateTypeTarget,
     },
     lang_item::{lang_attr, LangItem},
+    nameres::MacroSubNs,
     path::{GenericArg, GenericArgs, ModPath, Path, PathKind, PathSegment, PathSegments},
     resolver::{HasResolver, Resolver, TypeNs},
     type_ref::{ConstRefOrPath, TraitBoundModifier, TraitRef as HirTraitRef, TypeBound, TypeRef},
@@ -378,9 +379,15 @@ impl<'a> TyLoweringContext<'a> {
                 };
                 let ty = {
                     let macro_call = macro_call.to_node(self.db.upcast());
-                    match expander.enter_expand::<ast::Type>(self.db.upcast(), macro_call, |path| {
-                        self.resolver.resolve_path_as_macro(self.db.upcast(), &path)
-                    }) {
+                    let resolver = |path| {
+                        self.resolver.resolve_path_as_macro(
+                            self.db.upcast(),
+                            &path,
+                            Some(MacroSubNs::Bang),
+                        )
+                    };
+                    match expander.enter_expand::<ast::Type>(self.db.upcast(), macro_call, resolver)
+                    {
                         Ok(ExpandResult { value: Some((mark, expanded)), .. }) => {
                             let ctx = expander.ctx(self.db.upcast());
                             // FIXME: Report syntax errors in expansion here
diff --git a/crates/hir-ty/src/tests/macros.rs b/crates/hir-ty/src/tests/macros.rs
index d45edf730ad..9377a3a5f26 100644
--- a/crates/hir-ty/src/tests/macros.rs
+++ b/crates/hir-ty/src/tests/macros.rs
@@ -661,8 +661,9 @@ fn infer_builtin_macros_line() {
         "#,
         expect![[r#"
             !0..1 '0': i32
+            !0..6 '0asu32': u32
             63..87 '{     ...!(); }': ()
-            73..74 'x': i32
+            73..74 'x': u32
         "#]],
     );
 }
@@ -699,8 +700,9 @@ fn infer_builtin_macros_column() {
         "#,
         expect![[r#"
             !0..1 '0': i32
+            !0..6 '0asu32': u32
             65..91 '{     ...!(); }': ()
-            75..76 'x': i32
+            75..76 'x': u32
         "#]],
     );
 }
diff --git a/crates/hir/src/attrs.rs b/crates/hir/src/attrs.rs
index d025aa8f5a4..b817937296d 100644
--- a/crates/hir/src/attrs.rs
+++ b/crates/hir/src/attrs.rs
@@ -4,7 +4,6 @@ use hir_def::{
     attr::{AttrsWithOwner, Documentation},
     item_scope::ItemInNs,
     path::ModPath,
-    per_ns::PerNs,
     resolver::HasResolver,
     AttrDefId, GenericParamId, ModuleDefId,
 };
@@ -121,6 +120,7 @@ impl HasAttrs for AssocItem {
     }
 }
 
+/// Resolves the item `link` points to in the scope of `def`.
 fn resolve_doc_path(
     db: &dyn HirDatabase,
     def: AttrDefId,
@@ -155,14 +155,14 @@ fn resolve_doc_path(
             .syntax_node()
             .descendants()
             .find_map(ast::Path::cast)?;
-        if ast_path.to_string() != link {
+        if ast_path.syntax().text() != link {
             return None;
         }
         ModPath::from_src(db.upcast(), ast_path, &Hygiene::new_unhygienic())?
     };
 
     let resolved = resolver.resolve_module_path_in_items(db.upcast(), &modpath);
-    let resolved = if resolved == PerNs::none() {
+    let resolved = if resolved.is_none() {
         resolver.resolve_module_path_in_trait_assoc_items(db.upcast(), &modpath)?
     } else {
         resolved
diff --git a/crates/hir/src/semantics.rs b/crates/hir/src/semantics.rs
index 81ea99522f7..2d2b00b147e 100644
--- a/crates/hir/src/semantics.rs
+++ b/crates/hir/src/semantics.rs
@@ -10,6 +10,7 @@ use hir_def::{
     hir::Expr,
     lower::LowerCtx,
     macro_id_to_def_id,
+    nameres::MacroSubNs,
     resolver::{self, HasResolver, Resolver, TypeNs},
     type_ref::Mutability,
     AsMacroCall, DefWithBodyId, FieldId, FunctionId, MacroId, TraitId, VariantId,
@@ -616,7 +617,7 @@ impl<'db> SemanticsImpl<'db> {
         let krate = resolver.krate();
         let macro_call_id = macro_call.as_call_id(self.db.upcast(), krate, |path| {
             resolver
-                .resolve_path_as_macro(self.db.upcast(), &path)
+                .resolve_path_as_macro(self.db.upcast(), &path, Some(MacroSubNs::Bang))
                 .map(|it| macro_id_to_def_id(self.db.upcast(), it))
         })?;
         hir_expand::db::expand_speculative(
diff --git a/crates/hir/src/source_analyzer.rs b/crates/hir/src/source_analyzer.rs
index 159601955f8..dae77fad2f3 100644
--- a/crates/hir/src/source_analyzer.rs
+++ b/crates/hir/src/source_analyzer.rs
@@ -17,6 +17,7 @@ use hir_def::{
     lang_item::LangItem,
     lower::LowerCtx,
     macro_id_to_def_id,
+    nameres::MacroSubNs,
     path::{ModPath, Path, PathKind},
     resolver::{resolver_for_scope, Resolver, TypeNs, ValueNs},
     type_ref::Mutability,
@@ -484,7 +485,9 @@ impl SourceAnalyzer {
     ) -> Option<Macro> {
         let ctx = LowerCtx::with_file_id(db.upcast(), macro_call.file_id);
         let path = macro_call.value.path().and_then(|ast| Path::from_src(ast, &ctx))?;
-        self.resolver.resolve_path_as_macro(db.upcast(), path.mod_path()?).map(|it| it.into())
+        self.resolver
+            .resolve_path_as_macro(db.upcast(), path.mod_path()?, Some(MacroSubNs::Bang))
+            .map(|it| it.into())
     }
 
     pub(crate) fn resolve_bind_pat_to_const(
@@ -678,7 +681,7 @@ impl SourceAnalyzer {
                     }
                 }
             }
-            return match resolve_hir_path_as_macro(db, &self.resolver, &hir_path) {
+            return match resolve_hir_path_as_attr_macro(db, &self.resolver, &hir_path) {
                 Some(m) => Some(PathResolution::Def(ModuleDef::Macro(m))),
                 // this labels any path that starts with a tool module as the tool itself, this is technically wrong
                 // but there is no benefit in differentiating these two cases for the time being
@@ -756,7 +759,7 @@ impl SourceAnalyzer {
         let krate = self.resolver.krate();
         let macro_call_id = macro_call.as_call_id(db.upcast(), krate, |path| {
             self.resolver
-                .resolve_path_as_macro(db.upcast(), &path)
+                .resolve_path_as_macro(db.upcast(), &path, Some(MacroSubNs::Bang))
                 .map(|it| macro_id_to_def_id(db.upcast(), it))
         })?;
         Some(macro_call_id.as_file()).filter(|it| it.expansion_level(db.upcast()) < 64)
@@ -956,12 +959,14 @@ pub(crate) fn resolve_hir_path(
 }
 
 #[inline]
-pub(crate) fn resolve_hir_path_as_macro(
+pub(crate) fn resolve_hir_path_as_attr_macro(
     db: &dyn HirDatabase,
     resolver: &Resolver,
     path: &Path,
 ) -> Option<Macro> {
-    resolver.resolve_path_as_macro(db.upcast(), path.mod_path()?).map(Into::into)
+    resolver
+        .resolve_path_as_macro(db.upcast(), path.mod_path()?, Some(MacroSubNs::Attr))
+        .map(Into::into)
 }
 
 fn resolve_hir_path_(
@@ -1060,7 +1065,7 @@ fn resolve_hir_path_(
 
     let macros = || {
         resolver
-            .resolve_path_as_macro(db.upcast(), path.mod_path()?)
+            .resolve_path_as_macro(db.upcast(), path.mod_path()?, None)
             .map(|def| PathResolution::Def(ModuleDef::Macro(def.into())))
     };