]> git.lizzy.rs Git - rust.git/commitdiff
resolve: Make proc macro stubs less stubby
authorVadim Petrochenkov <vadim.petrochenkov@gmail.com>
Tue, 2 Jul 2019 22:44:04 +0000 (01:44 +0300)
committerVadim Petrochenkov <vadim.petrochenkov@gmail.com>
Wed, 10 Jul 2019 21:12:08 +0000 (00:12 +0300)
Create real working and registered (even if dummy) `SyntaxExtension`s for them.
This improves error recovery and allows to avoid all special cases for proc macro stubs (except for the error on use, of course).

The introduced dummy `SyntaxExtension`s can be used for any other inappropriately resolved macros as well.

src/librustc_resolve/build_reduced_graph.rs
src/librustc_resolve/lib.rs
src/librustc_resolve/macros.rs
src/libsyntax/ext/base.rs
src/test/ui/proc-macro/macro-namespace-reserved-2.rs
src/test/ui/proc-macro/macro-namespace-reserved-2.stderr

index 8515029193e9b60e34674b15ad627cca0dc25ab3..6fdd0c3ff3e4de1d5d1e9bb4d0ce3b83f6e32553 100644 (file)
 
 type Res = def::Res<NodeId>;
 
-fn proc_macro_stub(item: &Item) -> Option<(Ident, Span)> {
-    if attr::contains_name(&item.attrs, sym::proc_macro) ||
-       attr::contains_name(&item.attrs, sym::proc_macro_attribute) {
-        return Some((item.ident, item.span));
-    } else if let Some(attr) = attr::find_by_name(&item.attrs, sym::proc_macro_derive) {
-        if let Some(nested_meta) = attr.meta_item_list().and_then(|list| list.get(0).cloned()) {
-            if let Some(ident) = nested_meta.ident() {
-                return Some((ident, ident.span));
-            }
-        }
-    }
-    None
-}
-
 impl<'a> ToNameBinding<'a> for (Module<'a>, ty::Visibility, Span, Mark) {
     fn to_name_binding(self, arenas: &'a ResolverArenas<'a>) -> &'a NameBinding<'a> {
         arenas.alloc_name_binding(NameBinding {
@@ -470,9 +456,7 @@ fn build_reduced_graph_for_item(&mut self, item: &Item, parent_scope: ParentScop
 
                 // Functions introducing procedural macros reserve a slot
                 // in the macro namespace as well (see #52225).
-                if let Some((ident, span)) = proc_macro_stub(item) {
-                    self.define(parent, ident, MacroNS, (res, vis, span, expansion));
-                }
+                self.define_macro(item, expansion, &mut LegacyScope::Empty);
             }
 
             // These items live in the type namespace.
index 09d7d8ace6bc02cdf1d8b633d83dbca60af2fa02..b6c26b1a721e1e5b5d845ac1ea25a55371cb98d6 100644 (file)
@@ -40,7 +40,7 @@
 use syntax::source_map::SourceMap;
 use syntax::ext::hygiene::{Mark, Transparency, SyntaxContext};
 use syntax::ast::{self, Name, NodeId, Ident, FloatTy, IntTy, UintTy};
-use syntax::ext::base::{SyntaxExtension, SyntaxExtensionKind};
+use syntax::ext::base::SyntaxExtension;
 use syntax::ext::base::Determinacy::{self, Determined, Undetermined};
 use syntax::ext::base::MacroKind;
 use syntax::symbol::{Symbol, kw, sym};
@@ -1663,10 +1663,13 @@ pub struct Resolver<'a> {
     macro_use_prelude: FxHashMap<Name, &'a NameBinding<'a>>,
     pub all_macros: FxHashMap<Name, Res>,
     macro_map: FxHashMap<DefId, Lrc<SyntaxExtension>>,
+    dummy_ext_bang: Lrc<SyntaxExtension>,
+    dummy_ext_derive: Lrc<SyntaxExtension>,
     non_macro_attrs: [Lrc<SyntaxExtension>; 2],
     macro_defs: FxHashMap<Mark, DefId>,
     local_macro_def_scopes: FxHashMap<NodeId, Module<'a>>,
     unused_macros: NodeMap<Span>,
+    proc_macro_stubs: NodeSet,
 
     /// Maps the `Mark` of an expansion to its containing module or block.
     invocations: FxHashMap<Mark, &'a InvocationData<'a>>,
@@ -1925,9 +1928,8 @@ pub fn new(session: &'a Session,
         macro_defs.insert(Mark::root(), root_def_id);
 
         let features = session.features_untracked();
-        let non_macro_attr = |mark_used| Lrc::new(SyntaxExtension::default(
-            SyntaxExtensionKind::NonMacroAttr { mark_used }, session.edition()
-        ));
+        let non_macro_attr =
+            |mark_used| Lrc::new(SyntaxExtension::non_macro_attr(mark_used, session.edition()));
 
         Resolver {
             session,
@@ -2002,6 +2004,8 @@ pub fn new(session: &'a Session,
             macro_use_prelude: FxHashMap::default(),
             all_macros: FxHashMap::default(),
             macro_map: FxHashMap::default(),
+            dummy_ext_bang: Lrc::new(SyntaxExtension::dummy_bang(session.edition())),
+            dummy_ext_derive: Lrc::new(SyntaxExtension::dummy_derive(session.edition())),
             non_macro_attrs: [non_macro_attr(false), non_macro_attr(true)],
             invocations,
             macro_defs,
@@ -2010,6 +2014,7 @@ pub fn new(session: &'a Session,
             potentially_unused_imports: Vec::new(),
             struct_constructors: Default::default(),
             unused_macros: Default::default(),
+            proc_macro_stubs: Default::default(),
             current_type_ascription: Vec::new(),
             injected_crate: None,
             active_features:
@@ -2027,6 +2032,14 @@ fn non_macro_attr(&self, mark_used: bool) -> Lrc<SyntaxExtension> {
         self.non_macro_attrs[mark_used as usize].clone()
     }
 
+    fn dummy_ext(&self, macro_kind: MacroKind) -> Lrc<SyntaxExtension> {
+        match macro_kind {
+            MacroKind::Bang => self.dummy_ext_bang.clone(),
+            MacroKind::Derive => self.dummy_ext_derive.clone(),
+            MacroKind::Attr => self.non_macro_attr(true),
+        }
+    }
+
     /// Runs the function on each namespace.
     fn per_ns<F: FnMut(&mut Self, Namespace)>(&mut self, mut f: F) {
         f(self, TypeNS);
index 8361bbe45c48361bec6f3eb6b8a1171db75cc5b7..20eb97c15ba736961fe46d20075fd64e240da360 100644 (file)
@@ -11,7 +11,7 @@
 use rustc::hir::map::DefCollector;
 use rustc::middle::stability;
 use rustc::{ty, lint, span_bug};
-use syntax::ast::{self, Ident};
+use syntax::ast::{self, Ident, ItemKind};
 use syntax::attr::{self, StabilityLevel};
 use syntax::errors::DiagnosticBuilder;
 use syntax::ext::base::{self, Determinacy};
@@ -127,6 +127,21 @@ fn fast_print_path(path: &ast::Path) -> Symbol {
     }
 }
 
+fn proc_macro_stub(item: &ast::Item) -> Option<(MacroKind, Ident, Span)> {
+    if attr::contains_name(&item.attrs, sym::proc_macro) {
+        return Some((MacroKind::Bang, item.ident, item.span));
+    } else if attr::contains_name(&item.attrs, sym::proc_macro_attribute) {
+        return Some((MacroKind::Attr, item.ident, item.span));
+    } else if let Some(attr) = attr::find_by_name(&item.attrs, sym::proc_macro_derive) {
+        if let Some(nested_meta) = attr.meta_item_list().and_then(|list| list.get(0).cloned()) {
+            if let Some(ident) = nested_meta.ident() {
+                return Some((MacroKind::Derive, ident, ident.span));
+            }
+        }
+    }
+    None
+}
+
 impl<'a> base::Resolver for Resolver<'a> {
     fn next_node_id(&mut self) -> ast::NodeId {
         self.session.next_node_id()
@@ -216,10 +231,9 @@ fn resolve_macro_invocation(&mut self, invoc: &Invocation, invoc_id: Mark, force
         let parent_scope = self.invoc_parent_scope(invoc_id, derives_in_scope);
         let (res, ext) = match self.resolve_macro_to_res(path, kind, &parent_scope, true, force) {
             Ok((res, ext)) => (res, ext),
-            // Replace unresolved attributes with used inert attributes for better recovery.
-            Err(Determinacy::Determined) if kind == MacroKind::Attr =>
-                (Res::Err, self.non_macro_attr(true)),
-            Err(determinacy) => return Err(determinacy),
+            // Return dummy syntax extensions for unresolved macros for better recovery.
+            Err(Determinacy::Determined) => (Res::Err, self.dummy_ext(kind)),
+            Err(Determinacy::Undetermined) => return Err(Determinacy::Undetermined),
         };
 
         let span = invoc.span();
@@ -305,13 +319,14 @@ fn resolve_macro_to_res(
             Res::Def(DefKind::Macro(_), def_id) => {
                 if let Some(node_id) = self.definitions.as_local_node_id(def_id) {
                     self.unused_macros.remove(&node_id);
+                    if self.proc_macro_stubs.contains(&node_id) {
+                        self.session.span_err(
+                            path.span,
+                            "can't use a procedural macro from the same crate that defines it",
+                        );
+                    }
                 }
             }
-            Res::Def(DefKind::Fn, _) => {
-                let msg = "can't use a procedural macro from the same crate that defines it";
-                self.session.span_err(path.span, msg);
-                return Err(Determinacy::Determined);
-            }
             Res::NonMacroAttr(attr_kind) => {
                 if kind == MacroKind::Attr {
                     if attr_kind == NonMacroAttrKind::Custom {
@@ -1100,19 +1115,32 @@ pub fn define_macro(&mut self,
                         item: &ast::Item,
                         expansion: Mark,
                         current_legacy_scope: &mut LegacyScope<'a>) {
-        self.local_macro_def_scopes.insert(item.id, self.current_module);
-        let ident = item.ident;
+        let (ext, ident, span, is_legacy) = match &item.node {
+            ItemKind::MacroDef(def) => {
+                let ext = Lrc::new(macro_rules::compile(
+                    &self.session.parse_sess,
+                    &self.session.features_untracked(),
+                    item,
+                    self.session.edition(),
+                ));
+                (ext, item.ident, item.span, def.legacy)
+            }
+            ItemKind::Fn(..) => match proc_macro_stub(item) {
+                Some((macro_kind, ident, span)) => {
+                    self.proc_macro_stubs.insert(item.id);
+                    (self.dummy_ext(macro_kind), ident, span, false)
+                }
+                None => return,
+            }
+            _ => unreachable!(),
+        };
 
         let def_id = self.definitions.local_def_id(item.id);
-        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);
+        let res = Res::Def(DefKind::Macro(ext.macro_kind()), def_id);
         self.macro_map.insert(def_id, ext);
+        self.local_macro_def_scopes.insert(item.id, self.current_module);
 
-        let def = match item.node { ast::ItemKind::MacroDef(ref def) => def, _ => unreachable!() };
-        if def.legacy {
+        if is_legacy {
             let ident = ident.modern();
             self.macro_names.insert(ident);
             let is_macro_export = attr::contains_name(&item.attrs, sym::macro_export);
@@ -1121,7 +1149,7 @@ pub fn define_macro(&mut self,
             } else {
                 ty::Visibility::Restricted(DefId::local(CRATE_DEF_INDEX))
             };
-            let binding = (res, vis, item.span, expansion).to_name_binding(self.arenas);
+            let binding = (res, vis, span, expansion).to_name_binding(self.arenas);
             self.set_binding_parent_module(binding, self.current_module);
             let legacy_binding = self.arenas.alloc_legacy_binding(LegacyBinding {
                 parent_legacy_scope: *current_legacy_scope, binding, ident
@@ -1131,18 +1159,18 @@ pub fn define_macro(&mut self,
             if is_macro_export {
                 let module = self.graph_root;
                 self.define(module, ident, MacroNS,
-                            (res, vis, item.span, expansion, IsMacroExport));
+                            (res, vis, span, expansion, IsMacroExport));
             } else {
                 self.check_reserved_macro_name(ident, res);
-                self.unused_macros.insert(item.id, item.span);
+                self.unused_macros.insert(item.id, span);
             }
         } else {
             let module = self.current_module;
             let vis = self.resolve_visibility(&item.vis);
             if vis != ty::Visibility::Public {
-                self.unused_macros.insert(item.id, item.span);
+                self.unused_macros.insert(item.id, span);
             }
-            self.define(module, ident, MacroNS, (res, vis, item.span, expansion));
+            self.define(module, ident, MacroNS, (res, vis, span, expansion));
         }
     }
 }
index 04f124685cbb5f9091af1628358aa62920ec6984..82386b78f1dc2a5a62d3240cbcea53e178048b8f 100644 (file)
@@ -10,7 +10,7 @@
 use crate::ptr::P;
 use crate::symbol::{kw, sym, Ident, Symbol};
 use crate::{ThinVec, MACRO_ARGUMENTS};
-use crate::tokenstream::{self, TokenStream};
+use crate::tokenstream::{self, TokenStream, TokenTree};
 
 use errors::{DiagnosticBuilder, DiagnosticId};
 use smallvec::{smallvec, SmallVec};
@@ -640,6 +640,26 @@ pub fn default(kind: SyntaxExtensionKind, edition: Edition) -> SyntaxExtension {
         }
     }
 
+    pub fn dummy_bang(edition: Edition) -> SyntaxExtension {
+        fn expander<'cx>(_: &'cx mut ExtCtxt<'_>, span: Span, _: &[TokenTree])
+                         -> Box<dyn MacResult + 'cx> {
+            DummyResult::any(span)
+        }
+        SyntaxExtension::default(SyntaxExtensionKind::LegacyBang(Box::new(expander)), edition)
+    }
+
+    pub fn dummy_derive(edition: Edition) -> SyntaxExtension {
+        fn expander(_: &mut ExtCtxt<'_>, _: Span, _: &ast::MetaItem, _: Annotatable)
+                    -> Vec<Annotatable> {
+            Vec::new()
+        }
+        SyntaxExtension::default(SyntaxExtensionKind::Derive(Box::new(expander)), edition)
+    }
+
+    pub fn non_macro_attr(mark_used: bool, edition: Edition) -> SyntaxExtension {
+        SyntaxExtension::default(SyntaxExtensionKind::NonMacroAttr { mark_used }, edition)
+    }
+
     pub fn expn_info(&self, call_site: Span, descr: Symbol) -> ExpnInfo {
         ExpnInfo {
             call_site,
index 583640aa8171c309f273d454d7eea16259ed156b..c7b092830a243d15f0ecf76742276bdc62e47f62 100644 (file)
@@ -25,22 +25,24 @@ fn check_bang1() {
     my_macro!(); //~ ERROR can't use a procedural macro from the same crate that defines it
 }
 fn check_bang2() {
-    my_macro_attr!(); //~ ERROR can't use a procedural macro from the same crate that defines it
+    my_macro_attr!(); //~ ERROR cannot find macro `my_macro_attr!` in this scope
 }
 fn check_bang3() {
-    MyTrait!(); //~ ERROR can't use a procedural macro from the same crate that defines it
+    MyTrait!(); //~ ERROR cannot find macro `MyTrait!` in this scope
 }
 
-#[my_macro] //~ ERROR can't use a procedural macro from the same crate that defines it
+#[my_macro] //~ ERROR attribute `my_macro` is currently unknown
 fn check_attr1() {}
 #[my_macro_attr] //~ ERROR can't use a procedural macro from the same crate that defines it
 fn check_attr2() {}
 #[MyTrait] //~ ERROR can't use a procedural macro from the same crate that defines it
+           //~| ERROR `MyTrait` is a derive macro
 fn check_attr3() {}
 
-#[derive(my_macro)] //~ ERROR can't use a procedural macro from the same crate that defines it
+#[derive(my_macro)] //~ ERROR cannot find derive macro `my_macro` in this scope
 struct CheckDerive1;
 #[derive(my_macro_attr)] //~ ERROR can't use a procedural macro from the same crate that defines it
+                         //~| ERROR macro `my_macro_attr` may not be used for derive attributes
 struct CheckDerive2;
 #[derive(MyTrait)] //~ ERROR can't use a procedural macro from the same crate that defines it
 struct CheckDerive3;
index 548f9e3051dd3846e1d27320e3ceb45c6dc0d46c..83c77513ec3bfa20208e47c9ba6c0ff6f3a55e27 100644 (file)
@@ -4,24 +4,6 @@ error: can't use a procedural macro from the same crate that defines it
 LL |     my_macro!();
    |     ^^^^^^^^
 
-error: can't use a procedural macro from the same crate that defines it
-  --> $DIR/macro-namespace-reserved-2.rs:28:5
-   |
-LL |     my_macro_attr!();
-   |     ^^^^^^^^^^^^^
-
-error: can't use a procedural macro from the same crate that defines it
-  --> $DIR/macro-namespace-reserved-2.rs:31:5
-   |
-LL |     MyTrait!();
-   |     ^^^^^^^
-
-error: can't use a procedural macro from the same crate that defines it
-  --> $DIR/macro-namespace-reserved-2.rs:34:3
-   |
-LL | #[my_macro]
-   |   ^^^^^^^^
-
 error: can't use a procedural macro from the same crate that defines it
   --> $DIR/macro-namespace-reserved-2.rs:36:3
    |
@@ -34,23 +16,57 @@ error: can't use a procedural macro from the same crate that defines it
 LL | #[MyTrait]
    |   ^^^^^^^
 
-error: can't use a procedural macro from the same crate that defines it
-  --> $DIR/macro-namespace-reserved-2.rs:41:10
+error: `MyTrait` is a derive macro
+  --> $DIR/macro-namespace-reserved-2.rs:38:1
    |
-LL | #[derive(my_macro)]
-   |          ^^^^^^^^
+LL | #[MyTrait]
+   | ^^^^^^^^^^
 
 error: can't use a procedural macro from the same crate that defines it
-  --> $DIR/macro-namespace-reserved-2.rs:43:10
+  --> $DIR/macro-namespace-reserved-2.rs:44:10
+   |
+LL | #[derive(my_macro_attr)]
+   |          ^^^^^^^^^^^^^
+
+error: macro `my_macro_attr` may not be used for derive attributes
+  --> $DIR/macro-namespace-reserved-2.rs:44:10
    |
 LL | #[derive(my_macro_attr)]
    |          ^^^^^^^^^^^^^
 
 error: can't use a procedural macro from the same crate that defines it
-  --> $DIR/macro-namespace-reserved-2.rs:45:10
+  --> $DIR/macro-namespace-reserved-2.rs:47:10
    |
 LL | #[derive(MyTrait)]
    |          ^^^^^^^
 
-error: aborting due to 9 previous errors
+error[E0658]: The attribute `my_macro` is currently unknown to the compiler and may have meaning added to it in the future
+  --> $DIR/macro-namespace-reserved-2.rs:34:3
+   |
+LL | #[my_macro]
+   |   ^^^^^^^^
+   |
+   = note: for more information, see https://github.com/rust-lang/rust/issues/29642
+   = help: add #![feature(custom_attribute)] to the crate attributes to enable
+
+error: cannot find derive macro `my_macro` in this scope
+  --> $DIR/macro-namespace-reserved-2.rs:42:10
+   |
+LL | #[derive(my_macro)]
+   |          ^^^^^^^^
+
+error: cannot find macro `my_macro_attr!` in this scope
+  --> $DIR/macro-namespace-reserved-2.rs:28:5
+   |
+LL |     my_macro_attr!();
+   |     ^^^^^^^^^^^^^
+
+error: cannot find macro `MyTrait!` in this scope
+  --> $DIR/macro-namespace-reserved-2.rs:31:5
+   |
+LL |     MyTrait!();
+   |     ^^^^^^^
+
+error: aborting due to 11 previous errors
 
+For more information about this error, try `rustc --explain E0658`.