From 848b2d24096d646e475b2dae5fe8322af904e951 Mon Sep 17 00:00:00 2001
From: Vadim Petrochenkov <vadim.petrochenkov@gmail.com>
Date: Sun, 30 Jun 2019 01:24:34 +0300
Subject: [PATCH] resolve: Reserve cfg/cfg_attr/derive only in attribute
 sub-namespace

---
 src/librustc_resolve/build_reduced_graph.rs   | 16 +++++++++-----
 src/librustc_resolve/macros.rs                | 19 ++++++++++++-----
 src/librustc_resolve/resolve_imports.rs       | 21 ++++++-------------
 .../feature-gate-const_panic.stderr           | 16 +++++++-------
 .../ui/proc-macro/reserved-macro-names.rs     |  6 +++---
 .../ui/proc-macro/reserved-macro-names.stderr |  6 +++---
 6 files changed, 45 insertions(+), 39 deletions(-)

diff --git a/src/librustc_resolve/build_reduced_graph.rs b/src/librustc_resolve/build_reduced_graph.rs
index 616728d541848..3921bd30df25c 100644
--- a/src/librustc_resolve/build_reduced_graph.rs
+++ b/src/librustc_resolve/build_reduced_graph.rs
@@ -770,19 +770,25 @@ impl<'a> Resolver<'a> {
     }
 
     pub fn get_macro(&mut self, res: Res) -> Lrc<SyntaxExtension> {
+        self.opt_get_macro(res).expect("expected `DefKind::Macro` or `Res::NonMacroAttr`")
+    }
+
+    crate fn opt_get_macro(&mut self, res: Res) -> Option<Lrc<SyntaxExtension>> {
         let def_id = match res {
+            Res::Def(DefKind::Macro(MacroKind::ProcMacroStub), _) =>
+                return Some(self.non_macro_attr(true)), // some dummy extension
             Res::Def(DefKind::Macro(..), def_id) => def_id,
             Res::NonMacroAttr(attr_kind) =>
-                return self.non_macro_attr(attr_kind == NonMacroAttrKind::Tool),
-            _ => panic!("expected `DefKind::Macro` or `Res::NonMacroAttr`"),
+                return Some(self.non_macro_attr(attr_kind == NonMacroAttrKind::Tool)),
+            _ => return None,
         };
         if let Some(ext) = self.macro_map.get(&def_id) {
-            return ext.clone();
+            return Some(ext.clone());
         }
 
         let macro_def = match self.cstore.load_macro_untracked(def_id, &self.session) {
             LoadedMacro::MacroDef(macro_def) => macro_def,
-            LoadedMacro::ProcMacro(ext) => return ext,
+            LoadedMacro::ProcMacro(ext) => return Some(ext),
         };
 
         let ext = Lrc::new(macro_rules::compile(&self.session.parse_sess,
@@ -790,7 +796,7 @@ impl<'a> Resolver<'a> {
                                                &macro_def,
                                                self.cstore.crate_edition_untracked(def_id.krate)));
         self.macro_map.insert(def_id, ext.clone());
-        ext
+        Some(ext)
     }
 
     /// Ensures that the reduced graph rooted at the given external module
diff --git a/src/librustc_resolve/macros.rs b/src/librustc_resolve/macros.rs
index 6a8c46eaa40fb..7b509191d589f 100644
--- a/src/librustc_resolve/macros.rs
+++ b/src/librustc_resolve/macros.rs
@@ -1106,6 +1106,17 @@ impl<'a> Resolver<'a> {
         });
     }
 
+    crate fn check_reserved_macro_name(&self, ident: Ident, macro_kind: Option<MacroKind>) {
+        // Reserve some names that are not quite covered by the general check
+        // performed on `Resolver::builtin_attrs`.
+        if (macro_kind.is_some() && sub_namespace_match(macro_kind, Some(MacroKind::Attr))) &&
+           (ident.name == sym::cfg || ident.name == sym::cfg_attr || ident.name == sym::derive) {
+            self.session.span_err(
+                ident.span, &format!("name `{}` is reserved in attribute namespace", ident)
+            );
+        }
+    }
+
     pub fn define_macro(&mut self,
                         item: &ast::Item,
                         expansion: Mark,
@@ -1117,13 +1128,14 @@ impl<'a> Resolver<'a> {
         let ext = Lrc::new(macro_rules::compile(&self.session.parse_sess,
                                                &self.session.features_untracked(),
                                                item, self.session.edition()));
+        let macro_kind = ext.macro_kind();
+        let res = Res::Def(DefKind::Macro(macro_kind), def_id);
         self.macro_map.insert(def_id, ext);
 
         let def = match item.node { ast::ItemKind::MacroDef(ref def) => def, _ => unreachable!() };
         if def.legacy {
             let ident = ident.modern();
             self.macro_names.insert(ident);
-            let res = Res::Def(DefKind::Macro(MacroKind::Bang), def_id);
             let is_macro_export = attr::contains_name(&item.attrs, sym::macro_export);
             let vis = if is_macro_export {
                 ty::Visibility::Public
@@ -1142,14 +1154,11 @@ impl<'a> Resolver<'a> {
                 self.define(module, ident, MacroNS,
                             (res, vis, item.span, expansion, IsMacroExport));
             } else {
-                if !attr::contains_name(&item.attrs, sym::rustc_builtin_macro) {
-                    self.check_reserved_macro_name(ident, MacroNS);
-                }
+                self.check_reserved_macro_name(ident, Some(macro_kind));
                 self.unused_macros.insert(def_id);
             }
         } else {
             let module = self.current_module;
-            let res = Res::Def(DefKind::Macro(MacroKind::Bang), def_id);
             let vis = self.resolve_visibility(&item.vis);
             if vis != ty::Visibility::Public {
                 self.unused_macros.insert(def_id);
diff --git a/src/librustc_resolve/resolve_imports.rs b/src/librustc_resolve/resolve_imports.rs
index 404d728d8808c..3b20647d0bf9c 100644
--- a/src/librustc_resolve/resolve_imports.rs
+++ b/src/librustc_resolve/resolve_imports.rs
@@ -29,7 +29,7 @@ use rustc::{bug, span_bug};
 use syntax::ast::{self, Ident, Name, NodeId, CRATE_NODE_ID};
 use syntax::ext::base::Determinacy::{self, Determined, Undetermined};
 use syntax::ext::hygiene::Mark;
-use syntax::symbol::{kw, sym};
+use syntax::symbol::kw;
 use syntax::util::lev_distance::find_best_match_for_name;
 use syntax::{struct_span_err, unwrap_or};
 use syntax_pos::{MultiSpan, Span};
@@ -492,17 +492,6 @@ impl<'a> Resolver<'a> {
         })
     }
 
-    crate fn check_reserved_macro_name(&self, ident: Ident, ns: Namespace) {
-        // Reserve some names that are not quite covered by the general check
-        // performed on `Resolver::builtin_attrs`.
-        if ns == MacroNS &&
-           (ident.name == sym::cfg || ident.name == sym::cfg_attr ||
-            ident.name == sym::derive) {
-            self.session.span_err(ident.span,
-                                  &format!("name `{}` is reserved in macro namespace", ident));
-        }
-    }
-
     // Define the name or return the existing binding if there is a collision.
     pub fn try_define(&mut self,
                       module: Module<'a>,
@@ -510,17 +499,19 @@ impl<'a> Resolver<'a> {
                       ns: Namespace,
                       binding: &'a NameBinding<'a>)
                       -> Result<(), &'a NameBinding<'a>> {
-        self.check_reserved_macro_name(ident, ns);
+        let res = binding.res();
+        let macro_kind = self.opt_get_macro(res).map(|ext| ext.macro_kind());
+        self.check_reserved_macro_name(ident, macro_kind);
         self.set_binding_parent_module(binding, module);
         self.update_resolution(module, ident, ns, |this, resolution| {
             if let Some(old_binding) = resolution.binding {
-                if binding.res() == Res::Err {
+                if res == Res::Err {
                     // Do not override real bindings with `Res::Err`s from error recovery.
                     return Ok(());
                 }
                 match (old_binding.is_glob_import(), binding.is_glob_import()) {
                     (true, true) => {
-                        if binding.res() != old_binding.res() {
+                        if res != old_binding.res() {
                             resolution.binding = Some(this.ambiguity(AmbiguityKind::GlobVsGlob,
                                                                      old_binding, binding));
                         } else if !old_binding.vis.is_at_least(binding.vis, &*this) {
diff --git a/src/test/ui/consts/const-eval/feature-gate-const_panic.stderr b/src/test/ui/consts/const-eval/feature-gate-const_panic.stderr
index 5d3e88e4e58c2..bf45b9d9021bc 100644
--- a/src/test/ui/consts/const-eval/feature-gate-const_panic.stderr
+++ b/src/test/ui/consts/const-eval/feature-gate-const_panic.stderr
@@ -1,17 +1,17 @@
 error[E0658]: panicking in constants is unstable
-  --> $DIR/feature-gate-const_panic.rs:3:15
+  --> $DIR/feature-gate-const_panic.rs:6:15
    |
-LL | const Z: () = panic!("cheese");
-   |               ^^^^^^^^^^^^^^^^
+LL | const Y: () = unreachable!();
+   |               ^^^^^^^^^^^^^^
    |
    = note: for more information, see https://github.com/rust-lang/rust/issues/51999
    = help: add #![feature(const_panic)] to the crate attributes to enable
    = note: this error originates in a macro outside of the current crate (in Nightly builds, run with -Z external-macro-backtrace for more info)
 
 error[E0658]: panicking in constants is unstable
-  --> $DIR/feature-gate-const_panic.rs:9:15
+  --> $DIR/feature-gate-const_panic.rs:3:15
    |
-LL | const X: () = unimplemented!();
+LL | const Z: () = panic!("cheese");
    |               ^^^^^^^^^^^^^^^^
    |
    = note: for more information, see https://github.com/rust-lang/rust/issues/51999
@@ -19,10 +19,10 @@ LL | const X: () = unimplemented!();
    = note: this error originates in a macro outside of the current crate (in Nightly builds, run with -Z external-macro-backtrace for more info)
 
 error[E0658]: panicking in constants is unstable
-  --> $DIR/feature-gate-const_panic.rs:6:15
+  --> $DIR/feature-gate-const_panic.rs:9:15
    |
-LL | const Y: () = unreachable!();
-   |               ^^^^^^^^^^^^^^
+LL | const X: () = unimplemented!();
+   |               ^^^^^^^^^^^^^^^^
    |
    = note: for more information, see https://github.com/rust-lang/rust/issues/51999
    = help: add #![feature(const_panic)] to the crate attributes to enable
diff --git a/src/test/ui/proc-macro/reserved-macro-names.rs b/src/test/ui/proc-macro/reserved-macro-names.rs
index 7c66af172fd5e..9f56eccb7a61c 100644
--- a/src/test/ui/proc-macro/reserved-macro-names.rs
+++ b/src/test/ui/proc-macro/reserved-macro-names.rs
@@ -8,18 +8,18 @@ use proc_macro::*;
 
 #[proc_macro_attribute]
 pub fn cfg(_: TokenStream, input: TokenStream) -> TokenStream {
-    //~^ ERROR name `cfg` is reserved in macro namespace
+    //~^ ERROR name `cfg` is reserved in attribute namespace
     input
 }
 
 #[proc_macro_attribute]
 pub fn cfg_attr(_: TokenStream, input: TokenStream) -> TokenStream {
-    //~^ ERROR name `cfg_attr` is reserved in macro namespace
+    //~^ ERROR name `cfg_attr` is reserved in attribute namespace
     input
 }
 
 #[proc_macro_attribute]
 pub fn derive(_: TokenStream, input: TokenStream) -> TokenStream {
-    //~^ ERROR name `derive` is reserved in macro namespace
+    //~^ ERROR name `derive` is reserved in attribute namespace
     input
 }
diff --git a/src/test/ui/proc-macro/reserved-macro-names.stderr b/src/test/ui/proc-macro/reserved-macro-names.stderr
index 5ebe62a4969bb..f871e43ce51df 100644
--- a/src/test/ui/proc-macro/reserved-macro-names.stderr
+++ b/src/test/ui/proc-macro/reserved-macro-names.stderr
@@ -1,16 +1,16 @@
-error: name `cfg` is reserved in macro namespace
+error: name `cfg` is reserved in attribute namespace
   --> $DIR/reserved-macro-names.rs:10:8
    |
 LL | pub fn cfg(_: TokenStream, input: TokenStream) -> TokenStream {
    |        ^^^
 
-error: name `cfg_attr` is reserved in macro namespace
+error: name `cfg_attr` is reserved in attribute namespace
   --> $DIR/reserved-macro-names.rs:16:8
    |
 LL | pub fn cfg_attr(_: TokenStream, input: TokenStream) -> TokenStream {
    |        ^^^^^^^^
 
-error: name `derive` is reserved in macro namespace
+error: name `derive` is reserved in attribute namespace
   --> $DIR/reserved-macro-names.rs:22:8
    |
 LL | pub fn derive(_: TokenStream, input: TokenStream) -> TokenStream {