about summary refs log tree commit diff
path: root/compiler/rustc_resolve/src
diff options
context:
space:
mode:
Diffstat (limited to 'compiler/rustc_resolve/src')
-rw-r--r--compiler/rustc_resolve/src/build_reduced_graph.rs40
-rw-r--r--compiler/rustc_resolve/src/diagnostics.rs9
-rw-r--r--compiler/rustc_resolve/src/imports.rs48
-rw-r--r--compiler/rustc_resolve/src/late/diagnostics.rs9
-rw-r--r--compiler/rustc_resolve/src/late/lifetimes.rs4
-rw-r--r--compiler/rustc_resolve/src/lib.rs6
-rw-r--r--compiler/rustc_resolve/src/macros.rs134
7 files changed, 145 insertions, 105 deletions
diff --git a/compiler/rustc_resolve/src/build_reduced_graph.rs b/compiler/rustc_resolve/src/build_reduced_graph.rs
index 493b9f15271..06e9969697d 100644
--- a/compiler/rustc_resolve/src/build_reduced_graph.rs
+++ b/compiler/rustc_resolve/src/build_reduced_graph.rs
@@ -258,7 +258,16 @@ impl<'a, 'b> BuildReducedGraphVisitor<'a, 'b> {
                 Ok(ty::Visibility::Restricted(DefId::local(CRATE_DEF_INDEX)))
             }
             ast::VisibilityKind::Inherited => {
-                Ok(ty::Visibility::Restricted(parent_scope.module.normal_ancestor_id))
+                if matches!(self.parent_scope.module.kind, ModuleKind::Def(DefKind::Enum, _, _)) {
+                    // Any inherited visibility resolved directly inside an enum
+                    // (e.g. variants or fields) inherits from the visibility of the enum.
+                    let parent_enum = self.parent_scope.module.def_id().unwrap().expect_local();
+                    Ok(self.r.visibilities[&parent_enum])
+                } else {
+                    // If it's not in an enum, its visibility is restricted to the `mod` item
+                    // that it's defined in.
+                    Ok(ty::Visibility::Restricted(self.parent_scope.module.normal_ancestor_id))
+                }
             }
             ast::VisibilityKind::Restricted { ref path, id, .. } => {
                 // For visibilities we are not ready to provide correct implementation of "uniform
@@ -1155,14 +1164,18 @@ impl<'a, 'b> BuildReducedGraphVisitor<'a, 'b> {
         false
     }
 
-    fn visit_invoc(&mut self, id: NodeId) -> MacroRulesScopeRef<'a> {
+    fn visit_invoc(&mut self, id: NodeId) -> ExpnId {
         let invoc_id = id.placeholder_to_expn_id();
-
-        self.parent_scope.module.unexpanded_invocations.borrow_mut().insert(invoc_id);
-
         let old_parent_scope = self.r.invocation_parent_scopes.insert(invoc_id, self.parent_scope);
         assert!(old_parent_scope.is_none(), "invocation data is reset for an invocation");
+        invoc_id
+    }
 
+    /// Visit invocation in context in which it can emit a named item (possibly `macro_rules`)
+    /// directly into its parent scope's module.
+    fn visit_invoc_in_module(&mut self, id: NodeId) -> MacroRulesScopeRef<'a> {
+        let invoc_id = self.visit_invoc(id);
+        self.parent_scope.module.unexpanded_invocations.borrow_mut().insert(invoc_id);
         self.r.arenas.alloc_macro_rules_scope(MacroRulesScope::Invocation(invoc_id))
     }
 
@@ -1291,7 +1304,7 @@ impl<'a, 'b> Visitor<'b> for BuildReducedGraphVisitor<'a, 'b> {
                 return;
             }
             ItemKind::MacCall(..) => {
-                self.parent_scope.macro_rules = self.visit_invoc(item.id);
+                self.parent_scope.macro_rules = self.visit_invoc_in_module(item.id);
                 return;
             }
             ItemKind::Mod(..) => self.contains_macro_use(&item.attrs),
@@ -1309,7 +1322,7 @@ impl<'a, 'b> Visitor<'b> for BuildReducedGraphVisitor<'a, 'b> {
 
     fn visit_stmt(&mut self, stmt: &'b ast::Stmt) {
         if let ast::StmtKind::MacCall(..) = stmt.kind {
-            self.parent_scope.macro_rules = self.visit_invoc(stmt.id);
+            self.parent_scope.macro_rules = self.visit_invoc_in_module(stmt.id);
         } else {
             visit::walk_stmt(self, stmt);
         }
@@ -1317,7 +1330,7 @@ impl<'a, 'b> Visitor<'b> for BuildReducedGraphVisitor<'a, 'b> {
 
     fn visit_foreign_item(&mut self, foreign_item: &'b ForeignItem) {
         if let ForeignItemKind::MacCall(_) = foreign_item.kind {
-            self.visit_invoc(foreign_item.id);
+            self.visit_invoc_in_module(foreign_item.id);
             return;
         }
 
@@ -1336,7 +1349,14 @@ impl<'a, 'b> Visitor<'b> for BuildReducedGraphVisitor<'a, 'b> {
 
     fn visit_assoc_item(&mut self, item: &'b AssocItem, ctxt: AssocCtxt) {
         if let AssocItemKind::MacCall(_) = item.kind {
-            self.visit_invoc(item.id);
+            match ctxt {
+                AssocCtxt::Trait => {
+                    self.visit_invoc_in_module(item.id);
+                }
+                AssocCtxt::Impl => {
+                    self.visit_invoc(item.id);
+                }
+            }
             return;
         }
 
@@ -1460,7 +1480,7 @@ impl<'a, 'b> Visitor<'b> for BuildReducedGraphVisitor<'a, 'b> {
     // type and value namespaces.
     fn visit_variant(&mut self, variant: &'b ast::Variant) {
         if variant.is_placeholder {
-            self.visit_invoc(variant.id);
+            self.visit_invoc_in_module(variant.id);
             return;
         }
 
diff --git a/compiler/rustc_resolve/src/diagnostics.rs b/compiler/rustc_resolve/src/diagnostics.rs
index acd88af1806..809de9beff6 100644
--- a/compiler/rustc_resolve/src/diagnostics.rs
+++ b/compiler/rustc_resolve/src/diagnostics.rs
@@ -1,7 +1,6 @@
 use std::cmp::Reverse;
 use std::ptr;
 
-use rustc_ast::util::lev_distance::find_best_match_for_name;
 use rustc_ast::{self as ast, Path};
 use rustc_ast_pretty::pprust;
 use rustc_data_structures::fx::FxHashSet;
@@ -14,6 +13,7 @@ use rustc_middle::bug;
 use rustc_middle::ty::{self, DefIdTree};
 use rustc_session::Session;
 use rustc_span::hygiene::MacroKind;
+use rustc_span::lev_distance::find_best_match_for_name;
 use rustc_span::source_map::SourceMap;
 use rustc_span::symbol::{kw, sym, Ident, Symbol};
 use rustc_span::{BytePos, MultiSpan, Span};
@@ -143,7 +143,7 @@ impl<'a> Resolver<'a> {
                     _ => {
                         bug!(
                             "GenericParamsFromOuterFunction should only be used with Res::SelfTy, \
-                            DefKind::TyParam"
+                            DefKind::TyParam or DefKind::ConstParam"
                         );
                     }
                 }
@@ -481,6 +481,7 @@ impl<'a> Resolver<'a> {
                         name
                     ));
                 }
+                err.help("use `#![feature(const_generics)]` and `#![feature(const_evaluatable_checked)]` to allow generic const expressions");
 
                 err
             }
@@ -609,7 +610,7 @@ impl<'a> Resolver<'a> {
                     }
                 }
                 Scope::DeriveHelpersCompat => {
-                    let res = Res::NonMacroAttr(NonMacroAttrKind::DeriveHelper);
+                    let res = Res::NonMacroAttr(NonMacroAttrKind::DeriveHelperCompat);
                     if filter_fn(res) {
                         for derive in parent_scope.derives {
                             let parent_scope = &ParentScope { derives: &[], ..*parent_scope };
@@ -715,7 +716,7 @@ impl<'a> Resolver<'a> {
         suggestions.sort_by_cached_key(|suggestion| suggestion.candidate.as_str());
 
         match find_best_match_for_name(
-            suggestions.iter().map(|suggestion| &suggestion.candidate),
+            &suggestions.iter().map(|suggestion| suggestion.candidate).collect::<Vec<Symbol>>(),
             ident.name,
             None,
         ) {
diff --git a/compiler/rustc_resolve/src/imports.rs b/compiler/rustc_resolve/src/imports.rs
index 026cf8be738..cb1f0834ce7 100644
--- a/compiler/rustc_resolve/src/imports.rs
+++ b/compiler/rustc_resolve/src/imports.rs
@@ -10,7 +10,6 @@ use crate::{CrateLint, Module, ModuleOrUniformRoot, ParentScope, PerNS, ScopeSet
 use crate::{NameBinding, NameBindingKind, PathResult, PrivacyError, ToNameBinding};
 
 use rustc_ast::unwrap_or;
-use rustc_ast::util::lev_distance::find_best_match_for_name;
 use rustc_ast::NodeId;
 use rustc_ast_lowering::ResolverAstLowering;
 use rustc_data_structures::fx::FxHashSet;
@@ -25,6 +24,7 @@ use rustc_session::lint::builtin::{PUB_USE_OF_PRIVATE_EXTERN_CRATE, UNUSED_IMPOR
 use rustc_session::lint::BuiltinLintDiagnostics;
 use rustc_session::DiagnosticMessageId;
 use rustc_span::hygiene::ExpnId;
+use rustc_span::lev_distance::find_best_match_for_name;
 use rustc_span::symbol::{kw, Ident, Symbol};
 use rustc_span::{MultiSpan, Span};
 
@@ -1096,33 +1096,37 @@ impl<'a, 'b> ImportResolver<'a, 'b> {
                     _ => None,
                 };
                 let resolutions = resolutions.as_ref().into_iter().flat_map(|r| r.iter());
-                let names = resolutions.filter_map(|(BindingKey { ident: i, .. }, resolution)| {
-                    if *i == ident {
-                        return None;
-                    } // Never suggest the same name
-                    match *resolution.borrow() {
-                        NameResolution { binding: Some(name_binding), .. } => {
-                            match name_binding.kind {
-                                NameBindingKind::Import { binding, .. } => {
-                                    match binding.kind {
-                                        // Never suggest the name that has binding error
-                                        // i.e., the name that cannot be previously resolved
-                                        NameBindingKind::Res(Res::Err, _) => None,
-                                        _ => Some(&i.name),
+                let names = resolutions
+                    .filter_map(|(BindingKey { ident: i, .. }, resolution)| {
+                        if *i == ident {
+                            return None;
+                        } // Never suggest the same name
+                        match *resolution.borrow() {
+                            NameResolution { binding: Some(name_binding), .. } => {
+                                match name_binding.kind {
+                                    NameBindingKind::Import { binding, .. } => {
+                                        match binding.kind {
+                                            // Never suggest the name that has binding error
+                                            // i.e., the name that cannot be previously resolved
+                                            NameBindingKind::Res(Res::Err, _) => None,
+                                            _ => Some(i.name),
+                                        }
                                     }
+                                    _ => Some(i.name),
                                 }
-                                _ => Some(&i.name),
                             }
+                            NameResolution { ref single_imports, .. }
+                                if single_imports.is_empty() =>
+                            {
+                                None
+                            }
+                            _ => Some(i.name),
                         }
-                        NameResolution { ref single_imports, .. } if single_imports.is_empty() => {
-                            None
-                        }
-                        _ => Some(&i.name),
-                    }
-                });
+                    })
+                    .collect::<Vec<Symbol>>();
 
                 let lev_suggestion =
-                    find_best_match_for_name(names, ident.name, None).map(|suggestion| {
+                    find_best_match_for_name(&names, ident.name, None).map(|suggestion| {
                         (
                             vec![(ident.span, suggestion.to_string())],
                             String::from("a similar name exists in the module"),
diff --git a/compiler/rustc_resolve/src/late/diagnostics.rs b/compiler/rustc_resolve/src/late/diagnostics.rs
index 2473436a916..6ce299a9417 100644
--- a/compiler/rustc_resolve/src/late/diagnostics.rs
+++ b/compiler/rustc_resolve/src/late/diagnostics.rs
@@ -5,7 +5,6 @@ use crate::path_names_to_string;
 use crate::{CrateLint, Module, ModuleKind, ModuleOrUniformRoot};
 use crate::{PathResult, PathSource, Segment};
 
-use rustc_ast::util::lev_distance::find_best_match_for_name;
 use rustc_ast::visit::FnKind;
 use rustc_ast::{self as ast, Expr, ExprKind, Item, ItemKind, NodeId, Path, Ty, TyKind};
 use rustc_ast_pretty::pprust::path_segment_to_string;
@@ -18,6 +17,7 @@ use rustc_hir::def_id::{DefId, CRATE_DEF_INDEX, LOCAL_CRATE};
 use rustc_hir::PrimTy;
 use rustc_session::parse::feature_err;
 use rustc_span::hygiene::MacroKind;
+use rustc_span::lev_distance::find_best_match_for_name;
 use rustc_span::symbol::{kw, sym, Ident, Symbol};
 use rustc_span::{BytePos, MultiSpan, Span, DUMMY_SP};
 
@@ -1206,7 +1206,7 @@ impl<'a: 'ast, 'ast> LateResolutionVisitor<'a, '_, 'ast> {
         names.sort_by_cached_key(|suggestion| suggestion.candidate.as_str());
 
         match find_best_match_for_name(
-            names.iter().map(|suggestion| &suggestion.candidate),
+            &names.iter().map(|suggestion| suggestion.candidate).collect::<Vec<Symbol>>(),
             name,
             None,
         ) {
@@ -1592,9 +1592,10 @@ impl<'a: 'ast, 'ast> LateResolutionVisitor<'a, '_, 'ast> {
             .bindings
             .iter()
             .filter(|(id, _)| id.span.ctxt() == label.span.ctxt())
-            .map(|(id, _)| &id.name);
+            .map(|(id, _)| id.name)
+            .collect::<Vec<Symbol>>();
 
-        find_best_match_for_name(names, label.name, None).map(|symbol| {
+        find_best_match_for_name(&names, label.name, None).map(|symbol| {
             // Upon finding a similar name, get the ident that it was from - the span
             // contained within helps make a useful diagnostic. In addition, determine
             // whether this candidate is within scope.
diff --git a/compiler/rustc_resolve/src/late/lifetimes.rs b/compiler/rustc_resolve/src/late/lifetimes.rs
index c79d670737e..69f28045bb5 100644
--- a/compiler/rustc_resolve/src/late/lifetimes.rs
+++ b/compiler/rustc_resolve/src/late/lifetimes.rs
@@ -388,7 +388,7 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
             hir::ItemKind::ExternCrate(_)
             | hir::ItemKind::Use(..)
             | hir::ItemKind::Mod(..)
-            | hir::ItemKind::ForeignMod(..)
+            | hir::ItemKind::ForeignMod { .. }
             | hir::ItemKind::GlobalAsm(..) => {
                 // These sorts of items have no lifetime parameters at all.
                 intravisit::walk_item(self, item);
@@ -1098,7 +1098,7 @@ fn signal_shadowing_problem(tcx: TyCtxt<'_>, name: Symbol, orig: Original, shado
         )
     };
     err.span_label(orig.span, "first declared here");
-    err.span_label(shadower.span, format!("lifetime {} already in scope", name));
+    err.span_label(shadower.span, format!("{} `{}` already in scope", orig.kind.desc(), name));
     err.emit();
 }
 
diff --git a/compiler/rustc_resolve/src/lib.rs b/compiler/rustc_resolve/src/lib.rs
index d18335ef2e6..f764fbc3f8d 100644
--- a/compiler/rustc_resolve/src/lib.rs
+++ b/compiler/rustc_resolve/src/lib.rs
@@ -403,6 +403,7 @@ enum PathResult<'a> {
     },
 }
 
+#[derive(Debug)]
 enum ModuleKind {
     /// An anonymous module; e.g., just a block.
     ///
@@ -2539,6 +2540,7 @@ impl<'a> Resolver<'a> {
         span: Span,
         all_ribs: &[Rib<'a>],
     ) -> Res {
+        const CG_BUG_STR: &str = "min_const_generics resolve check didn't stop compilation";
         debug!("validate_res_from_ribs({:?})", res);
         let ribs = &all_ribs[rib_index + 1..];
 
@@ -2639,6 +2641,8 @@ impl<'a> Resolver<'a> {
                                             },
                                         );
                                     }
+
+                                    self.session.delay_span_bug(span, CG_BUG_STR);
                                     return Res::Err;
                                 }
                             }
@@ -2720,6 +2724,8 @@ impl<'a> Resolver<'a> {
                                         },
                                     );
                                 }
+
+                                self.session.delay_span_bug(span, CG_BUG_STR);
                                 return Res::Err;
                             }
 
diff --git a/compiler/rustc_resolve/src/macros.rs b/compiler/rustc_resolve/src/macros.rs
index e052b6b3345..c8dbe685128 100644
--- a/compiler/rustc_resolve/src/macros.rs
+++ b/compiler/rustc_resolve/src/macros.rs
@@ -12,24 +12,24 @@ use rustc_ast_pretty::pprust;
 use rustc_attr::StabilityLevel;
 use rustc_data_structures::fx::FxHashSet;
 use rustc_data_structures::ptr_key::PtrKey;
+use rustc_data_structures::sync::Lrc;
 use rustc_errors::struct_span_err;
 use rustc_expand::base::{Indeterminate, InvocationRes, ResolverExpand, SyntaxExtension};
 use rustc_expand::compile_declarative_macro;
-use rustc_expand::expand::{AstFragment, AstFragmentKind, Invocation, InvocationKind};
+use rustc_expand::expand::{AstFragment, Invocation, InvocationKind};
 use rustc_feature::is_builtin_attr_name;
 use rustc_hir::def::{self, DefKind, NonMacroAttrKind};
 use rustc_hir::def_id;
 use rustc_middle::middle::stability;
 use rustc_middle::ty;
-use rustc_session::lint::builtin::UNUSED_MACROS;
+use rustc_session::lint::builtin::{SOFT_UNSTABLE, UNUSED_MACROS};
+use rustc_session::parse::feature_err;
 use rustc_session::Session;
 use rustc_span::edition::Edition;
 use rustc_span::hygiene::{self, ExpnData, ExpnId, ExpnKind};
+use rustc_span::hygiene::{AstPass, MacroKind};
 use rustc_span::symbol::{kw, sym, Ident, Symbol};
 use rustc_span::{Span, DUMMY_SP};
-
-use rustc_data_structures::sync::Lrc;
-use rustc_span::hygiene::{AstPass, MacroKind};
 use std::cell::Cell;
 use std::{mem, ptr};
 
@@ -241,15 +241,20 @@ impl<'a> ResolverExpand for Resolver<'a> {
             }
         };
 
-        let (path, kind, derives, after_derive) = match invoc.kind {
+        let (path, kind, inner_attr, derives, after_derive) = match invoc.kind {
             InvocationKind::Attr { ref attr, ref derives, after_derive, .. } => (
                 &attr.get_normal_item().path,
                 MacroKind::Attr,
+                attr.style == ast::AttrStyle::Inner,
                 self.arenas.alloc_ast_paths(derives),
                 after_derive,
             ),
-            InvocationKind::Bang { ref mac, .. } => (&mac.path, MacroKind::Bang, &[][..], false),
-            InvocationKind::Derive { ref path, .. } => (path, MacroKind::Derive, &[][..], false),
+            InvocationKind::Bang { ref mac, .. } => {
+                (&mac.path, MacroKind::Bang, false, &[][..], false)
+            }
+            InvocationKind::Derive { ref path, .. } => {
+                (path, MacroKind::Derive, false, &[][..], false)
+            }
             InvocationKind::DeriveContainer { ref derives, .. } => {
                 // Block expansion of the container until we resolve all derives in it.
                 // This is required for two reasons:
@@ -281,7 +286,7 @@ impl<'a> ResolverExpand for Resolver<'a> {
                                     ext.helper_attrs.iter().map(|name| Ident::new(*name, span)),
                                 );
                                 if ext.is_derive_copy {
-                                    self.add_derive_copy(invoc_id);
+                                    self.containers_deriving_copy.insert(invoc_id);
                                 }
                                 ext
                             }
@@ -299,8 +304,17 @@ impl<'a> ResolverExpand for Resolver<'a> {
 
         // Derives are not included when `invocations` are collected, so we have to add them here.
         let parent_scope = &ParentScope { derives, ..parent_scope };
+        let require_inert = !invoc.fragment_kind.supports_macro_expansion();
         let node_id = self.lint_node_id(eager_expansion_root);
-        let (ext, res) = self.smart_resolve_macro_path(path, kind, parent_scope, node_id, force)?;
+        let (ext, res) = self.smart_resolve_macro_path(
+            path,
+            kind,
+            require_inert,
+            inner_attr,
+            parent_scope,
+            node_id,
+            force,
+        )?;
 
         let span = invoc.span();
         invoc_id.set_expn_data(ext.expn_data(
@@ -318,29 +332,6 @@ impl<'a> ResolverExpand for Resolver<'a> {
             self.definitions.add_parent_module_of_macro_def(invoc_id, normal_module_def_id);
         }
 
-        match invoc.fragment_kind {
-            AstFragmentKind::Arms
-            | AstFragmentKind::Fields
-            | AstFragmentKind::FieldPats
-            | AstFragmentKind::GenericParams
-            | AstFragmentKind::Params
-            | AstFragmentKind::StructFields
-            | AstFragmentKind::Variants => {
-                if let Res::Def(..) = res {
-                    self.session.span_err(
-                        span,
-                        &format!(
-                            "expected an inert attribute, found {} {}",
-                            res.article(),
-                            res.descr()
-                        ),
-                    );
-                    return Ok(InvocationRes::Single(self.dummy_ext(kind)));
-                }
-            }
-            _ => {}
-        }
-
         Ok(InvocationRes::Single(ext))
     }
 
@@ -360,10 +351,6 @@ impl<'a> ResolverExpand for Resolver<'a> {
         self.containers_deriving_copy.contains(&expn_id)
     }
 
-    fn add_derive_copy(&mut self, expn_id: ExpnId) {
-        self.containers_deriving_copy.insert(expn_id);
-    }
-
     // The function that implements the resolution logic of `#[cfg_accessible(path)]`.
     // Returns true if the path can certainly be resolved in one of three namespaces,
     // returns false if the path certainly cannot be resolved in any of the three namespaces.
@@ -403,10 +390,14 @@ impl<'a> ResolverExpand for Resolver<'a> {
 
 impl<'a> Resolver<'a> {
     /// Resolve macro path with error reporting and recovery.
+    /// Uses dummy syntax extensions for unresolved macros or macros with unexpected resolutions
+    /// for better error recovery.
     fn smart_resolve_macro_path(
         &mut self,
         path: &ast::Path,
         kind: MacroKind,
+        require_inert: bool,
+        inner_attr: bool,
         parent_scope: &ParentScope<'a>,
         node_id: NodeId,
         force: bool,
@@ -414,7 +405,6 @@ impl<'a> Resolver<'a> {
         let (ext, res) = match self.resolve_macro_path(path, Some(kind), parent_scope, true, force)
         {
             Ok((Some(ext), res)) => (ext, res),
-            // Use dummy syntax extensions for unresolved macros for better recovery.
             Ok((None, res)) => (self.dummy_ext(kind), res),
             Err(Determinacy::Determined) => (self.dummy_ext(kind), Res::Err),
             Err(Determinacy::Undetermined) => return Err(Indeterminate),
@@ -451,19 +441,42 @@ impl<'a> Resolver<'a> {
 
         self.check_stability_and_deprecation(&ext, path, node_id);
 
-        Ok(if ext.macro_kind() != kind {
-            let expected = kind.descr_expected();
+        let unexpected_res = if ext.macro_kind() != kind {
+            Some((kind.article(), kind.descr_expected()))
+        } else if require_inert && matches!(res, Res::Def(..)) {
+            Some(("a", "non-macro attribute"))
+        } else {
+            None
+        };
+        if let Some((article, expected)) = unexpected_res {
             let path_str = pprust::path_to_string(path);
             let msg = format!("expected {}, found {} `{}`", expected, res.descr(), path_str);
             self.session
                 .struct_span_err(path.span, &msg)
-                .span_label(path.span, format!("not {} {}", kind.article(), expected))
+                .span_label(path.span, format!("not {} {}", article, expected))
                 .emit();
-            // Use dummy syntax extensions for unexpected macro kinds for better recovery.
-            (self.dummy_ext(kind), Res::Err)
-        } else {
-            (ext, res)
-        })
+            return Ok((self.dummy_ext(kind), Res::Err));
+        }
+
+        // We are trying to avoid reporting this error if other related errors were reported.
+        if res != Res::Err
+            && inner_attr
+            && !self.session.features_untracked().custom_inner_attributes
+        {
+            let msg = match res {
+                Res::Def(..) => "inner macro attributes are unstable",
+                Res::NonMacroAttr(..) => "custom inner attributes are unstable",
+                _ => unreachable!(),
+            };
+            if path == &sym::test {
+                self.session.parse_sess.buffer_lint(SOFT_UNSTABLE, path.span, node_id, msg);
+            } else {
+                feature_err(&self.session.parse_sess, sym::custom_inner_attributes, path.span, msg)
+                    .emit();
+            }
+        }
+
+        Ok((ext, res))
     }
 
     pub fn resolve_macro_path(
@@ -568,10 +581,9 @@ impl<'a> Resolver<'a> {
             struct Flags: u8 {
                 const MACRO_RULES          = 1 << 0;
                 const MODULE               = 1 << 1;
-                const DERIVE_HELPER_COMPAT = 1 << 2;
-                const MISC_SUGGEST_CRATE   = 1 << 3;
-                const MISC_SUGGEST_SELF    = 1 << 4;
-                const MISC_FROM_PRELUDE    = 1 << 5;
+                const MISC_SUGGEST_CRATE   = 1 << 2;
+                const MISC_SUGGEST_SELF    = 1 << 3;
+                const MISC_FROM_PRELUDE    = 1 << 4;
             }
         }
 
@@ -646,14 +658,11 @@ impl<'a> Resolver<'a> {
                             ) {
                                 Ok((Some(ext), _)) => {
                                     if ext.helper_attrs.contains(&ident.name) {
-                                        let binding = (
-                                            Res::NonMacroAttr(NonMacroAttrKind::DeriveHelper),
-                                            ty::Visibility::Public,
+                                        result = ok(
+                                            Res::NonMacroAttr(NonMacroAttrKind::DeriveHelperCompat),
                                             derive.span,
-                                            ExpnId::root(),
-                                        )
-                                            .to_name_binding(this.arenas);
-                                        result = Ok((binding, Flags::DERIVE_HELPER_COMPAT));
+                                            this.arenas,
+                                        );
                                         break;
                                     }
                                 }
@@ -799,17 +808,15 @@ impl<'a> Resolver<'a> {
                             let (res, innermost_res) = (binding.res(), innermost_binding.res());
                             if res != innermost_res {
                                 let builtin = Res::NonMacroAttr(NonMacroAttrKind::Builtin);
-                                let is_derive_helper_compat = |res, flags: Flags| {
-                                    res == Res::NonMacroAttr(NonMacroAttrKind::DeriveHelper)
-                                        && flags.contains(Flags::DERIVE_HELPER_COMPAT)
-                                };
+                                let derive_helper_compat =
+                                    Res::NonMacroAttr(NonMacroAttrKind::DeriveHelperCompat);
 
                                 let ambiguity_error_kind = if is_import {
                                     Some(AmbiguityKind::Import)
                                 } else if innermost_res == builtin || res == builtin {
                                     Some(AmbiguityKind::BuiltinAttr)
-                                } else if is_derive_helper_compat(innermost_res, innermost_flags)
-                                    || is_derive_helper_compat(res, flags)
+                                } else if innermost_res == derive_helper_compat
+                                    || res == derive_helper_compat
                                 {
                                     Some(AmbiguityKind::DeriveHelper)
                                 } else if innermost_flags.contains(Flags::MACRO_RULES)
@@ -1034,6 +1041,7 @@ impl<'a> Resolver<'a> {
                 depr.suggestion,
                 lint,
                 span,
+                node_id,
             );
         }
     }