Auto merge of #54086 - petrochenkov:derhelp, r=alexcrichton
resolve: Future proof derive helper attributes Derive helpers no longer require going through recovery mode (fixes https://github.com/rust-lang/rust/issues/53481). They also report an error if they are ambiguous with any other macro in scope, so we can resolve the question about their exact priority sometime later (cc https://github.com/rust-lang/rust/issues/52226).
This commit is contained in:
commit
994cdd9185
11 changed files with 221 additions and 106 deletions
|
@ -13,7 +13,7 @@
|
|||
//! Here we build the "reduced graph": the graph of the module tree without
|
||||
//! any imports resolved.
|
||||
|
||||
use macros::{InvocationData, LegacyScope};
|
||||
use macros::{InvocationData, ParentScope, LegacyScope};
|
||||
use resolve_imports::ImportDirective;
|
||||
use resolve_imports::ImportDirectiveSubclass::{self, GlobImport, SingleImport};
|
||||
use {Module, ModuleData, ModuleKind, NameBinding, NameBindingKind, ToNameBinding};
|
||||
|
@ -1061,8 +1061,15 @@ impl<'a, 'b, 'cl> Visitor<'a> for BuildReducedGraphVisitor<'a, 'b, 'cl> {
|
|||
|
||||
fn visit_attribute(&mut self, attr: &'a ast::Attribute) {
|
||||
if !attr.is_sugared_doc && is_builtin_attr(attr) {
|
||||
self.resolver.current_module.builtin_attrs.borrow_mut().push((
|
||||
attr.path.segments[0].ident, self.expansion, self.current_legacy_scope
|
||||
let parent_scope = ParentScope {
|
||||
module: self.resolver.current_module.nearest_item_scope(),
|
||||
expansion: self.expansion,
|
||||
legacy: self.current_legacy_scope,
|
||||
// Let's hope discerning built-in attributes from derive helpers is not necessary
|
||||
derives: Vec::new(),
|
||||
};
|
||||
parent_scope.module.builtin_attrs.borrow_mut().push((
|
||||
attr.path.segments[0].ident, parent_scope
|
||||
));
|
||||
}
|
||||
visit::walk_attribute(self, attr);
|
||||
|
|
|
@ -80,7 +80,7 @@ use std::mem::replace;
|
|||
use rustc_data_structures::sync::Lrc;
|
||||
|
||||
use resolve_imports::{ImportDirective, ImportDirectiveSubclass, NameResolution, ImportResolver};
|
||||
use macros::{InvocationData, LegacyBinding, LegacyScope};
|
||||
use macros::{InvocationData, LegacyBinding, ParentScope};
|
||||
|
||||
// NB: This module needs to be declared first so diagnostics are
|
||||
// registered before they are used.
|
||||
|
@ -1009,9 +1009,9 @@ pub struct ModuleData<'a> {
|
|||
normal_ancestor_id: DefId,
|
||||
|
||||
resolutions: RefCell<FxHashMap<(Ident, Namespace), &'a RefCell<NameResolution<'a>>>>,
|
||||
legacy_macro_resolutions: RefCell<Vec<(Ident, MacroKind, Mark, LegacyScope<'a>, Option<Def>)>>,
|
||||
legacy_macro_resolutions: RefCell<Vec<(Ident, MacroKind, ParentScope<'a>, Option<Def>)>>,
|
||||
macro_resolutions: RefCell<Vec<(Box<[Ident]>, Span)>>,
|
||||
builtin_attrs: RefCell<Vec<(Ident, Mark, LegacyScope<'a>)>>,
|
||||
builtin_attrs: RefCell<Vec<(Ident, ParentScope<'a>)>>,
|
||||
|
||||
// Macro invocations that can expand into items in this module.
|
||||
unresolved_invocations: RefCell<FxHashSet<Mark>>,
|
||||
|
@ -3494,16 +3494,17 @@ impl<'a, 'crateloader: 'a> Resolver<'a, 'crateloader> {
|
|||
path_span: Span,
|
||||
crate_lint: CrateLint,
|
||||
) -> PathResult<'a> {
|
||||
self.resolve_path_with_parent_expansion(base_module, path, opt_ns, Mark::root(),
|
||||
record_used, path_span, crate_lint)
|
||||
let parent_scope = ParentScope { module: self.current_module, ..self.dummy_parent_scope() };
|
||||
self.resolve_path_with_parent_scope(base_module, path, opt_ns, &parent_scope,
|
||||
record_used, path_span, crate_lint)
|
||||
}
|
||||
|
||||
fn resolve_path_with_parent_expansion(
|
||||
fn resolve_path_with_parent_scope(
|
||||
&mut self,
|
||||
base_module: Option<ModuleOrUniformRoot<'a>>,
|
||||
path: &[Ident],
|
||||
opt_ns: Option<Namespace>, // `None` indicates a module path
|
||||
parent_expansion: Mark,
|
||||
parent_scope: &ParentScope<'a>,
|
||||
record_used: bool,
|
||||
path_span: Span,
|
||||
crate_lint: CrateLint,
|
||||
|
@ -3511,6 +3512,7 @@ impl<'a, 'crateloader: 'a> Resolver<'a, 'crateloader> {
|
|||
let mut module = base_module;
|
||||
let mut allow_super = true;
|
||||
let mut second_binding = None;
|
||||
self.current_module = parent_scope.module;
|
||||
|
||||
debug!(
|
||||
"resolve_path(path={:?}, opt_ns={:?}, record_used={:?}, \
|
||||
|
@ -3596,9 +3598,8 @@ impl<'a, 'crateloader: 'a> Resolver<'a, 'crateloader> {
|
|||
self.resolve_ident_in_module(module, ident, ns, record_used, path_span)
|
||||
} else if opt_ns == Some(MacroNS) {
|
||||
assert!(ns == TypeNS);
|
||||
self.resolve_lexical_macro_path_segment(ident, ns, None, parent_expansion,
|
||||
record_used, record_used, path_span)
|
||||
.map(|(binding, _)| binding)
|
||||
self.resolve_lexical_macro_path_segment(ident, ns, None, parent_scope, record_used,
|
||||
record_used, path_span).map(|(b, _)| b)
|
||||
} else {
|
||||
let record_used_id =
|
||||
if record_used { crate_lint.node_id().or(Some(CRATE_NODE_ID)) } else { None };
|
||||
|
|
|
@ -101,6 +101,15 @@ pub enum LegacyScope<'a> {
|
|||
Invocation(&'a InvocationData<'a>),
|
||||
}
|
||||
|
||||
/// Everything you need to resolve a macro path.
|
||||
#[derive(Clone)]
|
||||
pub struct ParentScope<'a> {
|
||||
crate module: Module<'a>,
|
||||
crate expansion: Mark,
|
||||
crate legacy: LegacyScope<'a>,
|
||||
crate derives: Vec<ast::Path>,
|
||||
}
|
||||
|
||||
pub struct ProcMacError {
|
||||
crate_name: Symbol,
|
||||
name: Symbol,
|
||||
|
@ -326,14 +335,15 @@ impl<'a, 'crateloader: 'a> base::Resolver for Resolver<'a, 'crateloader> {
|
|||
InvocationKind::Attr { attr: None, .. } =>
|
||||
return Ok(None),
|
||||
InvocationKind::Attr { attr: Some(ref attr), ref traits, .. } =>
|
||||
(&attr.path, MacroKind::Attr, &traits[..]),
|
||||
(&attr.path, MacroKind::Attr, traits.clone()),
|
||||
InvocationKind::Bang { ref mac, .. } =>
|
||||
(&mac.node.path, MacroKind::Bang, &[][..]),
|
||||
(&mac.node.path, MacroKind::Bang, Vec::new()),
|
||||
InvocationKind::Derive { ref path, .. } =>
|
||||
(path, MacroKind::Derive, &[][..]),
|
||||
(path, MacroKind::Derive, Vec::new()),
|
||||
};
|
||||
|
||||
let (def, ext) = self.resolve_macro_to_def(path, kind, invoc_id, derives_in_scope, force)?;
|
||||
let parent_scope = self.invoc_parent_scope(invoc_id, derives_in_scope);
|
||||
let (def, ext) = self.resolve_macro_to_def(path, kind, &parent_scope, force)?;
|
||||
|
||||
if let Def::Macro(def_id, _) = def {
|
||||
self.macro_defs.insert(invoc.expansion_data.mark, def_id);
|
||||
|
@ -349,9 +359,10 @@ impl<'a, 'crateloader: 'a> base::Resolver for Resolver<'a, 'crateloader> {
|
|||
}
|
||||
|
||||
fn resolve_macro_path(&mut self, path: &ast::Path, kind: MacroKind, invoc_id: Mark,
|
||||
derives_in_scope: &[ast::Path], force: bool)
|
||||
derives_in_scope: Vec<ast::Path>, force: bool)
|
||||
-> Result<Lrc<SyntaxExtension>, Determinacy> {
|
||||
Ok(self.resolve_macro_to_def(path, kind, invoc_id, derives_in_scope, force)?.1)
|
||||
let parent_scope = self.invoc_parent_scope(invoc_id, derives_in_scope);
|
||||
Ok(self.resolve_macro_to_def(path, kind, &parent_scope, force)?.1)
|
||||
}
|
||||
|
||||
fn check_unused_macros(&self) {
|
||||
|
@ -373,10 +384,28 @@ impl<'a, 'crateloader: 'a> base::Resolver for Resolver<'a, 'crateloader> {
|
|||
}
|
||||
|
||||
impl<'a, 'cl> Resolver<'a, 'cl> {
|
||||
fn resolve_macro_to_def(&mut self, path: &ast::Path, kind: MacroKind, invoc_id: Mark,
|
||||
derives_in_scope: &[ast::Path], force: bool)
|
||||
-> Result<(Def, Lrc<SyntaxExtension>), Determinacy> {
|
||||
let def = self.resolve_macro_to_def_inner(path, kind, invoc_id, derives_in_scope, force);
|
||||
pub fn dummy_parent_scope(&mut self) -> ParentScope<'a> {
|
||||
self.invoc_parent_scope(Mark::root(), Vec::new())
|
||||
}
|
||||
|
||||
fn invoc_parent_scope(&mut self, invoc_id: Mark, derives: Vec<ast::Path>) -> ParentScope<'a> {
|
||||
let invoc = self.invocations[&invoc_id];
|
||||
ParentScope {
|
||||
module: invoc.module.get().nearest_item_scope(),
|
||||
expansion: invoc_id.parent(),
|
||||
legacy: invoc.parent_legacy_scope.get(),
|
||||
derives,
|
||||
}
|
||||
}
|
||||
|
||||
fn resolve_macro_to_def(
|
||||
&mut self,
|
||||
path: &ast::Path,
|
||||
kind: MacroKind,
|
||||
parent_scope: &ParentScope<'a>,
|
||||
force: bool,
|
||||
) -> Result<(Def, Lrc<SyntaxExtension>), Determinacy> {
|
||||
let def = self.resolve_macro_to_def_inner(path, kind, parent_scope, force);
|
||||
|
||||
// Report errors and enforce feature gates for the resolved macro.
|
||||
if def != Err(Determinacy::Undetermined) {
|
||||
|
@ -440,15 +469,15 @@ impl<'a, 'cl> Resolver<'a, 'cl> {
|
|||
Ok((def, self.get_macro(def)))
|
||||
}
|
||||
|
||||
pub fn resolve_macro_to_def_inner(&mut self, path: &ast::Path, kind: MacroKind, invoc_id: Mark,
|
||||
derives_in_scope: &[ast::Path], force: bool)
|
||||
-> Result<Def, Determinacy> {
|
||||
pub fn resolve_macro_to_def_inner(
|
||||
&mut self,
|
||||
path: &ast::Path,
|
||||
kind: MacroKind,
|
||||
parent_scope: &ParentScope<'a>,
|
||||
force: bool,
|
||||
) -> Result<Def, Determinacy> {
|
||||
let ast::Path { ref segments, span } = *path;
|
||||
let mut path: Vec<_> = segments.iter().map(|seg| seg.ident).collect();
|
||||
let invocation = self.invocations[&invoc_id];
|
||||
let parent_expansion = invoc_id.parent();
|
||||
let parent_legacy_scope = invocation.parent_legacy_scope.get();
|
||||
self.current_module = invocation.module.get().nearest_item_scope();
|
||||
|
||||
// Possibly apply the macro helper hack
|
||||
if kind == MacroKind::Bang && path.len() == 1 &&
|
||||
|
@ -458,9 +487,9 @@ impl<'a, 'cl> Resolver<'a, 'cl> {
|
|||
}
|
||||
|
||||
if path.len() > 1 {
|
||||
let def = match self.resolve_path_with_parent_expansion(None, &path, Some(MacroNS),
|
||||
parent_expansion, false, span,
|
||||
CrateLint::No) {
|
||||
let def = match self.resolve_path_with_parent_scope(None, &path, Some(MacroNS),
|
||||
parent_scope, false, span,
|
||||
CrateLint::No) {
|
||||
PathResult::NonModule(path_res) => match path_res.base_def() {
|
||||
Def::Err => Err(Determinacy::Determined),
|
||||
def @ _ => {
|
||||
|
@ -480,19 +509,17 @@ impl<'a, 'cl> Resolver<'a, 'cl> {
|
|||
Err(Determinacy::Determined)
|
||||
},
|
||||
};
|
||||
self.current_module.macro_resolutions.borrow_mut()
|
||||
parent_scope.module.macro_resolutions.borrow_mut()
|
||||
.push((path.into_boxed_slice(), span));
|
||||
return def;
|
||||
}
|
||||
|
||||
let legacy_resolution = self.resolve_legacy_scope(
|
||||
path[0], Some(kind), parent_expansion, parent_legacy_scope, false
|
||||
);
|
||||
let result = if let Some(legacy_binding) = legacy_resolution {
|
||||
let result = if let Some(legacy_binding) = self.resolve_legacy_scope(path[0], Some(kind),
|
||||
parent_scope, false) {
|
||||
Ok(legacy_binding.def())
|
||||
} else {
|
||||
match self.resolve_lexical_macro_path_segment(path[0], MacroNS, Some(kind),
|
||||
parent_expansion, false, force, span) {
|
||||
parent_scope, false, force, span) {
|
||||
Ok((binding, _)) => Ok(binding.def_ignoring_ambiguity()),
|
||||
Err(Determinacy::Undetermined) => return Err(Determinacy::Undetermined),
|
||||
Err(Determinacy::Determined) => {
|
||||
|
@ -502,44 +529,10 @@ impl<'a, 'cl> Resolver<'a, 'cl> {
|
|||
}
|
||||
};
|
||||
|
||||
self.current_module.legacy_macro_resolutions.borrow_mut()
|
||||
.push((path[0], kind, parent_expansion, parent_legacy_scope, result.ok()));
|
||||
parent_scope.module.legacy_macro_resolutions.borrow_mut()
|
||||
.push((path[0], kind, parent_scope.clone(), result.ok()));
|
||||
|
||||
if let Ok(Def::NonMacroAttr(NonMacroAttrKind::Custom)) = result {} else {
|
||||
return result;
|
||||
}
|
||||
|
||||
// At this point we've found that the `attr` is determinately unresolved and thus can be
|
||||
// interpreted as a custom attribute. Normally custom attributes are feature gated, but
|
||||
// it may be a custom attribute whitelisted by a derive macro and they do not require
|
||||
// a feature gate.
|
||||
//
|
||||
// So here we look through all of the derive annotations in scope and try to resolve them.
|
||||
// If they themselves successfully resolve *and* one of the resolved derive macros
|
||||
// whitelists this attribute's name, then this is a registered attribute and we can convert
|
||||
// it from a "generic custom attrite" into a "known derive helper attribute".
|
||||
assert!(kind == MacroKind::Attr);
|
||||
enum ConvertToDeriveHelper { Yes, No, DontKnow }
|
||||
let mut convert_to_derive_helper = ConvertToDeriveHelper::No;
|
||||
for derive in derives_in_scope {
|
||||
match self.resolve_macro_path(derive, MacroKind::Derive, invoc_id, &[], force) {
|
||||
Ok(ext) => if let SyntaxExtension::ProcMacroDerive(_, ref inert_attrs, _) = *ext {
|
||||
if inert_attrs.contains(&path[0].name) {
|
||||
convert_to_derive_helper = ConvertToDeriveHelper::Yes;
|
||||
break
|
||||
}
|
||||
},
|
||||
Err(Determinacy::Undetermined) =>
|
||||
convert_to_derive_helper = ConvertToDeriveHelper::DontKnow,
|
||||
Err(Determinacy::Determined) => {}
|
||||
}
|
||||
}
|
||||
|
||||
match convert_to_derive_helper {
|
||||
ConvertToDeriveHelper::Yes => Ok(Def::NonMacroAttr(NonMacroAttrKind::DeriveHelper)),
|
||||
ConvertToDeriveHelper::No => result,
|
||||
ConvertToDeriveHelper::DontKnow => Err(Determinacy::determined(force)),
|
||||
}
|
||||
result
|
||||
}
|
||||
|
||||
// Resolve the initial segment of a non-global macro path
|
||||
|
@ -551,7 +544,7 @@ impl<'a, 'cl> Resolver<'a, 'cl> {
|
|||
mut ident: Ident,
|
||||
ns: Namespace,
|
||||
kind: Option<MacroKind>,
|
||||
parent_expansion: Mark,
|
||||
parent_scope: &ParentScope<'a>,
|
||||
record_used: bool,
|
||||
force: bool,
|
||||
path_span: Span,
|
||||
|
@ -580,6 +573,13 @@ impl<'a, 'cl> Resolver<'a, 'cl> {
|
|||
// 2b. Standard library prelude is currently implemented as `macro-use` (closed, controlled)
|
||||
// 3. Language prelude: builtin macros (closed, controlled, except for legacy plugins).
|
||||
// 4. Language prelude: builtin attributes (closed, controlled).
|
||||
// N (unordered). Derive helpers (open, not controlled). All ambiguities with other names
|
||||
// are currently reported as errors. They should be higher in priority than preludes
|
||||
// and maybe even names in modules according to the "general principles" above. They
|
||||
// also should be subject to restricted shadowing because are effectively produced by
|
||||
// derives (you need to resolve the derive first to add helpers into scope), but they
|
||||
// should be available before the derive is expanded for compatibility.
|
||||
// It's mess in general, so we are being conservative for now.
|
||||
|
||||
assert!(ns == TypeNS || ns == MacroNS);
|
||||
assert!(force || !record_used); // `record_used` implies `force`
|
||||
|
@ -603,6 +603,7 @@ impl<'a, 'cl> Resolver<'a, 'cl> {
|
|||
MacroUsePrelude,
|
||||
BuiltinMacros,
|
||||
BuiltinAttrs,
|
||||
DeriveHelpers,
|
||||
ExternPrelude,
|
||||
ToolPrelude,
|
||||
StdLibPrelude,
|
||||
|
@ -610,8 +611,8 @@ impl<'a, 'cl> Resolver<'a, 'cl> {
|
|||
}
|
||||
|
||||
// Go through all the scopes and try to resolve the name.
|
||||
let mut where_to_resolve = WhereToResolve::Module(self.current_module);
|
||||
let mut use_prelude = !self.current_module.no_implicit_prelude;
|
||||
let mut where_to_resolve = WhereToResolve::Module(parent_scope.module);
|
||||
let mut use_prelude = !parent_scope.module.no_implicit_prelude;
|
||||
loop {
|
||||
let result = match where_to_resolve {
|
||||
WhereToResolve::Module(module) => {
|
||||
|
@ -652,6 +653,26 @@ impl<'a, 'cl> Resolver<'a, 'cl> {
|
|||
Err(Determinacy::Determined)
|
||||
}
|
||||
}
|
||||
WhereToResolve::DeriveHelpers => {
|
||||
let mut result = Err(Determinacy::Determined);
|
||||
for derive in &parent_scope.derives {
|
||||
let parent_scope = ParentScope { derives: Vec::new(), ..*parent_scope };
|
||||
if let Ok((_, ext)) = self.resolve_macro_to_def(derive, MacroKind::Derive,
|
||||
&parent_scope, force) {
|
||||
if let SyntaxExtension::ProcMacroDerive(_, helper_attrs, _) = &*ext {
|
||||
if helper_attrs.contains(&ident.name) {
|
||||
let binding =
|
||||
(Def::NonMacroAttr(NonMacroAttrKind::DeriveHelper),
|
||||
ty::Visibility::Public, derive.span, Mark::root())
|
||||
.to_name_binding(self.arenas);
|
||||
result = Ok((binding, FromPrelude(false)));
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
result
|
||||
}
|
||||
WhereToResolve::ExternPrelude => {
|
||||
if use_prelude && self.extern_prelude.contains(&ident.name) {
|
||||
if !self.session.features_untracked().extern_prelude &&
|
||||
|
@ -731,7 +752,8 @@ impl<'a, 'cl> Resolver<'a, 'cl> {
|
|||
}
|
||||
WhereToResolve::MacroUsePrelude => WhereToResolve::BuiltinMacros,
|
||||
WhereToResolve::BuiltinMacros => WhereToResolve::BuiltinAttrs,
|
||||
WhereToResolve::BuiltinAttrs => break, // nowhere else to search
|
||||
WhereToResolve::BuiltinAttrs => WhereToResolve::DeriveHelpers,
|
||||
WhereToResolve::DeriveHelpers => break, // nowhere else to search
|
||||
WhereToResolve::ExternPrelude => WhereToResolve::ToolPrelude,
|
||||
WhereToResolve::ToolPrelude => WhereToResolve::StdLibPrelude,
|
||||
WhereToResolve::StdLibPrelude => WhereToResolve::BuiltinTypes,
|
||||
|
@ -753,9 +775,12 @@ impl<'a, 'cl> Resolver<'a, 'cl> {
|
|||
|
||||
if let Some(innermost_result) = innermost_result {
|
||||
// Found another solution, if the first one was "weak", report an error.
|
||||
if result.0.def() != innermost_result.0.def() &&
|
||||
let (def, innermost_def) = (result.0.def(), innermost_result.0.def());
|
||||
if def != innermost_def &&
|
||||
(innermost_result.0.is_glob_import() ||
|
||||
innermost_result.0.may_appear_after(parent_expansion, result.0)) {
|
||||
innermost_result.0.may_appear_after(parent_scope.expansion, result.0) ||
|
||||
innermost_def == Def::NonMacroAttr(NonMacroAttrKind::DeriveHelper) ||
|
||||
def == Def::NonMacroAttr(NonMacroAttrKind::DeriveHelper)) {
|
||||
self.ambiguity_errors.push(AmbiguityError {
|
||||
ident,
|
||||
b1: innermost_result.0,
|
||||
|
@ -797,13 +822,13 @@ impl<'a, 'cl> Resolver<'a, 'cl> {
|
|||
}
|
||||
}
|
||||
|
||||
fn resolve_legacy_scope(&mut self,
|
||||
ident: Ident,
|
||||
kind: Option<MacroKind>,
|
||||
parent_expansion: Mark,
|
||||
parent_legacy_scope: LegacyScope<'a>,
|
||||
record_used: bool)
|
||||
-> Option<&'a NameBinding<'a>> {
|
||||
fn resolve_legacy_scope(
|
||||
&mut self,
|
||||
ident: Ident,
|
||||
kind: Option<MacroKind>,
|
||||
parent_scope: &ParentScope<'a>,
|
||||
record_used: bool,
|
||||
) -> Option<&'a NameBinding<'a>> {
|
||||
if macro_kind_mismatch(ident.name, kind, Some(MacroKind::Bang)) {
|
||||
return None;
|
||||
}
|
||||
|
@ -824,7 +849,7 @@ impl<'a, 'cl> Resolver<'a, 'cl> {
|
|||
let mut innermost_result: Option<&NameBinding> = None;
|
||||
|
||||
// Go through all the scopes and try to resolve the name.
|
||||
let mut where_to_resolve = parent_legacy_scope;
|
||||
let mut where_to_resolve = parent_scope.legacy;
|
||||
loop {
|
||||
let result = match where_to_resolve {
|
||||
LegacyScope::Binding(legacy_binding) if ident == legacy_binding.ident =>
|
||||
|
@ -852,7 +877,7 @@ impl<'a, 'cl> Resolver<'a, 'cl> {
|
|||
if let Some(innermost_result) = innermost_result {
|
||||
// Found another solution, if the first one was "weak", report an error.
|
||||
if result.def() != innermost_result.def() &&
|
||||
innermost_result.may_appear_after(parent_expansion, result) {
|
||||
innermost_result.may_appear_after(parent_scope.expansion, result) {
|
||||
self.ambiguity_errors.push(AmbiguityError {
|
||||
ident,
|
||||
b1: innermost_result,
|
||||
|
@ -889,14 +914,15 @@ impl<'a, 'cl> Resolver<'a, 'cl> {
|
|||
}
|
||||
}
|
||||
|
||||
for &(ident, kind, parent_expansion, parent_legacy_scope, def)
|
||||
in module.legacy_macro_resolutions.borrow().iter() {
|
||||
let legacy_macro_resolutions =
|
||||
mem::replace(&mut *module.legacy_macro_resolutions.borrow_mut(), Vec::new());
|
||||
for (ident, kind, parent_scope, def) in legacy_macro_resolutions {
|
||||
let span = ident.span;
|
||||
let legacy_resolution = self.resolve_legacy_scope(
|
||||
ident, Some(kind), parent_expansion, parent_legacy_scope, true
|
||||
ident, Some(kind), &parent_scope, true
|
||||
);
|
||||
let resolution = self.resolve_lexical_macro_path_segment(
|
||||
ident, MacroNS, Some(kind), parent_expansion, true, true, span
|
||||
ident, MacroNS, Some(kind), &parent_scope, true, true, span
|
||||
);
|
||||
|
||||
let check_consistency = |this: &Self, new_def: Def| {
|
||||
|
@ -932,7 +958,7 @@ impl<'a, 'cl> Resolver<'a, 'cl> {
|
|||
(Some(legacy_binding), Ok((binding, FromPrelude(from_prelude))))
|
||||
if legacy_binding.def() != binding.def_ignoring_ambiguity() &&
|
||||
(!from_prelude ||
|
||||
legacy_binding.may_appear_after(parent_expansion, binding)) => {
|
||||
legacy_binding.may_appear_after(parent_scope.expansion, binding)) => {
|
||||
self.report_ambiguity_error(ident, legacy_binding, binding);
|
||||
},
|
||||
// OK, non-macro-expanded legacy wins over prelude even if defs are different
|
||||
|
@ -953,13 +979,13 @@ impl<'a, 'cl> Resolver<'a, 'cl> {
|
|||
};
|
||||
}
|
||||
|
||||
for &(ident, parent_expansion, parent_legacy_scope)
|
||||
in module.builtin_attrs.borrow().iter() {
|
||||
let builtin_attrs = mem::replace(&mut *module.builtin_attrs.borrow_mut(), Vec::new());
|
||||
for (ident, parent_scope) in builtin_attrs {
|
||||
let resolve_legacy = |this: &mut Self| this.resolve_legacy_scope(
|
||||
ident, Some(MacroKind::Attr), parent_expansion, parent_legacy_scope, true
|
||||
ident, Some(MacroKind::Attr), &parent_scope, true
|
||||
);
|
||||
let resolve_modern = |this: &mut Self| this.resolve_lexical_macro_path_segment(
|
||||
ident, MacroNS, Some(MacroKind::Attr), parent_expansion, true, true, ident.span
|
||||
ident, MacroNS, Some(MacroKind::Attr), &parent_scope, true, true, ident.span
|
||||
).map(|(binding, _)| binding).ok();
|
||||
|
||||
if let Some(binding) = resolve_legacy(self).or_else(|| resolve_modern(self)) {
|
||||
|
|
|
@ -398,12 +398,12 @@ impl<'a, 'tcx, 'rcx, 'cstore> DocFolder for LinkCollector<'a, 'tcx, 'rcx, 'cstor
|
|||
/// Resolve a string as a macro
|
||||
fn macro_resolve(cx: &DocContext, path_str: &str) -> Option<Def> {
|
||||
use syntax::ext::base::{MacroKind, SyntaxExtension};
|
||||
use syntax::ext::hygiene::Mark;
|
||||
let segment = ast::PathSegment::from_ident(Ident::from_str(path_str));
|
||||
let path = ast::Path { segments: vec![segment], span: DUMMY_SP };
|
||||
let mut resolver = cx.resolver.borrow_mut();
|
||||
let mark = Mark::root();
|
||||
if let Ok(def) = resolver.resolve_macro_to_def_inner(&path, MacroKind::Bang, mark, &[], false) {
|
||||
let parent_scope = resolver.dummy_parent_scope();
|
||||
if let Ok(def) = resolver.resolve_macro_to_def_inner(&path, MacroKind::Bang,
|
||||
&parent_scope, false) {
|
||||
if let SyntaxExtension::DeclMacro { .. } = *resolver.get_macro(def) {
|
||||
return Some(def);
|
||||
}
|
||||
|
|
|
@ -730,7 +730,7 @@ pub trait Resolver {
|
|||
fn resolve_macro_invocation(&mut self, invoc: &Invocation, invoc_id: Mark, force: bool)
|
||||
-> Result<Option<Lrc<SyntaxExtension>>, Determinacy>;
|
||||
fn resolve_macro_path(&mut self, path: &ast::Path, kind: MacroKind, invoc_id: Mark,
|
||||
derives_in_scope: &[ast::Path], force: bool)
|
||||
derives_in_scope: Vec<ast::Path>, force: bool)
|
||||
-> Result<Lrc<SyntaxExtension>, Determinacy>;
|
||||
|
||||
fn check_unused_macros(&self);
|
||||
|
@ -768,7 +768,7 @@ impl Resolver for DummyResolver {
|
|||
Err(Determinacy::Determined)
|
||||
}
|
||||
fn resolve_macro_path(&mut self, _path: &ast::Path, _kind: MacroKind, _invoc_id: Mark,
|
||||
_derives_in_scope: &[ast::Path], _force: bool)
|
||||
_derives_in_scope: Vec<ast::Path>, _force: bool)
|
||||
-> Result<Lrc<SyntaxExtension>, Determinacy> {
|
||||
Err(Determinacy::Determined)
|
||||
}
|
||||
|
|
|
@ -384,7 +384,7 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
|
|||
let mark = Mark::fresh(self.cx.current_expansion.mark);
|
||||
derives.push(mark);
|
||||
let item = match self.cx.resolver.resolve_macro_path(
|
||||
path, MacroKind::Derive, Mark::root(), &[], false) {
|
||||
path, MacroKind::Derive, Mark::root(), Vec::new(), false) {
|
||||
Ok(ext) => match *ext {
|
||||
BuiltinDerive(..) => item_with_markers.clone(),
|
||||
_ => item.clone(),
|
||||
|
|
|
@ -0,0 +1,16 @@
|
|||
// no-prefer-dynamic
|
||||
|
||||
#![crate_type = "proc-macro"]
|
||||
|
||||
extern crate proc_macro;
|
||||
use proc_macro::*;
|
||||
|
||||
#[proc_macro_attribute]
|
||||
pub fn my_attr(_: TokenStream, input: TokenStream) -> TokenStream {
|
||||
input
|
||||
}
|
||||
|
||||
#[proc_macro_derive(MyTrait, attributes(my_attr))]
|
||||
pub fn derive(input: TokenStream) -> TokenStream {
|
||||
TokenStream::new()
|
||||
}
|
12
src/test/ui-fulldeps/proc-macro/auxiliary/issue-53481.rs
Normal file
12
src/test/ui-fulldeps/proc-macro/auxiliary/issue-53481.rs
Normal file
|
@ -0,0 +1,12 @@
|
|||
// no-prefer-dynamic
|
||||
|
||||
#![crate_type = "proc-macro"]
|
||||
|
||||
extern crate proc_macro;
|
||||
|
||||
use proc_macro::*;
|
||||
|
||||
#[proc_macro_derive(MyTrait, attributes(my_attr))]
|
||||
pub fn foo(_: TokenStream) -> TokenStream {
|
||||
TokenStream::new()
|
||||
}
|
10
src/test/ui-fulldeps/proc-macro/derive-helper-shadowing.rs
Normal file
10
src/test/ui-fulldeps/proc-macro/derive-helper-shadowing.rs
Normal file
|
@ -0,0 +1,10 @@
|
|||
// aux-build:derive-helper-shadowing.rs
|
||||
|
||||
extern crate derive_helper_shadowing;
|
||||
use derive_helper_shadowing::*;
|
||||
|
||||
#[derive(MyTrait)]
|
||||
#[my_attr] //~ ERROR `my_attr` is ambiguous
|
||||
struct S;
|
||||
|
||||
fn main() {}
|
|
@ -0,0 +1,21 @@
|
|||
error[E0659]: `my_attr` is ambiguous
|
||||
--> $DIR/derive-helper-shadowing.rs:7:3
|
||||
|
|
||||
LL | #[my_attr] //~ ERROR `my_attr` is ambiguous
|
||||
| ^^^^^^^ ambiguous name
|
||||
|
|
||||
note: `my_attr` could refer to the name imported here
|
||||
--> $DIR/derive-helper-shadowing.rs:4:5
|
||||
|
|
||||
LL | use derive_helper_shadowing::*;
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
note: `my_attr` could also refer to the name defined here
|
||||
--> $DIR/derive-helper-shadowing.rs:6:10
|
||||
|
|
||||
LL | #[derive(MyTrait)]
|
||||
| ^^^^^^^
|
||||
= note: consider adding an explicit import of `my_attr` to disambiguate
|
||||
|
||||
error: aborting due to previous error
|
||||
|
||||
For more information about this error, try `rustc --explain E0659`.
|
22
src/test/ui-fulldeps/proc-macro/issue-53481.rs
Normal file
22
src/test/ui-fulldeps/proc-macro/issue-53481.rs
Normal file
|
@ -0,0 +1,22 @@
|
|||
// compile-pass
|
||||
// aux-build:issue-53481.rs
|
||||
|
||||
#[macro_use]
|
||||
extern crate issue_53481;
|
||||
|
||||
mod m1 {
|
||||
use m2::MyTrait;
|
||||
|
||||
#[derive(MyTrait)]
|
||||
struct A {}
|
||||
}
|
||||
|
||||
mod m2 {
|
||||
pub type MyTrait = u8;
|
||||
|
||||
#[derive(MyTrait)]
|
||||
#[my_attr]
|
||||
struct B {}
|
||||
}
|
||||
|
||||
fn main() {}
|
Loading…
Add table
Reference in a new issue