diff options
| author | Vadim Petrochenkov <vadim.petrochenkov@gmail.com> | 2019-07-03 01:44:04 +0300 |
|---|---|---|
| committer | Vadim Petrochenkov <vadim.petrochenkov@gmail.com> | 2019-07-11 00:12:08 +0300 |
| commit | cd0fd630e8170f8770485cb8248ff3d823521523 (patch) | |
| tree | 7a8996509f28dada6dbe1b06c328b9aa87903294 | |
| parent | b392781edc145d1d1592c6d1bba4c33fbc1f51d5 (diff) | |
resolve: Make proc macro stubs less stubby
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.
| -rw-r--r-- | src/librustc_resolve/build_reduced_graph.rs | 18 | ||||
| -rw-r--r-- | src/librustc_resolve/lib.rs | 21 | ||||
| -rw-r--r-- | src/librustc_resolve/macros.rs | 76 | ||||
| -rw-r--r-- | src/libsyntax/ext/base.rs | 22 | ||||
| -rw-r--r-- | src/test/ui/proc-macro/macro-namespace-reserved-2.rs | 10 | ||||
| -rw-r--r-- | src/test/ui/proc-macro/macro-namespace-reserved-2.stderr | 66 |
6 files changed, 138 insertions, 75 deletions
diff --git a/src/librustc_resolve/build_reduced_graph.rs b/src/librustc_resolve/build_reduced_graph.rs index 8515029193e..6fdd0c3ff3e 100644 --- a/src/librustc_resolve/build_reduced_graph.rs +++ b/src/librustc_resolve/build_reduced_graph.rs @@ -46,20 +46,6 @@ use log::debug; 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 @@ impl<'a> Resolver<'a> { // 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. diff --git a/src/librustc_resolve/lib.rs b/src/librustc_resolve/lib.rs index 09d7d8ace6b..b6c26b1a721 100644 --- a/src/librustc_resolve/lib.rs +++ b/src/librustc_resolve/lib.rs @@ -40,7 +40,7 @@ use rustc_metadata::cstore::CStore; 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 @@ impl<'a> Resolver<'a> { 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 @@ impl<'a> Resolver<'a> { 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 @@ impl<'a> Resolver<'a> { 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 @@ impl<'a> Resolver<'a> { 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); diff --git a/src/librustc_resolve/macros.rs b/src/librustc_resolve/macros.rs index 8361bbe45c4..20eb97c15ba 100644 --- a/src/librustc_resolve/macros.rs +++ b/src/librustc_resolve/macros.rs @@ -11,7 +11,7 @@ use rustc::hir::def::{self, DefKind, NonMacroAttrKind}; 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 @@ impl<'a> base::Resolver for Resolver<'a> { 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 @@ impl<'a> Resolver<'a> { 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 @@ impl<'a> Resolver<'a> { 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 @@ impl<'a> Resolver<'a> { } 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 @@ impl<'a> Resolver<'a> { 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)); } } } diff --git a/src/libsyntax/ext/base.rs b/src/libsyntax/ext/base.rs index 04f124685cb..82386b78f1d 100644 --- a/src/libsyntax/ext/base.rs +++ b/src/libsyntax/ext/base.rs @@ -10,7 +10,7 @@ use crate::parse::token; 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 @@ impl 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, diff --git a/src/test/ui/proc-macro/macro-namespace-reserved-2.rs b/src/test/ui/proc-macro/macro-namespace-reserved-2.rs index 583640aa817..c7b092830a2 100644 --- a/src/test/ui/proc-macro/macro-namespace-reserved-2.rs +++ b/src/test/ui/proc-macro/macro-namespace-reserved-2.rs @@ -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; diff --git a/src/test/ui/proc-macro/macro-namespace-reserved-2.stderr b/src/test/ui/proc-macro/macro-namespace-reserved-2.stderr index 548f9e3051d..83c77513ec3 100644 --- a/src/test/ui/proc-macro/macro-namespace-reserved-2.stderr +++ b/src/test/ui/proc-macro/macro-namespace-reserved-2.stderr @@ -5,24 +5,6 @@ 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 | LL | #[my_macro_attr] @@ -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`. |
