From 1b6be5a1ca6a699bfaa26947f905efbb665039a5 Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Thu, 13 Sep 2018 01:41:07 +0300 Subject: [PATCH 1/2] resolve: Put different parent scopes into a single structure --- src/librustc_resolve/build_reduced_graph.rs | 13 +- src/librustc_resolve/lib.rs | 21 +-- src/librustc_resolve/macros.rs | 134 +++++++++++------- .../passes/collect_intra_doc_links.rs | 6 +- src/libsyntax/ext/base.rs | 4 +- src/libsyntax/ext/expand.rs | 2 +- 6 files changed, 108 insertions(+), 72 deletions(-) diff --git a/src/librustc_resolve/build_reduced_graph.rs b/src/librustc_resolve/build_reduced_graph.rs index d1a05964c8f64..7d9139df41501 100644 --- a/src/librustc_resolve/build_reduced_graph.rs +++ b/src/librustc_resolve/build_reduced_graph.rs @@ -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); diff --git a/src/librustc_resolve/lib.rs b/src/librustc_resolve/lib.rs index c725d56d0cfdc..93f1c20661ba6 100644 --- a/src/librustc_resolve/lib.rs +++ b/src/librustc_resolve/lib.rs @@ -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>>>, - legacy_macro_resolutions: RefCell, Option)>>, + legacy_macro_resolutions: RefCell, Option)>>, macro_resolutions: RefCell, Span)>>, - builtin_attrs: RefCell)>>, + builtin_attrs: RefCell)>>, // Macro invocations that can expand into items in this module. unresolved_invocations: RefCell>, @@ -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>, path: &[Ident], opt_ns: Option, // `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 }; diff --git a/src/librustc_resolve/macros.rs b/src/librustc_resolve/macros.rs index 7733ce475e339..af3da94ced926 100644 --- a/src/librustc_resolve/macros.rs +++ b/src/librustc_resolve/macros.rs @@ -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, +} + 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, force: bool) -> Result, 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), 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) -> 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), 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 { + pub fn resolve_macro_to_def_inner( + &mut self, + path: &ast::Path, + kind: MacroKind, + parent_scope: &ParentScope<'a>, + force: bool, + ) -> Result { 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,8 +529,8 @@ 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; @@ -521,9 +548,9 @@ impl<'a, 'cl> Resolver<'a, 'cl> { 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 { + for derive in &parent_scope.derives { + match self.resolve_macro_to_def(derive, MacroKind::Derive, parent_scope, force) { + Ok((_, ext)) => if let SyntaxExtension::ProcMacroDerive(_, inert_attrs, _) = &*ext { if inert_attrs.contains(&path[0].name) { convert_to_derive_helper = ConvertToDeriveHelper::Yes; break @@ -551,7 +578,7 @@ impl<'a, 'cl> Resolver<'a, 'cl> { mut ident: Ident, ns: Namespace, kind: Option, - parent_expansion: Mark, + parent_scope: &ParentScope<'a>, record_used: bool, force: bool, path_span: Span, @@ -610,8 +637,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) => { @@ -755,7 +782,7 @@ impl<'a, 'cl> Resolver<'a, 'cl> { // Found another solution, if the first one was "weak", report an error. if result.0.def() != innermost_result.0.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)) { self.ambiguity_errors.push(AmbiguityError { ident, b1: innermost_result.0, @@ -797,13 +824,13 @@ impl<'a, 'cl> Resolver<'a, 'cl> { } } - fn resolve_legacy_scope(&mut self, - ident: Ident, - kind: Option, - 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, + 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 +851,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 +879,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 +916,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 +960,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 +981,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)) { diff --git a/src/librustdoc/passes/collect_intra_doc_links.rs b/src/librustdoc/passes/collect_intra_doc_links.rs index cced30d1a0c20..181fe379248ce 100644 --- a/src/librustdoc/passes/collect_intra_doc_links.rs +++ b/src/librustdoc/passes/collect_intra_doc_links.rs @@ -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 { 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); } diff --git a/src/libsyntax/ext/base.rs b/src/libsyntax/ext/base.rs index 07c3e578e5b04..e42624bf41f0a 100644 --- a/src/libsyntax/ext/base.rs +++ b/src/libsyntax/ext/base.rs @@ -730,7 +730,7 @@ pub trait Resolver { fn resolve_macro_invocation(&mut self, invoc: &Invocation, invoc_id: Mark, force: bool) -> Result>, 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, force: bool) -> Result, 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, _force: bool) -> Result, Determinacy> { Err(Determinacy::Determined) } diff --git a/src/libsyntax/ext/expand.rs b/src/libsyntax/ext/expand.rs index 7b4e1814a33d7..40903e8ad6cb7 100644 --- a/src/libsyntax/ext/expand.rs +++ b/src/libsyntax/ext/expand.rs @@ -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(), From 2b3e98f4e389ddec4f4ebea4b500cffd73f4928a Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Thu, 13 Sep 2018 05:11:13 +0300 Subject: [PATCH 2/2] resolve: Future proof derive helper attributes --- src/librustc_resolve/macros.rs | 74 +++++++++---------- .../auxiliary/derive-helper-shadowing.rs | 16 ++++ .../proc-macro/auxiliary/issue-53481.rs | 12 +++ .../proc-macro/derive-helper-shadowing.rs | 10 +++ .../proc-macro/derive-helper-shadowing.stderr | 21 ++++++ .../ui-fulldeps/proc-macro/issue-53481.rs | 22 ++++++ 6 files changed, 117 insertions(+), 38 deletions(-) create mode 100644 src/test/ui-fulldeps/proc-macro/auxiliary/derive-helper-shadowing.rs create mode 100644 src/test/ui-fulldeps/proc-macro/auxiliary/issue-53481.rs create mode 100644 src/test/ui-fulldeps/proc-macro/derive-helper-shadowing.rs create mode 100644 src/test/ui-fulldeps/proc-macro/derive-helper-shadowing.stderr create mode 100644 src/test/ui-fulldeps/proc-macro/issue-53481.rs diff --git a/src/librustc_resolve/macros.rs b/src/librustc_resolve/macros.rs index af3da94ced926..f687e022a412c 100644 --- a/src/librustc_resolve/macros.rs +++ b/src/librustc_resolve/macros.rs @@ -532,41 +532,7 @@ impl<'a, 'cl> Resolver<'a, 'cl> { 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 &parent_scope.derives { - match self.resolve_macro_to_def(derive, MacroKind::Derive, parent_scope, force) { - Ok((_, ext)) => if let SyntaxExtension::ProcMacroDerive(_, 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 @@ -607,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` @@ -630,6 +603,7 @@ impl<'a, 'cl> Resolver<'a, 'cl> { MacroUsePrelude, BuiltinMacros, BuiltinAttrs, + DeriveHelpers, ExternPrelude, ToolPrelude, StdLibPrelude, @@ -679,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 && @@ -758,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, @@ -780,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_scope.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, diff --git a/src/test/ui-fulldeps/proc-macro/auxiliary/derive-helper-shadowing.rs b/src/test/ui-fulldeps/proc-macro/auxiliary/derive-helper-shadowing.rs new file mode 100644 index 0000000000000..0fd8aa5638a50 --- /dev/null +++ b/src/test/ui-fulldeps/proc-macro/auxiliary/derive-helper-shadowing.rs @@ -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() +} diff --git a/src/test/ui-fulldeps/proc-macro/auxiliary/issue-53481.rs b/src/test/ui-fulldeps/proc-macro/auxiliary/issue-53481.rs new file mode 100644 index 0000000000000..9554cdde4907e --- /dev/null +++ b/src/test/ui-fulldeps/proc-macro/auxiliary/issue-53481.rs @@ -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() +} diff --git a/src/test/ui-fulldeps/proc-macro/derive-helper-shadowing.rs b/src/test/ui-fulldeps/proc-macro/derive-helper-shadowing.rs new file mode 100644 index 0000000000000..c2357d501ee44 --- /dev/null +++ b/src/test/ui-fulldeps/proc-macro/derive-helper-shadowing.rs @@ -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() {} diff --git a/src/test/ui-fulldeps/proc-macro/derive-helper-shadowing.stderr b/src/test/ui-fulldeps/proc-macro/derive-helper-shadowing.stderr new file mode 100644 index 0000000000000..d597b577bb790 --- /dev/null +++ b/src/test/ui-fulldeps/proc-macro/derive-helper-shadowing.stderr @@ -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`. diff --git a/src/test/ui-fulldeps/proc-macro/issue-53481.rs b/src/test/ui-fulldeps/proc-macro/issue-53481.rs new file mode 100644 index 0000000000000..479fd1db630a3 --- /dev/null +++ b/src/test/ui-fulldeps/proc-macro/issue-53481.rs @@ -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() {}