]> git.lizzy.rs Git - rust.git/blobdiff - src/librustc_resolve/macros.rs
resolve: `Scope::DeriveHelpers` -> `Scope::DeriveHelpersCompat`
[rust.git] / src / librustc_resolve / macros.rs
index cc811d3b59a41c4bec4fdd482857d4e3ef6ec169..0d6dd5a7f105c22ff9478ab94c360b3dae1b86b1 100644 (file)
@@ -3,16 +3,17 @@
 
 use crate::{AmbiguityError, AmbiguityKind, AmbiguityErrorMisc, Determinacy};
 use crate::{CrateLint, Resolver, ResolutionError, Scope, ScopeSet, ParentScope, Weak};
-use crate::{ModuleKind, NameBinding, PathResult, Segment, ToNameBinding};
-use crate::{ModuleOrUniformRoot, KNOWN_TOOLS};
+use crate::{ModuleKind, ModuleOrUniformRoot, NameBinding, PathResult, Segment, ToNameBinding};
 use crate::Namespace::*;
 use crate::resolve_imports::ImportResolver;
 use rustc::hir::def::{self, DefKind, NonMacroAttrKind};
 use rustc::hir::def_id;
 use rustc::middle::stability;
+use rustc::session::Session;
+use rustc::util::nodemap::FxHashSet;
 use rustc::{ty, lint, span_bug};
 use syntax::ast::{self, NodeId, Ident};
-use syntax::attr::StabilityLevel;
+use syntax::attr::{self, StabilityLevel};
 use syntax::edition::Edition;
 use syntax::feature_gate::{emit_feature_err, is_builtin_attr_name};
 use syntax::feature_gate::GateIssue;
@@ -93,6 +94,46 @@ fn fast_print_path(path: &ast::Path) -> Symbol {
     }
 }
 
+/// The code common between processing `#![register_tool]` and `#![register_attr]`.
+fn registered_idents(
+    sess: &Session,
+    attrs: &[ast::Attribute],
+    attr_name: Symbol,
+    descr: &str,
+) -> FxHashSet<Ident> {
+    let mut registered = FxHashSet::default();
+    for attr in attr::filter_by_name(attrs, attr_name) {
+        for nested_meta in attr.meta_item_list().unwrap_or_default() {
+            match nested_meta.ident() {
+                Some(ident) => if let Some(old_ident) = registered.replace(ident) {
+                    let msg = format!("{} `{}` was already registered", descr, ident);
+                    sess.struct_span_err(ident.span, &msg)
+                        .span_label(old_ident.span, "already registered here").emit();
+                }
+                None => {
+                    let msg = format!("`{}` only accepts identifiers", attr_name);
+                    let span = nested_meta.span();
+                    sess.struct_span_err(span, &msg).span_label(span, "not an identifier").emit();
+                }
+            }
+        }
+    }
+    registered
+}
+
+crate fn registered_attrs_and_tools(
+    sess: &Session,
+    attrs: &[ast::Attribute],
+) -> (FxHashSet<Ident>, FxHashSet<Ident>) {
+    let registered_attrs = registered_idents(sess, attrs, sym::register_attr, "attribute");
+    let mut registered_tools = registered_idents(sess, attrs, sym::register_tool, "tool");
+    // We implicitly add `rustfmt` and `clippy` to known tools,
+    // but it's not an error to register them explicitly.
+    let predefined_tools = [sym::clippy, sym::rustfmt];
+    registered_tools.extend(predefined_tools.iter().cloned().map(Ident::with_dummy_span));
+    (registered_attrs, registered_tools)
+}
+
 impl<'a> base::Resolver for Resolver<'a> {
     fn next_node_id(&mut self) -> NodeId {
         self.next_node_id()
@@ -416,10 +457,9 @@ pub fn resolve_macro_path(
             struct Flags: u8 {
                 const MACRO_RULES        = 1 << 0;
                 const MODULE             = 1 << 1;
-                const PRELUDE            = 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;
             }
         }
 
@@ -453,18 +493,20 @@ struct Flags: u8 {
         // Go through all the scopes and try to resolve the name.
         let break_result = self.visit_scopes(scope_set, parent_scope, orig_ident,
                                              |this, scope, use_prelude, ident| {
+            let ok = |res, span, arenas| Ok((
+                (res, ty::Visibility::Public, span, ExpnId::root()).to_name_binding(arenas),
+                Flags::empty(),
+            ));
             let result = match scope {
-                Scope::DeriveHelpers => {
+                Scope::DeriveHelpersCompat => {
                     let mut result = Err(Determinacy::Determined);
                     for derive in parent_scope.derives {
                         let parent_scope = &ParentScope { derives: &[], ..*parent_scope };
                         match this.resolve_macro_path(derive, Some(MacroKind::Derive),
                                                       parent_scope, true, force) {
                             Ok((Some(ext), _)) => if ext.helper_attrs.contains(&ident.name) {
-                                let binding = (Res::NonMacroAttr(NonMacroAttrKind::DeriveHelper),
-                                               ty::Visibility::Public, derive.span, ExpnId::root())
-                                               .to_name_binding(this.arenas);
-                                result = Ok((binding, Flags::empty()));
+                                let res = Res::NonMacroAttr(NonMacroAttrKind::DeriveHelper);
+                                result = ok(res, derive.span, this.arenas);
                                 break;
                             }
                             Ok(_) | Err(Determinacy::Determined) => {}
@@ -531,41 +573,39 @@ struct Flags: u8 {
                         Err((Determinacy::Determined, _)) => Err(Determinacy::Determined),
                     }
                 }
+                Scope::RegisteredAttrs => match this.registered_attrs.get(&ident).cloned() {
+                    Some(ident) => ok(
+                        Res::NonMacroAttr(NonMacroAttrKind::Registered), ident.span, this.arenas
+                    ),
+                    None => Err(Determinacy::Determined)
+                }
                 Scope::MacroUsePrelude => match this.macro_use_prelude.get(&ident.name).cloned() {
-                    Some(binding) => Ok((binding, Flags::PRELUDE | Flags::MISC_FROM_PRELUDE)),
+                    Some(binding) => Ok((binding, Flags::MISC_FROM_PRELUDE)),
                     None => Err(Determinacy::determined(
                         this.graph_root.unexpanded_invocations.borrow().is_empty()
                     ))
                 }
                 Scope::BuiltinAttrs => if is_builtin_attr_name(ident.name) {
-                    let binding = (Res::NonMacroAttr(NonMacroAttrKind::Builtin),
-                                   ty::Visibility::Public, DUMMY_SP, ExpnId::root())
-                                   .to_name_binding(this.arenas);
-                    Ok((binding, Flags::PRELUDE))
+                    ok(Res::NonMacroAttr(NonMacroAttrKind::Builtin), DUMMY_SP, this.arenas)
                 } else {
                     Err(Determinacy::Determined)
                 }
                 Scope::LegacyPluginHelpers => if this.session.plugin_attributes.borrow().iter()
                                                      .any(|(name, _)| ident.name == *name) {
-                    let binding = (Res::NonMacroAttr(NonMacroAttrKind::LegacyPluginHelper),
-                                   ty::Visibility::Public, DUMMY_SP, ExpnId::root())
-                                   .to_name_binding(this.arenas);
-                    Ok((binding, Flags::PRELUDE))
+                    let res = Res::NonMacroAttr(NonMacroAttrKind::LegacyPluginHelper);
+                    ok(res, DUMMY_SP, this.arenas)
                 } else {
                     Err(Determinacy::Determined)
                 }
                 Scope::ExternPrelude => match this.extern_prelude_get(ident, !record_used) {
-                    Some(binding) => Ok((binding, Flags::PRELUDE)),
+                    Some(binding) => Ok((binding, Flags::empty())),
                     None => Err(Determinacy::determined(
                         this.graph_root.unexpanded_invocations.borrow().is_empty()
                     )),
                 }
-                Scope::ToolPrelude => if KNOWN_TOOLS.contains(&ident.name) {
-                    let binding = (Res::ToolMod, ty::Visibility::Public, DUMMY_SP, ExpnId::root())
-                                   .to_name_binding(this.arenas);
-                    Ok((binding, Flags::PRELUDE))
-                } else {
-                    Err(Determinacy::Determined)
+                Scope::ToolPrelude => match this.registered_tools.get(&ident).cloned() {
+                    Some(ident) => ok(Res::ToolMod, ident.span, this.arenas),
+                    None => Err(Determinacy::Determined)
                 }
                 Scope::StdLibPrelude => {
                     let mut result = Err(Determinacy::Determined);
@@ -579,7 +619,7 @@ struct Flags: u8 {
                             path_span,
                         ) {
                             if use_prelude || this.is_builtin_macro(binding.res()) {
-                                result = Ok((binding, Flags::PRELUDE | Flags::MISC_FROM_PRELUDE));
+                                result = Ok((binding, Flags::MISC_FROM_PRELUDE));
                             }
                         }
                     }
@@ -587,11 +627,7 @@ struct Flags: u8 {
                 }
                 Scope::BuiltinTypes => match this.primitive_type_table.primitive_types
                                                  .get(&ident.name).cloned() {
-                    Some(prim_ty) => {
-                        let binding = (Res::PrimTy(prim_ty), ty::Visibility::Public,
-                                       DUMMY_SP, ExpnId::root()).to_name_binding(this.arenas);
-                        Ok((binding, Flags::PRELUDE))
-                    }
+                    Some(prim_ty) => ok(Res::PrimTy(prim_ty), DUMMY_SP, this.arenas),
                     None => Err(Determinacy::Determined)
                 }
             };
@@ -608,8 +644,6 @@ struct Flags: u8 {
                         if res != innermost_res {
                             let builtin = Res::NonMacroAttr(NonMacroAttrKind::Builtin);
                             let derive_helper = Res::NonMacroAttr(NonMacroAttrKind::DeriveHelper);
-                            let legacy_helper =
-                                Res::NonMacroAttr(NonMacroAttrKind::LegacyPluginHelper);
 
                             let ambiguity_error_kind = if is_import {
                                 Some(AmbiguityKind::Import)
@@ -617,11 +651,6 @@ struct Flags: u8 {
                                 Some(AmbiguityKind::BuiltinAttr)
                             } else if innermost_res == derive_helper || res == derive_helper {
                                 Some(AmbiguityKind::DeriveHelper)
-                            } else if innermost_res == legacy_helper &&
-                                      flags.contains(Flags::PRELUDE) ||
-                                      res == legacy_helper &&
-                                      innermost_flags.contains(Flags::PRELUDE) {
-                                Some(AmbiguityKind::LegacyHelperVsPrelude)
                             } else if innermost_flags.contains(Flags::MACRO_RULES) &&
                                       flags.contains(Flags::MODULE) &&
                                       !this.disambiguate_legacy_vs_modern(innermost_binding,
@@ -681,20 +710,7 @@ struct Flags: u8 {
             return Ok(binding);
         }
 
-        let determinacy = Determinacy::determined(determinacy == Determinacy::Determined || force);
-        if determinacy == Determinacy::Determined && macro_kind == Some(MacroKind::Attr) &&
-           self.session.features_untracked().custom_attribute {
-            // For single-segment attributes interpret determinate "no resolution" as a custom
-            // attribute. (Lexical resolution implies the first segment and attr kind should imply
-            // the last segment, so we are certainly working with a single-segment attribute here.)
-            assert!(ns == MacroNS);
-            let binding = (Res::NonMacroAttr(NonMacroAttrKind::Custom),
-                           ty::Visibility::Public, orig_ident.span, ExpnId::root())
-                           .to_name_binding(self.arenas);
-            Ok(binding)
-        } else {
-            Err(determinacy)
-        }
+        Err(Determinacy::determined(determinacy == Determinacy::Determined || force))
     }
 
     crate fn finalize_macro_resolutions(&mut self) {
@@ -705,16 +721,7 @@ struct Flags: u8 {
                     // Make sure compilation does not succeed if preferred macro resolution
                     // has changed after the macro had been expanded. In theory all such
                     // situations should be reported as ambiguity errors, so this is a bug.
-                    if initial_res == Res::NonMacroAttr(NonMacroAttrKind::Custom) {
-                        // Yeah, legacy custom attributes are implemented using forced resolution
-                        // (which is a best effort error recovery tool, basically), so we can't
-                        // promise their resolution won't change later.
-                        let msg = format!("inconsistent resolution for a macro: first {}, then {}",
-                                          initial_res.descr(), res.descr());
-                        this.session.span_err(span, &msg);
-                    } else {
-                        span_bug!(span, "inconsistent resolution for a macro");
-                    }
+                    span_bug!(span, "inconsistent resolution for a macro");
                 }
             } else {
                 // It's possible that the macro was unresolved (indeterminate) and silently
@@ -826,7 +833,8 @@ fn prohibit_imported_non_macro_attrs(&self, binding: Option<&'a NameBinding<'a>>
                                          res: Option<Res>, span: Span) {
         if let Some(Res::NonMacroAttr(kind)) = res {
             if kind != NonMacroAttrKind::Tool && binding.map_or(true, |b| b.is_import()) {
-                let msg = format!("cannot use a {} through an import", kind.descr());
+                let msg =
+                    format!("cannot use {} {} through an import", kind.article(), kind.descr());
                 let mut err = self.session.struct_span_err(span, &msg);
                 if let Some(binding) = binding {
                     err.span_note(binding.span, &format!("the {} imported here", kind.descr()));