//! A bunch of methods and structures more or less related to resolving macros and //! interface provided by `Resolver` to macro expander. 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::Namespace::*; use crate::resolve_imports::ImportResolver; use rustc::hir::def::{self, DefKind, NonMacroAttrKind}; use rustc::hir::def_id; use rustc::middle::stability; use rustc::{ty, lint, span_bug}; use syntax::ast::{self, NodeId, Ident}; use syntax::attr::StabilityLevel; use syntax::edition::Edition; use syntax::feature_gate::{emit_feature_err, is_builtin_attr_name}; use syntax::feature_gate::GateIssue; use syntax::print::pprust; use syntax::symbol::{Symbol, kw, sym}; use syntax_expand::base::{self, InvocationRes, Indeterminate}; use syntax_expand::base::SyntaxExtension; use syntax_expand::expand::{AstFragment, AstFragmentKind, Invocation, InvocationKind}; use syntax_expand::compile_declarative_macro; use syntax_pos::hygiene::{self, ExpnId, ExpnData, ExpnKind}; use syntax_pos::{Span, DUMMY_SP}; use std::{mem, ptr}; use rustc_data_structures::sync::Lrc; use syntax_pos::hygiene::{MacroKind, AstPass}; type Res = def::Res; /// Binding produced by a `macro_rules` item. /// Not modularized, can shadow previous legacy bindings, etc. #[derive(Debug)] pub struct LegacyBinding<'a> { crate binding: &'a NameBinding<'a>, /// Legacy scope into which the `macro_rules` item was planted. crate parent_legacy_scope: LegacyScope<'a>, crate ident: Ident, } /// The scope introduced by a `macro_rules!` macro. /// This starts at the macro's definition and ends at the end of the macro's parent /// module (named or unnamed), or even further if it escapes with `#[macro_use]`. /// Some macro invocations need to introduce legacy scopes too because they /// can potentially expand into macro definitions. #[derive(Copy, Clone, Debug)] pub enum LegacyScope<'a> { /// Empty "root" scope at the crate start containing no names. Empty, /// The scope introduced by a `macro_rules!` macro definition. Binding(&'a LegacyBinding<'a>), /// The scope introduced by a macro invocation that can potentially /// create a `macro_rules!` macro definition. Invocation(ExpnId), } // Macro namespace is separated into two sub-namespaces, one for bang macros and // one for attribute-like macros (attributes, derives). // We ignore resolutions from one sub-namespace when searching names in scope for another. fn sub_namespace_match(candidate: Option, requirement: Option) -> bool { #[derive(PartialEq)] enum SubNS { Bang, AttrLike } let sub_ns = |kind| match kind { MacroKind::Bang => SubNS::Bang, MacroKind::Attr | MacroKind::Derive => SubNS::AttrLike, }; let candidate = candidate.map(sub_ns); let requirement = requirement.map(sub_ns); // "No specific sub-namespace" means "matches anything" for both requirements and candidates. candidate.is_none() || requirement.is_none() || candidate == requirement } // We don't want to format a path using pretty-printing, // `format!("{}", path)`, because that tries to insert // line-breaks and is slow. fn fast_print_path(path: &ast::Path) -> Symbol { if path.segments.len() == 1 { return path.segments[0].ident.name } else { let mut path_str = String::with_capacity(64); for (i, segment) in path.segments.iter().enumerate() { if i != 0 { path_str.push_str("::"); } if segment.ident.name != kw::PathRoot { path_str.push_str(&segment.ident.as_str()) } } Symbol::intern(&path_str) } } impl<'a> base::Resolver for Resolver<'a> { fn next_node_id(&mut self) -> NodeId { self.session.next_node_id() } fn resolve_dollar_crates(&mut self) { hygiene::update_dollar_crate_names(|ctxt| { let ident = Ident::new(kw::DollarCrate, DUMMY_SP.with_ctxt(ctxt)); match self.resolve_crate_root(ident).kind { ModuleKind::Def(.., name) if name != kw::Invalid => name, _ => kw::Crate, } }); } fn visit_ast_fragment_with_placeholders(&mut self, expansion: ExpnId, fragment: &AstFragment) { // Integrate the new AST fragment into all the definition and module structures. // We are inside the `expansion` now, but other parent scope components are still the same. let parent_scope = ParentScope { expansion, ..self.invocation_parent_scopes[&expansion] }; let output_legacy_scope = self.build_reduced_graph(fragment, parent_scope); self.output_legacy_scopes.insert(expansion, output_legacy_scope); parent_scope.module.unexpanded_invocations.borrow_mut().remove(&expansion); } fn register_builtin_macro(&mut self, ident: ast::Ident, ext: SyntaxExtension) { if self.builtin_macros.insert(ident.name, ext).is_some() { self.session.span_err(ident.span, &format!("built-in macro `{}` was already defined", ident)); } } // Create a new Expansion with a definition site of the provided module, or // a fake empty `#[no_implicit_prelude]` module if no module is provided. fn expansion_for_ast_pass( &mut self, call_site: Span, pass: AstPass, features: &[Symbol], parent_module_id: Option, ) -> ExpnId { let expn_id = ExpnId::fresh(Some(ExpnData::allow_unstable( ExpnKind::AstPass(pass), call_site, self.session.edition(), features.into(), ))); let parent_scope = if let Some(module_id) = parent_module_id { let parent_def_id = self.definitions.local_def_id(module_id); self.definitions.add_parent_module_of_macro_def(expn_id, parent_def_id); self.module_map[&parent_def_id] } else { self.definitions.add_parent_module_of_macro_def( expn_id, def_id::DefId::local(def_id::CRATE_DEF_INDEX), ); self.empty_module }; self.ast_transform_scopes.insert(expn_id, parent_scope); expn_id } fn resolve_imports(&mut self) { ImportResolver { r: self }.resolve_imports() } fn resolve_macro_invocation( &mut self, invoc: &Invocation, eager_expansion_root: ExpnId, force: bool ) -> Result { let invoc_id = invoc.expansion_data.id; let parent_scope = match self.invocation_parent_scopes.get(&invoc_id) { Some(parent_scope) => *parent_scope, None => { // If there's no entry in the table, then we are resolving an eagerly expanded // macro, which should inherit its parent scope from its eager expansion root - // the macro that requested this eager expansion. let parent_scope = *self.invocation_parent_scopes.get(&eager_expansion_root) .expect("non-eager expansion without a parent scope"); self.invocation_parent_scopes.insert(invoc_id, parent_scope); parent_scope } }; let (path, kind, derives, after_derive) = match invoc.kind { InvocationKind::Attr { ref attr, ref 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, .. } => (path, MacroKind::Derive, &[][..], false), InvocationKind::DeriveContainer { ref derives, .. } => { // Block expansion of the container until we resolve all derives in it. // This is required for two reasons: // - Derive helper attributes are in scope for the item to which the `#[derive]` // is applied, so they have to be produced by the container's expansion rather // than by individual derives. // - Derives in the container need to know whether one of them is a built-in `Copy`. // FIXME: Try to avoid repeated resolutions for derives here and in expansion. let mut exts = Vec::new(); for path in derives { exts.push(match self.resolve_macro_path( path, Some(MacroKind::Derive), &parent_scope, true, force ) { Ok((Some(ext), _)) => ext, Ok(_) | Err(Determinacy::Determined) => self.dummy_ext(MacroKind::Derive), Err(Determinacy::Undetermined) => return Err(Indeterminate), }) } return Ok(InvocationRes::DeriveContainer(exts)); } }; // Derives are not included when `invocations` are collected, so we have to add them here. let parent_scope = &ParentScope { derives, ..parent_scope }; let (ext, res) = self.smart_resolve_macro_path(path, kind, parent_scope, force)?; let span = invoc.span(); invoc_id.set_expn_data(ext.expn_data(parent_scope.expansion, span, fast_print_path(path))); if let Res::Def(_, def_id) = res { if after_derive { self.session.span_err(span, "macro attributes must be placed before `#[derive]`"); } self.macro_defs.insert(invoc_id, def_id); let normal_module_def_id = self.macro_def_scope(invoc_id).normal_ancestor_id; self.definitions.add_parent_module_of_macro_def(invoc_id, normal_module_def_id); } match invoc.fragment_kind { AstFragmentKind::Arms | AstFragmentKind::Fields | AstFragmentKind::FieldPats | AstFragmentKind::GenericParams | AstFragmentKind::Params | AstFragmentKind::StructFields | AstFragmentKind::Variants => { if let Res::Def(..) = res { self.session.span_err( span, &format!("expected an inert attribute, found {} {}", res.article(), res.descr()), ); return Ok(InvocationRes::Single(self.dummy_ext(kind))); } }, _ => {} } Ok(InvocationRes::Single(ext)) } fn check_unused_macros(&mut self) { for (&node_id, &span) in self.unused_macros.iter() { self.lint_buffer.buffer_lint( lint::builtin::UNUSED_MACROS, node_id, span, "unused macro definition" ); } } fn has_derive_copy(&self, expn_id: ExpnId) -> bool { self.containers_deriving_copy.contains(&expn_id) } fn add_derive_copy(&mut self, expn_id: ExpnId) { self.containers_deriving_copy.insert(expn_id); } } impl<'a> Resolver<'a> { /// Resolve macro path with error reporting and recovery. fn smart_resolve_macro_path( &mut self, path: &ast::Path, kind: MacroKind, parent_scope: &ParentScope<'a>, force: bool, ) -> Result<(Lrc, Res), Indeterminate> { let (ext, res) = match self.resolve_macro_path(path, Some(kind), parent_scope, true, force) { Ok((Some(ext), res)) => (ext, res), // Use dummy syntax extensions for unresolved macros for better recovery. Ok((None, res)) => (self.dummy_ext(kind), res), Err(Determinacy::Determined) => (self.dummy_ext(kind), Res::Err), Err(Determinacy::Undetermined) => return Err(Indeterminate), }; // Report errors and enforce feature gates for the resolved macro. let features = self.session.features_untracked(); for segment in &path.segments { if let Some(args) = &segment.args { self.session.span_err(args.span(), "generic arguments in macro path"); } if kind == MacroKind::Attr && !features.rustc_attrs && segment.ident.as_str().starts_with("rustc") { let msg = "attributes starting with `rustc` are reserved for use by the `rustc` compiler"; emit_feature_err( &self.session.parse_sess, sym::rustc_attrs, segment.ident.span, GateIssue::Language, msg, ); } } match 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::NonMacroAttr(..) | Res::Err => {} _ => panic!("expected `DefKind::Macro` or `Res::NonMacroAttr`"), }; self.check_stability_and_deprecation(&ext, path); Ok(if ext.macro_kind() != kind { let expected = kind.descr_expected(); let path_str = pprust::path_to_string(path); let msg = format!("expected {}, found {} `{}`", expected, res.descr(), path_str); self.session.struct_span_err(path.span, &msg) .span_label(path.span, format!("not {} {}", kind.article(), expected)) .emit(); // Use dummy syntax extensions for unexpected macro kinds for better recovery. (self.dummy_ext(kind), Res::Err) } else { (ext, res) }) } pub fn resolve_macro_path( &mut self, path: &ast::Path, kind: Option, parent_scope: &ParentScope<'a>, trace: bool, force: bool, ) -> Result<(Option>, Res), Determinacy> { let path_span = path.span; let mut path = Segment::from_path(path); // Possibly apply the macro helper hack if kind == Some(MacroKind::Bang) && path.len() == 1 && path[0].ident.span.ctxt().outer_expn_data().local_inner_macros { let root = Ident::new(kw::DollarCrate, path[0].ident.span); path.insert(0, Segment::from_ident(root)); } let res = if path.len() > 1 { let res = match self.resolve_path(&path, Some(MacroNS), parent_scope, false, path_span, CrateLint::No) { PathResult::NonModule(path_res) if path_res.unresolved_segments() == 0 => { Ok(path_res.base_res()) } PathResult::Indeterminate if !force => return Err(Determinacy::Undetermined), PathResult::NonModule(..) | PathResult::Indeterminate | PathResult::Failed { .. } => Err(Determinacy::Determined), PathResult::Module(..) => unreachable!(), }; if trace { let kind = kind.expect("macro kind must be specified if tracing is enabled"); self.multi_segment_macro_resolutions .push((path, path_span, kind, *parent_scope, res.ok())); } self.prohibit_imported_non_macro_attrs(None, res.ok(), path_span); res } else { let scope_set = kind.map_or(ScopeSet::All(MacroNS, false), ScopeSet::Macro); let binding = self.early_resolve_ident_in_lexical_scope( path[0].ident, scope_set, parent_scope, false, force, path_span ); if let Err(Determinacy::Undetermined) = binding { return Err(Determinacy::Undetermined); } if trace { let kind = kind.expect("macro kind must be specified if tracing is enabled"); self.single_segment_macro_resolutions .push((path[0].ident, kind, *parent_scope, binding.ok())); } let res = binding.map(|binding| binding.res()); self.prohibit_imported_non_macro_attrs(binding.ok(), res.ok(), path_span); res }; res.map(|res| (self.get_macro(res), res)) } // Resolve an identifier in lexical scope. // This is a variation of `fn resolve_ident_in_lexical_scope` that can be run during // expansion and import resolution (perhaps they can be merged in the future). // The function is used for resolving initial segments of macro paths (e.g., `foo` in // `foo::bar!(); or `foo!();`) and also for import paths on 2018 edition. crate fn early_resolve_ident_in_lexical_scope( &mut self, orig_ident: Ident, scope_set: ScopeSet, parent_scope: &ParentScope<'a>, record_used: bool, force: bool, path_span: Span, ) -> Result<&'a NameBinding<'a>, Determinacy> { bitflags::bitflags! { 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; } } assert!(force || !record_used); // `record_used` implies `force` // Make sure `self`, `super` etc produce an error when passed to here. if orig_ident.is_path_segment_keyword() { return Err(Determinacy::Determined); } let (ns, macro_kind, is_import) = match scope_set { ScopeSet::All(ns, is_import) => (ns, None, is_import), ScopeSet::AbsolutePath(ns) => (ns, None, false), ScopeSet::Macro(macro_kind) => (MacroNS, Some(macro_kind), false), }; // This is *the* result, resolution from the scope closest to the resolved identifier. // However, sometimes this result is "weak" because it comes from a glob import or // a macro expansion, and in this case it cannot shadow names from outer scopes, e.g. // mod m { ... } // solution in outer scope // { // use prefix::*; // imports another `m` - innermost solution // // weak, cannot shadow the outer `m`, need to report ambiguity error // m::mac!(); // } // So we have to save the innermost solution and continue searching in outer scopes // to detect potential ambiguities. let mut innermost_result: Option<(&NameBinding<'_>, Flags)> = None; let mut determinacy = Determinacy::Determined; // 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 result = match scope { Scope::DeriveHelpers => { 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())); break; } Ok(_) | Err(Determinacy::Determined) => {} Err(Determinacy::Undetermined) => result = Err(Determinacy::Undetermined), } } result } Scope::MacroRules(legacy_scope) => match legacy_scope { LegacyScope::Binding(legacy_binding) if ident == legacy_binding.ident => Ok((legacy_binding.binding, Flags::MACRO_RULES)), LegacyScope::Invocation(invoc_id) if !this.output_legacy_scopes.contains_key(&invoc_id) => Err(Determinacy::Undetermined), _ => Err(Determinacy::Determined), } Scope::CrateRoot => { let root_ident = Ident::new(kw::PathRoot, ident.span); let root_module = this.resolve_crate_root(root_ident); let binding = this.resolve_ident_in_module_ext( ModuleOrUniformRoot::Module(root_module), ident, ns, parent_scope, record_used, path_span, ); match binding { Ok(binding) => Ok((binding, Flags::MODULE | Flags::MISC_SUGGEST_CRATE)), Err((Determinacy::Undetermined, Weak::No)) => return Some(Err(Determinacy::determined(force))), Err((Determinacy::Undetermined, Weak::Yes)) => Err(Determinacy::Undetermined), Err((Determinacy::Determined, _)) => Err(Determinacy::Determined), } } Scope::Module(module) => { let adjusted_parent_scope = &ParentScope { module, ..*parent_scope }; let binding = this.resolve_ident_in_module_unadjusted_ext( ModuleOrUniformRoot::Module(module), ident, ns, adjusted_parent_scope, true, record_used, path_span, ); match binding { Ok(binding) => { let misc_flags = if ptr::eq(module, this.graph_root) { Flags::MISC_SUGGEST_CRATE } else if module.is_normal() { Flags::MISC_SUGGEST_SELF } else { Flags::empty() }; Ok((binding, Flags::MODULE | misc_flags)) } Err((Determinacy::Undetermined, Weak::No)) => return Some(Err(Determinacy::determined(force))), Err((Determinacy::Undetermined, Weak::Yes)) => Err(Determinacy::Undetermined), Err((Determinacy::Determined, _)) => Err(Determinacy::Determined), } } Scope::MacroUsePrelude => match this.macro_use_prelude.get(&ident.name).cloned() { Some(binding) => Ok((binding, Flags::PRELUDE | 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)) } 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)) } else { Err(Determinacy::Determined) } Scope::ExternPrelude => match this.extern_prelude_get(ident, !record_used) { Some(binding) => Ok((binding, Flags::PRELUDE)), 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::StdLibPrelude => { let mut result = Err(Determinacy::Determined); if let Some(prelude) = this.prelude { if let Ok(binding) = this.resolve_ident_in_module_unadjusted( ModuleOrUniformRoot::Module(prelude), ident, ns, parent_scope, false, path_span, ) { if use_prelude || this.is_builtin_macro(binding.res()) { result = Ok((binding, Flags::PRELUDE | Flags::MISC_FROM_PRELUDE)); } } } result } 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)) } None => Err(Determinacy::Determined) } }; match result { Ok((binding, flags)) if sub_namespace_match(binding.macro_kind(), macro_kind) => { if !record_used { return Some(Ok(binding)); } if let Some((innermost_binding, innermost_flags)) = innermost_result { // Found another solution, if the first one was "weak", report an error. let (res, innermost_res) = (binding.res(), innermost_binding.res()); 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) } else if innermost_res == builtin || res == builtin { 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, binding) || flags.contains(Flags::MACRO_RULES) && innermost_flags.contains(Flags::MODULE) && !this.disambiguate_legacy_vs_modern(binding, innermost_binding) { Some(AmbiguityKind::LegacyVsModern) } else if innermost_binding.is_glob_import() { Some(AmbiguityKind::GlobVsOuter) } else if innermost_binding.may_appear_after(parent_scope.expansion, binding) { Some(AmbiguityKind::MoreExpandedVsOuter) } else { None }; if let Some(kind) = ambiguity_error_kind { let misc = |f: Flags| if f.contains(Flags::MISC_SUGGEST_CRATE) { AmbiguityErrorMisc::SuggestCrate } else if f.contains(Flags::MISC_SUGGEST_SELF) { AmbiguityErrorMisc::SuggestSelf } else if f.contains(Flags::MISC_FROM_PRELUDE) { AmbiguityErrorMisc::FromPrelude } else { AmbiguityErrorMisc::None }; this.ambiguity_errors.push(AmbiguityError { kind, ident: orig_ident, b1: innermost_binding, b2: binding, misc1: misc(innermost_flags), misc2: misc(flags), }); return Some(Ok(innermost_binding)); } } } else { // Found the first solution. innermost_result = Some((binding, flags)); } } Ok(..) | Err(Determinacy::Determined) => {} Err(Determinacy::Undetermined) => determinacy = Determinacy::Undetermined } None }); if let Some(break_result) = break_result { return break_result; } // The first found solution was the only one, return it. if let Some((binding, _)) = innermost_result { 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) } } crate fn finalize_macro_resolutions(&mut self) { let check_consistency = |this: &mut Self, path: &[Segment], span, kind: MacroKind, initial_res: Option, res: Res| { if let Some(initial_res) = initial_res { if res != initial_res && res != Res::Err && this.ambiguity_errors.is_empty() { // 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"); } } } else { // It's possible that the macro was unresolved (indeterminate) and silently // expanded into a dummy fragment for recovery during expansion. // Now, post-expansion, the resolution may succeed, but we can't change the // past and need to report an error. // However, non-speculative `resolve_path` can successfully return private items // even if speculative `resolve_path` returned nothing previously, so we skip this // less informative error if the privacy error is reported elsewhere. if this.privacy_errors.is_empty() { let msg = format!("cannot determine resolution for the {} `{}`", kind.descr(), Segment::names_to_string(path)); let msg_note = "import resolution is stuck, try simplifying macro imports"; this.session.struct_span_err(span, &msg).note(msg_note).emit(); } } }; let macro_resolutions = mem::take(&mut self.multi_segment_macro_resolutions); for (mut path, path_span, kind, parent_scope, initial_res) in macro_resolutions { // FIXME: Path resolution will ICE if segment IDs present. for seg in &mut path { seg.id = None; } match self.resolve_path( &path, Some(MacroNS), &parent_scope, true, path_span, CrateLint::No ) { PathResult::NonModule(path_res) if path_res.unresolved_segments() == 0 => { let res = path_res.base_res(); check_consistency(self, &path, path_span, kind, initial_res, res); } path_res @ PathResult::NonModule(..) | path_res @ PathResult::Failed { .. } => { let (span, label) = if let PathResult::Failed { span, label, .. } = path_res { (span, label) } else { (path_span, format!("partially resolved path in {} {}", kind.article(), kind.descr())) }; self.report_error(span, ResolutionError::FailedToResolve { label, suggestion: None }); } PathResult::Module(..) | PathResult::Indeterminate => unreachable!(), } } let macro_resolutions = mem::take(&mut self.single_segment_macro_resolutions); for (ident, kind, parent_scope, initial_binding) in macro_resolutions { match self.early_resolve_ident_in_lexical_scope(ident, ScopeSet::Macro(kind), &parent_scope, true, true, ident.span) { Ok(binding) => { let initial_res = initial_binding.map(|initial_binding| { self.record_use(ident, MacroNS, initial_binding, false); initial_binding.res() }); let res = binding.res(); let seg = Segment::from_ident(ident); check_consistency(self, &[seg], ident.span, kind, initial_res, res); } Err(..) => { let expected = kind.descr_expected(); let msg = format!("cannot find {} `{}` in this scope", expected, ident); let mut err = self.session.struct_span_err(ident.span, &msg); self.unresolved_macro_suggestions(&mut err, kind, &parent_scope, ident); err.emit(); } } } let builtin_attrs = mem::take(&mut self.builtin_attrs); for (ident, parent_scope) in builtin_attrs { let _ = self.early_resolve_ident_in_lexical_scope( ident, ScopeSet::Macro(MacroKind::Attr), &parent_scope, true, true, ident.span ); } } fn check_stability_and_deprecation(&mut self, ext: &SyntaxExtension, path: &ast::Path) { let span = path.span; if let Some(stability) = &ext.stability { if let StabilityLevel::Unstable { reason, issue, is_soft } = stability.level { let feature = stability.feature; if !self.active_features.contains(&feature) && !span.allows_unstable(feature) { let node_id = ast::CRATE_NODE_ID; let lint_buffer = &mut self.lint_buffer; let soft_handler = |lint, span, msg: &_| { lint_buffer.buffer_lint(lint, node_id, span, msg) }; stability::report_unstable( self.session, feature, reason, issue, is_soft, span, soft_handler ); } } if let Some(depr) = &stability.rustc_depr { let path = pprust::path_to_string(path); let (message, lint) = stability::rustc_deprecation_message(depr, &path); stability::early_report_deprecation( &mut self.lint_buffer, &message, depr.suggestion, lint, span ); } } if let Some(depr) = &ext.deprecation { let path = pprust::path_to_string(&path); let (message, lint) = stability::deprecation_message(depr, &path); stability::early_report_deprecation(&mut self.lint_buffer, &message, None, lint, span); } } fn prohibit_imported_non_macro_attrs(&self, binding: Option<&'a NameBinding<'a>>, res: Option, 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 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())); } err.emit(); } } } crate fn check_reserved_macro_name(&mut self, ident: Ident, res: Res) { // Reserve some names that are not quite covered by the general check // performed on `Resolver::builtin_attrs`. if ident.name == sym::cfg || ident.name == sym::cfg_attr || ident.name == sym::derive { let macro_kind = self.get_macro(res).map(|ext| ext.macro_kind()); if macro_kind.is_some() && sub_namespace_match(macro_kind, Some(MacroKind::Attr)) { self.session.span_err( ident.span, &format!("name `{}` is reserved in attribute namespace", ident) ); } } } /// Compile the macro into a `SyntaxExtension` and possibly replace it with a pre-defined /// extension partially or entirely for built-in macros and legacy plugin macros. crate fn compile_macro(&mut self, item: &ast::Item, edition: Edition) -> SyntaxExtension { let mut result = compile_declarative_macro( &self.session.parse_sess, self.session.features_untracked(), item, edition ); if result.is_builtin { // The macro was marked with `#[rustc_builtin_macro]`. if let Some(ext) = self.builtin_macros.remove(&item.ident.name) { if ext.is_builtin { // The macro is a built-in, replace only the expander function. result.kind = ext.kind; } else { // The macro is from a plugin, the in-source definition is dummy, // take all the data from the resolver. result = ext; } } else { let msg = format!("cannot find a built-in macro with name `{}`", item.ident); self.session.span_err(item.span, &msg); } } result } }