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;
}
}
+/// 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.session.next_node_id()
+ self.next_node_id()
}
fn resolve_dollar_crates(&mut self) {
let (path, kind, derives, after_derive) = match invoc.kind {
InvocationKind::Attr { ref attr, ref derives, after_derive, .. } =>
- (&attr.path, MacroKind::Attr, self.arenas.alloc_ast_paths(derives), after_derive),
+ (&attr.get_normal_item().path,
+ MacroKind::Attr,
+ self.arenas.alloc_ast_paths(derives),
+ after_derive),
InvocationKind::Bang { ref mac, .. } =>
(&mac.path, MacroKind::Bang, &[][..], false),
InvocationKind::Derive { ref 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;
}
}
// 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) => {}
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);
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));
}
}
}
}
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)
}
};
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)
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,
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) {
// 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
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()));