Auto merge of #54336 - petrochenkov:preuni, r=alexcrichton

resolve: Some refactorings in preparation for uniform paths 2.0

The main result is that in-scope resolution performed during macro expansion / import resolution is now consolidated in a single function (`fn early_resolve_ident_in_lexical_scope`), which can now be used for resolving first import segments as well when uniform paths are enabled.

r? @ghost
This commit is contained in:
bors 2018-10-05 12:52:53 +00:00
commit 60c846046e
14 changed files with 276 additions and 417 deletions

View File

@ -2388,6 +2388,7 @@ name = "rustc_resolve"
version = "0.0.0"
dependencies = [
"arena 0.0.0",
"bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)",
"log 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)",
"rustc 0.0.0",
"rustc_data_structures 0.0.0",

View File

@ -36,6 +36,8 @@ pub enum NonMacroAttrKind {
Tool,
/// Single-segment custom attribute registered by a derive macro (`#[serde(default)]`).
DeriveHelper,
/// Single-segment custom attriubte registered by a legacy plugin (`register_attribute`).
LegacyPluginHelper,
/// Single-segment custom attribute not registered in any way (`#[my_attr]`).
Custom,
}
@ -259,6 +261,7 @@ impl NonMacroAttrKind {
NonMacroAttrKind::Builtin => "built-in attribute",
NonMacroAttrKind::Tool => "tool attribute",
NonMacroAttrKind::DeriveHelper => "derive helper attribute",
NonMacroAttrKind::LegacyPluginHelper => "legacy plugin helper attribute",
NonMacroAttrKind::Custom => "custom attribute",
}
}

View File

@ -1012,6 +1012,7 @@ impl_stable_hash_for!(enum hir::def::NonMacroAttrKind {
Builtin,
Tool,
DeriveHelper,
LegacyPluginHelper,
Custom,
});

View File

@ -10,6 +10,7 @@ crate-type = ["dylib"]
test = false
[dependencies]
bitflags = "1.0"
log = "0.4"
syntax = { path = "../libsyntax" }
rustc = { path = "../librustc" }

View File

@ -17,6 +17,8 @@
#![feature(rustc_diagnostic_macros)]
#![feature(slice_sort_by_cached_key)]
#[macro_use]
extern crate bitflags;
#[macro_use]
extern crate log;
#[macro_use]
@ -1012,7 +1014,8 @@ pub struct ModuleData<'a> {
normal_ancestor_id: DefId,
resolutions: RefCell<FxHashMap<(Ident, Namespace), &'a RefCell<NameResolution<'a>>>>,
legacy_macro_resolutions: RefCell<Vec<(Ident, MacroKind, ParentScope<'a>, Option<Def>)>>,
legacy_macro_resolutions: RefCell<Vec<(Ident, MacroKind, ParentScope<'a>,
Option<&'a NameBinding<'a>>)>>,
macro_resolutions: RefCell<Vec<(Box<[Ident]>, Span)>>,
builtin_attrs: RefCell<Vec<(Ident, ParentScope<'a>)>>,
@ -1210,10 +1213,6 @@ impl<'a> NameBinding<'a> {
}
}
fn get_macro<'b: 'a>(&self, resolver: &mut Resolver<'a, 'b>) -> Lrc<SyntaxExtension> {
resolver.get_macro(self.def_ignoring_ambiguity())
}
// We sometimes need to treat variants as `pub` for backwards compatibility
fn pseudo_vis(&self) -> ty::Visibility {
if self.is_variant() && self.def().def_id().is_local() {
@ -3664,8 +3663,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_scope, record_used,
record_used, path_span).map(|(b, _)| b)
self.early_resolve_ident_in_lexical_scope(ident, ns, None, parent_scope,
record_used, record_used, path_span)
} else {
let record_used_id =
if record_used { crate_lint.node_id().or(Some(CRATE_NODE_ID)) } else { None };

View File

@ -11,7 +11,7 @@
use {AmbiguityError, CrateLint, Resolver, ResolutionError, is_known_tool, resolve_error};
use {Module, ModuleKind, NameBinding, NameBindingKind, PathResult, ToNameBinding};
use ModuleOrUniformRoot;
use Namespace::{self, TypeNS, MacroNS};
use Namespace::{self, *};
use build_reduced_graph::{BuildReducedGraphVisitor, IsMacroExport};
use resolve_imports::ImportResolver;
use rustc::hir::def_id::{DefId, CRATE_DEF_INDEX, DefIndex,
@ -22,9 +22,9 @@ use rustc::{ty, lint};
use syntax::ast::{self, Name, Ident};
use syntax::attr;
use syntax::errors::DiagnosticBuilder;
use syntax::ext::base::{self, Determinacy, MultiModifier, MultiDecorator};
use syntax::ext::base::{self, Determinacy};
use syntax::ext::base::{MacroKind, SyntaxExtension, Resolver as SyntaxResolver};
use syntax::ext::expand::{AstFragment, Invocation, InvocationKind, TogetherWith};
use syntax::ext::expand::{AstFragment, Invocation, InvocationKind};
use syntax::ext::hygiene::{self, Mark};
use syntax::ext::tt::macro_rules;
use syntax::feature_gate::{self, feature_err, emit_feature_err, is_builtin_attr_name, GateIssue};
@ -43,9 +43,6 @@ use std::cell::Cell;
use std::mem;
use rustc_data_structures::sync::Lrc;
#[derive(Clone, Copy)]
crate struct FromPrelude(bool);
#[derive(Clone)]
pub struct InvocationData<'a> {
def_index: DefIndex,
@ -245,27 +242,10 @@ impl<'a, 'crateloader: 'a> base::Resolver for Resolver<'a, 'crateloader> {
// Resolves attribute and derive legacy macros from `#![plugin(..)]`.
fn find_legacy_attr_invoc(&mut self, attrs: &mut Vec<ast::Attribute>, allow_derive: bool)
-> Option<ast::Attribute> {
for i in 0..attrs.len() {
let name = attrs[i].name();
if self.session.plugin_attributes.borrow().iter()
.any(|&(ref attr_nm, _)| name == &**attr_nm) {
attr::mark_known(&attrs[i]);
}
match self.builtin_macros.get(&name).cloned() {
Some(binding) => match *binding.get_macro(self) {
MultiModifier(..) | MultiDecorator(..) | SyntaxExtension::AttrProcMacro(..) => {
return Some(attrs.remove(i))
}
_ => {}
},
None => {}
}
if !allow_derive {
return None;
}
if !allow_derive { return None }
// Check for legacy derives
for i in 0..attrs.len() {
let name = attrs[i].name();
@ -333,29 +313,24 @@ impl<'a, 'crateloader: 'a> base::Resolver for Resolver<'a, 'crateloader> {
fn resolve_macro_invocation(&mut self, invoc: &Invocation, invoc_id: Mark, force: bool)
-> Result<Option<Lrc<SyntaxExtension>>, Determinacy> {
let (path, kind, derives_in_scope, together_with) = match invoc.kind {
let (path, kind, derives_in_scope, after_derive) = match invoc.kind {
InvocationKind::Attr { attr: None, .. } =>
return Ok(None),
InvocationKind::Attr { attr: Some(ref attr), ref traits, together_with, .. } =>
(&attr.path, MacroKind::Attr, traits.clone(), together_with),
InvocationKind::Attr { attr: Some(ref attr), ref traits, after_derive, .. } =>
(&attr.path, MacroKind::Attr, traits.clone(), after_derive),
InvocationKind::Bang { ref mac, .. } =>
(&mac.node.path, MacroKind::Bang, Vec::new(), TogetherWith::None),
(&mac.node.path, MacroKind::Bang, Vec::new(), false),
InvocationKind::Derive { ref path, .. } =>
(path, MacroKind::Derive, Vec::new(), TogetherWith::None),
(path, MacroKind::Derive, Vec::new(), false),
};
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 {
match together_with {
TogetherWith::Derive =>
self.session.span_err(invoc.span(),
"macro attributes must be placed before `#[derive]`"),
TogetherWith::TestBench if !self.session.features_untracked().plugin =>
self.session.span_err(invoc.span(),
"macro attributes cannot be used together with `#[test]` or `#[bench]`"),
_ => {}
if after_derive {
self.session.span_err(invoc.span(),
"macro attributes must be placed before `#[derive]`");
}
self.macro_defs.insert(invoc.expansion_data.mark, def_id);
let normal_module_def_id =
@ -520,37 +495,34 @@ impl<'a, 'cl> Resolver<'a, 'cl> {
Err(Determinacy::Determined)
},
};
parent_scope.module.macro_resolutions.borrow_mut()
.push((path.into_boxed_slice(), span));
return def;
}
let result = if let Some(legacy_binding) = self.resolve_legacy_scope(path[0], Some(kind),
parent_scope, false) {
Ok(legacy_binding.def())
def
} else {
match self.resolve_lexical_macro_path_segment(path[0], MacroNS, Some(kind),
parent_scope, false, force, span) {
Ok((binding, _)) => Ok(binding.def_ignoring_ambiguity()),
let binding = self.early_resolve_ident_in_lexical_scope(
path[0], MacroNS, Some(kind), parent_scope, false, force, span
);
match binding {
Ok(..) => {}
Err(Determinacy::Determined) => self.found_unresolved_macro = true,
Err(Determinacy::Undetermined) => return Err(Determinacy::Undetermined),
Err(Determinacy::Determined) => {
self.found_unresolved_macro = true;
Err(Determinacy::Determined)
}
}
};
parent_scope.module.legacy_macro_resolutions.borrow_mut()
.push((path[0], kind, parent_scope.clone(), result.ok()));
parent_scope.module.legacy_macro_resolutions.borrow_mut()
.push((path[0], kind, parent_scope.clone(), binding.ok()));
result
binding.map(|binding| binding.def_ignoring_ambiguity())
}
}
// Resolve the initial segment of a non-global macro path
// (e.g. `foo` in `foo::bar!(); or `foo!();`).
// 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).
crate fn resolve_lexical_macro_path_segment(
// The function is used for resolving initial segments of macro paths (e.g. `foo` in
// `foo::bar!(); or `foo!();`) and can be used for "uniform path" imports in the future.
crate fn early_resolve_ident_in_lexical_scope(
&mut self,
mut ident: Ident,
ns: Namespace,
@ -559,12 +531,12 @@ impl<'a, 'cl> Resolver<'a, 'cl> {
record_used: bool,
force: bool,
path_span: Span,
) -> Result<(&'a NameBinding<'a>, FromPrelude), Determinacy> {
) -> Result<&'a NameBinding<'a>, Determinacy> {
// General principles:
// 1. Not controlled (user-defined) names should have higher priority than controlled names
// built into the language or standard library. This way we can add new names into the
// language or standard library without breaking user code.
// 2. "Closed set" below means new names can appear after the current resolution attempt.
// 2. "Closed set" below means new names cannot appear after the current resolution attempt.
// Places to search (in order of decreasing priority):
// (Type NS)
// 1. FIXME: Ribs (type parameters), there's no necessary infrastructure yet
@ -575,24 +547,58 @@ impl<'a, 'cl> Resolver<'a, 'cl> {
// 4. Tool modules (closed, controlled right now, but not in the future).
// 5. Standard library prelude (de-facto closed, controlled).
// 6. Language prelude (closed, controlled).
// (Value NS)
// 1. FIXME: Ribs (local variables), there's no necessary infrastructure yet
// (open set, not controlled).
// 2. Names in modules (both normal `mod`ules and blocks), loop through hygienic parents
// (open, not controlled).
// 3. Standard library prelude (de-facto closed, controlled).
// (Macro NS)
// 0. Derive helpers (open, not controlled). All ambiguities with other names
// 1-3. Derive helpers (open, not controlled). All ambiguities with other names
// are currently reported as errors. They should be higher in priority than preludes
// and probably 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.
// 1. Names in modules (both normal `mod`ules and blocks), loop through hygienic parents
// (open, not controlled).
// 2. `macro_use` prelude (open, the open part is from macro expansions, not controlled).
// 2a. User-defined prelude from macro-use
// 1-3. `macro_rules` (open, not controlled), loop through legacy scopes. Have higher
// priority than prelude macros, but create ambiguities with macros in modules.
// 1-3. Names in modules (both normal `mod`ules and blocks), loop through hygienic parents
// (open, not controlled). Have higher priority than prelude macros, but create
// ambiguities with `macro_rules`.
// 4. `macro_use` prelude (open, the open part is from macro expansions, not controlled).
// 4a. User-defined prelude from macro-use
// (open, the open part is from macro expansions, not controlled).
// 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).
// 4b. Standard library prelude is currently implemented as `macro-use` (closed, controlled)
// 5. Language prelude: builtin macros (closed, controlled, except for legacy plugins).
// 6. Language prelude: builtin attributes (closed, controlled).
// 4-6. Legacy plugin helpers (open, not controlled). Similar to derive helpers,
// but introduced by legacy plugins using `register_attribute`. Priority is somewhere
// in prelude, not sure where exactly (creates ambiguities with any other prelude names).
enum WhereToResolve<'a> {
DeriveHelpers,
MacroRules(LegacyScope<'a>),
Module(Module<'a>),
MacroUsePrelude,
BuiltinMacros,
BuiltinAttrs,
LegacyPluginHelpers,
ExternPrelude,
ToolPrelude,
StdLibPrelude,
BuiltinTypes,
}
bitflags! {
struct Flags: u8 {
const DERIVE_HELPERS = 1 << 0;
const MACRO_RULES = 1 << 1;
const MODULE = 1 << 2;
const PRELUDE = 1 << 3;
}
}
assert!(ns == TypeNS || ns == MacroNS);
assert!(force || !record_used); // `record_used` implies `force`
ident = ident.modern();
@ -607,60 +613,13 @@ impl<'a, 'cl> Resolver<'a, 'cl> {
// }
// So we have to save the innermost solution and continue searching in outer scopes
// to detect potential ambiguities.
let mut innermost_result: Option<(&NameBinding, FromPrelude)> = None;
enum WhereToResolve<'a> {
Module(Module<'a>),
MacroUsePrelude,
BuiltinMacros,
BuiltinAttrs,
DeriveHelpers,
ExternPrelude,
ToolPrelude,
StdLibPrelude,
BuiltinTypes,
}
let mut innermost_result: Option<(&NameBinding, Flags, /* conflicts with */ Flags)> = None;
// Go through all the scopes and try to resolve the name.
let mut where_to_resolve = WhereToResolve::DeriveHelpers;
let mut use_prelude = !parent_scope.module.no_implicit_prelude;
loop {
let result = match where_to_resolve {
WhereToResolve::Module(module) => {
let orig_current_module = mem::replace(&mut self.current_module, module);
let binding = self.resolve_ident_in_module_unadjusted(
ModuleOrUniformRoot::Module(module),
ident,
ns,
true,
record_used,
path_span,
);
self.current_module = orig_current_module;
binding.map(|binding| (binding, FromPrelude(false)))
}
WhereToResolve::MacroUsePrelude => {
match self.macro_use_prelude.get(&ident.name).cloned() {
Some(binding) => Ok((binding, FromPrelude(true))),
None => Err(Determinacy::Determined),
}
}
WhereToResolve::BuiltinMacros => {
match self.builtin_macros.get(&ident.name).cloned() {
Some(binding) => Ok((binding, FromPrelude(true))),
None => Err(Determinacy::Determined),
}
}
WhereToResolve::BuiltinAttrs => {
if is_builtin_attr_name(ident.name) {
let binding = (Def::NonMacroAttr(NonMacroAttrKind::Builtin),
ty::Visibility::Public, ident.span, Mark::root())
.to_name_binding(self.arenas);
Ok((binding, FromPrelude(true)))
} else {
Err(Determinacy::Determined)
}
}
WhereToResolve::DeriveHelpers => {
let mut result = Err(Determinacy::Determined);
for derive in &parent_scope.derives {
@ -673,7 +632,7 @@ impl<'a, 'cl> Resolver<'a, 'cl> {
(Def::NonMacroAttr(NonMacroAttrKind::DeriveHelper),
ty::Visibility::Public, derive.span, Mark::root())
.to_name_binding(self.arenas);
result = Ok((binding, FromPrelude(false)));
result = Ok((binding, Flags::DERIVE_HELPERS, Flags::all()));
break;
}
}
@ -681,6 +640,57 @@ impl<'a, 'cl> Resolver<'a, 'cl> {
}
result
}
WhereToResolve::MacroRules(legacy_scope) => match legacy_scope {
LegacyScope::Binding(legacy_binding) if ident == legacy_binding.ident =>
Ok((legacy_binding.binding, Flags::MACRO_RULES, Flags::empty())),
_ => Err(Determinacy::Determined),
}
WhereToResolve::Module(module) => {
let orig_current_module = mem::replace(&mut self.current_module, module);
let binding = self.resolve_ident_in_module_unadjusted(
ModuleOrUniformRoot::Module(module),
ident,
ns,
true,
record_used,
path_span,
);
self.current_module = orig_current_module;
binding.map(|binding| (binding, Flags::MODULE, Flags::empty()))
}
WhereToResolve::MacroUsePrelude => {
match self.macro_use_prelude.get(&ident.name).cloned() {
Some(binding) => Ok((binding, Flags::PRELUDE, Flags::empty())),
None => Err(Determinacy::Determined),
}
}
WhereToResolve::BuiltinMacros => {
match self.builtin_macros.get(&ident.name).cloned() {
Some(binding) => Ok((binding, Flags::PRELUDE, Flags::empty())),
None => Err(Determinacy::Determined),
}
}
WhereToResolve::BuiltinAttrs => {
if is_builtin_attr_name(ident.name) {
let binding = (Def::NonMacroAttr(NonMacroAttrKind::Builtin),
ty::Visibility::Public, ident.span, Mark::root())
.to_name_binding(self.arenas);
Ok((binding, Flags::PRELUDE, Flags::empty()))
} else {
Err(Determinacy::Determined)
}
}
WhereToResolve::LegacyPluginHelpers => {
if self.session.plugin_attributes.borrow().iter()
.any(|(name, _)| ident.name == &**name) {
let binding = (Def::NonMacroAttr(NonMacroAttrKind::LegacyPluginHelper),
ty::Visibility::Public, ident.span, Mark::root())
.to_name_binding(self.arenas);
Ok((binding, Flags::PRELUDE, Flags::PRELUDE))
} else {
Err(Determinacy::Determined)
}
}
WhereToResolve::ExternPrelude => {
if use_prelude && self.session.extern_prelude.contains(&ident.name) {
let crate_id =
@ -691,7 +701,7 @@ impl<'a, 'cl> Resolver<'a, 'cl> {
let binding = (crate_root, ty::Visibility::Public,
ident.span, Mark::root()).to_name_binding(self.arenas);
Ok((binding, FromPrelude(true)))
Ok((binding, Flags::PRELUDE, Flags::empty()))
} else {
Err(Determinacy::Determined)
}
@ -700,7 +710,7 @@ impl<'a, 'cl> Resolver<'a, 'cl> {
if use_prelude && is_known_tool(ident.name) {
let binding = (Def::ToolMod, ty::Visibility::Public,
ident.span, Mark::root()).to_name_binding(self.arenas);
Ok((binding, FromPrelude(true)))
Ok((binding, Flags::PRELUDE, Flags::empty()))
} else {
Err(Determinacy::Determined)
}
@ -717,46 +727,60 @@ impl<'a, 'cl> Resolver<'a, 'cl> {
false,
path_span,
) {
result = Ok((binding, FromPrelude(true)));
result = Ok((binding, Flags::PRELUDE, Flags::empty()));
}
}
}
result
}
WhereToResolve::BuiltinTypes => {
if let Some(prim_ty) =
self.primitive_type_table.primitive_types.get(&ident.name).cloned() {
let binding = (Def::PrimTy(prim_ty), ty::Visibility::Public,
ident.span, Mark::root()).to_name_binding(self.arenas);
Ok((binding, FromPrelude(true)))
} else {
Err(Determinacy::Determined)
match self.primitive_type_table.primitive_types.get(&ident.name).cloned() {
Some(prim_ty) => {
let binding = (Def::PrimTy(prim_ty), ty::Visibility::Public,
ident.span, Mark::root()).to_name_binding(self.arenas);
Ok((binding, Flags::PRELUDE, Flags::empty()))
}
None => Err(Determinacy::Determined)
}
}
};
macro_rules! continue_search { () => {
where_to_resolve = match where_to_resolve {
WhereToResolve::DeriveHelpers =>
WhereToResolve::MacroRules(parent_scope.legacy),
WhereToResolve::MacroRules(legacy_scope) => match legacy_scope {
LegacyScope::Binding(binding) =>
WhereToResolve::MacroRules(binding.parent_legacy_scope),
LegacyScope::Invocation(invocation) =>
WhereToResolve::MacroRules(invocation.output_legacy_scope.get()),
LegacyScope::Empty => WhereToResolve::Module(parent_scope.module),
LegacyScope::Uninitialized => unreachable!(),
}
WhereToResolve::Module(module) => {
match self.hygienic_lexical_parent(module, &mut ident.span) {
Some(parent_module) => WhereToResolve::Module(parent_module),
None => {
use_prelude = !module.no_implicit_prelude;
if ns == MacroNS {
WhereToResolve::MacroUsePrelude
} else {
WhereToResolve::ExternPrelude
match ns {
TypeNS => WhereToResolve::ExternPrelude,
ValueNS => WhereToResolve::StdLibPrelude,
MacroNS => WhereToResolve::MacroUsePrelude,
}
}
}
}
WhereToResolve::MacroUsePrelude => WhereToResolve::BuiltinMacros,
WhereToResolve::BuiltinMacros => WhereToResolve::BuiltinAttrs,
WhereToResolve::BuiltinAttrs => break, // nowhere else to search
WhereToResolve::DeriveHelpers => WhereToResolve::Module(parent_scope.module),
WhereToResolve::BuiltinAttrs => WhereToResolve::LegacyPluginHelpers,
WhereToResolve::LegacyPluginHelpers => break, // nowhere else to search
WhereToResolve::ExternPrelude => WhereToResolve::ToolPrelude,
WhereToResolve::ToolPrelude => WhereToResolve::StdLibPrelude,
WhereToResolve::StdLibPrelude => WhereToResolve::BuiltinTypes,
WhereToResolve::StdLibPrelude => match ns {
TypeNS => WhereToResolve::BuiltinTypes,
ValueNS => break, // nowhere else to search
MacroNS => unreachable!(),
}
WhereToResolve::BuiltinTypes => break, // nowhere else to search
};
@ -764,33 +788,36 @@ impl<'a, 'cl> Resolver<'a, 'cl> {
}}
match result {
Ok(result) => {
if sub_namespace_mismatch(kind, result.0.macro_kind()) {
Ok((binding, flags, ambig_flags)) => {
if sub_namespace_mismatch(kind, binding.macro_kind()) {
continue_search!();
}
if !record_used {
return Ok(result);
return Ok(binding);
}
if let Some(innermost_result) = innermost_result {
if let Some((innermost_binding, innermost_flags, innermost_ambig_flags))
= innermost_result {
// Found another solution, if the first one was "weak", report an error.
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_def == Def::NonMacroAttr(NonMacroAttrKind::DeriveHelper) ||
def == Def::NonMacroAttr(NonMacroAttrKind::DeriveHelper)) {
if binding.def() != innermost_binding.def() &&
(innermost_binding.is_glob_import() ||
innermost_binding.may_appear_after(parent_scope.expansion, binding) ||
innermost_flags.intersects(ambig_flags) ||
flags.intersects(innermost_ambig_flags) ||
(innermost_flags.contains(Flags::MACRO_RULES) &&
flags.contains(Flags::MODULE) &&
!self.disambiguate_legacy_vs_modern(innermost_binding, binding))) {
self.ambiguity_errors.push(AmbiguityError {
ident,
b1: innermost_result.0,
b2: result.0,
b1: innermost_binding,
b2: binding,
});
return Ok(innermost_result);
return Ok(innermost_binding);
}
} else {
// Found the first solution.
innermost_result = Some(result);
innermost_result = Some((binding, flags, ambig_flags));
}
continue_search!();
@ -803,8 +830,8 @@ impl<'a, 'cl> Resolver<'a, 'cl> {
}
// The first found solution was the only one, return it.
if let Some(innermost_result) = innermost_result {
return Ok(innermost_result);
if let Some((binding, ..)) = innermost_result {
return Ok(binding);
}
let determinacy = Determinacy::determined(force);
@ -816,92 +843,12 @@ impl<'a, 'cl> Resolver<'a, 'cl> {
let binding = (Def::NonMacroAttr(NonMacroAttrKind::Custom),
ty::Visibility::Public, ident.span, Mark::root())
.to_name_binding(self.arenas);
Ok((binding, FromPrelude(true)))
Ok(binding)
} else {
Err(determinacy)
}
}
fn resolve_legacy_scope(
&mut self,
ident: Ident,
kind: Option<MacroKind>,
parent_scope: &ParentScope<'a>,
record_used: bool,
) -> Option<&'a NameBinding<'a>> {
if sub_namespace_mismatch(kind, Some(MacroKind::Bang)) {
return None;
}
let ident = ident.modern();
// This is *the* result, resolution from the scope closest to the resolved identifier.
// However, sometimes this result is "weak" because it comes from a macro expansion,
// and in this case it cannot shadow names from outer scopes, e.g.
// macro_rules! m { ... } // solution in outer scope
// {
// define_m!(); // generates another `macro_rules! m` - innermost solution
// // weak, cannot shadow the outer `m`, need to report ambiguity error
// m!();
// }
// So we have to save the innermost solution and continue searching in outer scopes
// to detect potential ambiguities.
let mut innermost_result: Option<&NameBinding> = None;
// Go through all the scopes and try to resolve the name.
let mut where_to_resolve = parent_scope.legacy;
loop {
let result = match where_to_resolve {
LegacyScope::Binding(legacy_binding) if ident == legacy_binding.ident =>
Some(legacy_binding.binding),
_ => None,
};
macro_rules! continue_search { () => {
where_to_resolve = match where_to_resolve {
LegacyScope::Empty => break, // nowhere else to search
LegacyScope::Binding(binding) => binding.parent_legacy_scope,
LegacyScope::Invocation(invocation) => invocation.output_legacy_scope.get(),
LegacyScope::Uninitialized => unreachable!(),
};
continue;
}}
match result {
Some(result) => {
if !record_used {
return Some(result);
}
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_scope.expansion, result) {
self.ambiguity_errors.push(AmbiguityError {
ident,
b1: innermost_result,
b2: result,
});
return Some(innermost_result);
}
} else {
// Found the first solution.
innermost_result = Some(result);
}
continue_search!();
}
None => {
continue_search!();
}
}
}
// The first found solution was the only one (or there was no solution at all), return it.
innermost_result
}
pub fn finalize_current_module_macro_resolutions(&mut self) {
let module = self.current_module;
for &(ref path, span) in module.macro_resolutions.borrow().iter() {
@ -916,80 +863,52 @@ impl<'a, 'cl> Resolver<'a, 'cl> {
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_scope, true
for (ident, kind, parent_scope, initial_binding) in legacy_macro_resolutions {
let binding = self.early_resolve_ident_in_lexical_scope(
ident, MacroNS, Some(kind), &parent_scope, true, true, ident.span
);
let resolution = self.resolve_lexical_macro_path_segment(
ident, MacroNS, Some(kind), &parent_scope, true, true, span
);
let check_consistency = |this: &Self, new_def: Def| {
if let Some(def) = def {
if this.ambiguity_errors.is_empty() && new_def != def && new_def != Def::Err {
// 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 span-bug.
span_bug!(span, "inconsistent resolution for a macro");
match binding {
Ok(binding) => {
let def = binding.def_ignoring_ambiguity();
if let Some(initial_binding) = initial_binding {
self.record_use(ident, MacroNS, initial_binding);
let initial_def = initial_binding.def_ignoring_ambiguity();
if self.ambiguity_errors.is_empty() &&
def != initial_def && def != Def::Err {
// 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.
span_bug!(ident.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.
let msg = format!("cannot determine resolution for the {} `{}`",
kind.descr(), ident);
let msg_note = "import resolution is stuck, try simplifying macro imports";
self.session.struct_span_err(ident.span, &msg).note(msg_note).emit();
}
} 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.
let msg =
format!("cannot determine resolution for the {} `{}`", kind.descr(), ident);
let msg_note = "import resolution is stuck, try simplifying macro imports";
this.session.struct_span_err(span, &msg).note(msg_note).emit();
}
};
match (legacy_resolution, resolution) {
(None, Err(_)) => {
assert!(def.is_none());
Err(..) => {
assert!(initial_binding.is_none());
let bang = if kind == MacroKind::Bang { "!" } else { "" };
let msg =
format!("cannot find {} `{}{}` in this scope", kind.descr(), ident, bang);
let mut err = self.session.struct_span_err(span, &msg);
self.suggest_macro_name(&ident.as_str(), kind, &mut err, span);
let mut err = self.session.struct_span_err(ident.span, &msg);
self.suggest_macro_name(&ident.as_str(), kind, &mut err, ident.span);
err.emit();
},
(Some(legacy_binding), Ok((binding, FromPrelude(from_prelude))))
if legacy_binding.def() != binding.def_ignoring_ambiguity() &&
(!from_prelude &&
!self.disambiguate_legacy_vs_modern(legacy_binding, 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
// Also, non-macro-expanded legacy wins over modern from the same module
// Also, legacy and modern can co-exist if their defs are same
(Some(legacy_binding), Ok(_)) |
// OK, unambiguous resolution
(Some(legacy_binding), Err(_)) => {
check_consistency(self, legacy_binding.def());
}
// OK, unambiguous resolution
(None, Ok((binding, FromPrelude(from_prelude)))) => {
check_consistency(self, binding.def_ignoring_ambiguity());
if from_prelude {
self.record_use(ident, MacroNS, binding);
}
}
};
}
}
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_scope, true
);
let resolve_modern = |this: &mut Self| this.resolve_lexical_macro_path_segment(
let binding = self.early_resolve_ident_in_lexical_scope(
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)) {
);
if let Ok(binding) = binding {
if binding.def_ignoring_ambiguity() !=
Def::NonMacroAttr(NonMacroAttrKind::Builtin) {
let builtin_binding = (Def::NonMacroAttr(NonMacroAttrKind::Builtin),

View File

@ -334,7 +334,7 @@ impl<'a, 'crateloader> Resolver<'a, 'crateloader> {
// expansion. With restricted shadowing names from globs and macro expansions cannot
// shadow names from outer scopes, so we can freely fallback from module search to search
// in outer scopes. To continue search in outer scopes we have to lie a bit and return
// `Determined` to `resolve_lexical_macro_path_segment` even if the correct answer
// `Determined` to `early_resolve_ident_in_lexical_scope` even if the correct answer
// for in-module resolution could be `Undetermined`.
if restricted_shadowing {
return Err(Determined);

View File

@ -220,14 +220,6 @@ pub struct Invocation {
pub expansion_data: ExpansionData,
}
// Needed for feature-gating attributes used after derives or together with test/bench
#[derive(Clone, Copy, PartialEq)]
pub enum TogetherWith {
None,
Derive,
TestBench,
}
pub enum InvocationKind {
Bang {
mac: ast::Mac,
@ -238,7 +230,8 @@ pub enum InvocationKind {
attr: Option<ast::Attribute>,
traits: Vec<Path>,
item: Annotatable,
together_with: TogetherWith,
// We temporarily report errors for attribute macros placed after derives
after_derive: bool,
},
Derive {
path: Path,
@ -1084,19 +1077,17 @@ impl<'a, 'b> InvocationCollector<'a, 'b> {
traits: Vec<Path>,
item: Annotatable,
kind: AstFragmentKind,
together_with: TogetherWith)
after_derive: bool)
-> AstFragment {
self.collect(kind, InvocationKind::Attr { attr, traits, item, together_with })
self.collect(kind, InvocationKind::Attr { attr, traits, item, after_derive })
}
fn find_attr_invoc(&self, attrs: &mut Vec<ast::Attribute>, together_with: &mut TogetherWith)
fn find_attr_invoc(&self, attrs: &mut Vec<ast::Attribute>, after_derive: &mut bool)
-> Option<ast::Attribute> {
let attr = attrs.iter()
.position(|a| {
if a.path == "derive" {
*together_with = TogetherWith::Derive
} else if a.path == "rustc_test_marker2" {
*together_with = TogetherWith::TestBench
*after_derive = true;
}
!attr::is_known(a) && !is_builtin_attr(a)
})
@ -1109,19 +1100,15 @@ impl<'a, 'b> InvocationCollector<'a, 'b> {
"non-builtin inner attributes are unstable");
}
}
if together_with == &TogetherWith::None &&
attrs.iter().any(|a| a.path == "rustc_test_marker2") {
*together_with = TogetherWith::TestBench;
}
attr
}
/// If `item` is an attr invocation, remove and return the macro attribute and derive traits.
fn classify_item<T>(&mut self, mut item: T)
-> (Option<ast::Attribute>, Vec<Path>, T, TogetherWith)
-> (Option<ast::Attribute>, Vec<Path>, T, /* after_derive */ bool)
where T: HasAttrs,
{
let (mut attr, mut traits, mut together_with) = (None, Vec::new(), TogetherWith::None);
let (mut attr, mut traits, mut after_derive) = (None, Vec::new(), false);
item = item.map_attrs(|mut attrs| {
if let Some(legacy_attr_invoc) = self.cx.resolver.find_legacy_attr_invoc(&mut attrs,
@ -1130,20 +1117,20 @@ impl<'a, 'b> InvocationCollector<'a, 'b> {
return attrs;
}
attr = self.find_attr_invoc(&mut attrs, &mut together_with);
attr = self.find_attr_invoc(&mut attrs, &mut after_derive);
traits = collect_derives(&mut self.cx, &mut attrs);
attrs
});
(attr, traits, item, together_with)
(attr, traits, item, after_derive)
}
/// Alternative of `classify_item()` that ignores `#[derive]` so invocations fallthrough
/// to the unused-attributes lint (making it an error on statements and expressions
/// is a breaking change)
fn classify_nonitem<T: HasAttrs>(&mut self, mut item: T)
-> (Option<ast::Attribute>, T, TogetherWith) {
let (mut attr, mut together_with) = (None, TogetherWith::None);
-> (Option<ast::Attribute>, T, /* after_derive */ bool) {
let (mut attr, mut after_derive) = (None, false);
item = item.map_attrs(|mut attrs| {
if let Some(legacy_attr_invoc) = self.cx.resolver.find_legacy_attr_invoc(&mut attrs,
@ -1152,11 +1139,11 @@ impl<'a, 'b> InvocationCollector<'a, 'b> {
return attrs;
}
attr = self.find_attr_invoc(&mut attrs, &mut together_with);
attr = self.find_attr_invoc(&mut attrs, &mut after_derive);
attrs
});
(attr, item, together_with)
(attr, item, after_derive)
}
fn configure<T: HasAttrs>(&mut self, node: T) -> Option<T> {
@ -1195,7 +1182,7 @@ impl<'a, 'b> Folder for InvocationCollector<'a, 'b> {
expr.node = self.cfg.configure_expr_kind(expr.node);
// ignore derives so they remain unused
let (attr, expr, together_with) = self.classify_nonitem(expr);
let (attr, expr, after_derive) = self.classify_nonitem(expr);
if attr.is_some() {
// collect the invoc regardless of whether or not attributes are permitted here
@ -1204,7 +1191,7 @@ impl<'a, 'b> Folder for InvocationCollector<'a, 'b> {
// AstFragmentKind::Expr requires the macro to emit an expression
return self.collect_attr(attr, vec![], Annotatable::Expr(P(expr)),
AstFragmentKind::Expr, together_with).make_expr();
AstFragmentKind::Expr, after_derive).make_expr();
}
if let ast::ExprKind::Mac(mac) = expr.node {
@ -1220,13 +1207,13 @@ impl<'a, 'b> Folder for InvocationCollector<'a, 'b> {
expr.node = self.cfg.configure_expr_kind(expr.node);
// ignore derives so they remain unused
let (attr, expr, together_with) = self.classify_nonitem(expr);
let (attr, expr, after_derive) = self.classify_nonitem(expr);
if attr.is_some() {
attr.as_ref().map(|a| self.cfg.maybe_emit_expr_attr_err(a));
return self.collect_attr(attr, vec![], Annotatable::Expr(P(expr)),
AstFragmentKind::OptExpr, together_with).make_opt_expr();
AstFragmentKind::OptExpr, after_derive).make_opt_expr();
}
if let ast::ExprKind::Mac(mac) = expr.node {
@ -1258,18 +1245,18 @@ impl<'a, 'b> Folder for InvocationCollector<'a, 'b> {
// we'll expand attributes on expressions separately
if !stmt.is_expr() {
let (attr, derives, stmt_, together_with) = if stmt.is_item() {
let (attr, derives, stmt_, after_derive) = if stmt.is_item() {
self.classify_item(stmt)
} else {
// ignore derives on non-item statements so it falls through
// to the unused-attributes lint
let (attr, stmt, together_with) = self.classify_nonitem(stmt);
(attr, vec![], stmt, together_with)
let (attr, stmt, after_derive) = self.classify_nonitem(stmt);
(attr, vec![], stmt, after_derive)
};
if attr.is_some() || !derives.is_empty() {
return self.collect_attr(attr, derives, Annotatable::Stmt(P(stmt_)),
AstFragmentKind::Stmts, together_with).make_stmts();
AstFragmentKind::Stmts, after_derive).make_stmts();
}
stmt = stmt_;
@ -1311,10 +1298,10 @@ impl<'a, 'b> Folder for InvocationCollector<'a, 'b> {
fn fold_item(&mut self, item: P<ast::Item>) -> SmallVec<[P<ast::Item>; 1]> {
let item = configure!(self, item);
let (attr, traits, item, together_with) = self.classify_item(item);
let (attr, traits, item, after_derive) = self.classify_item(item);
if attr.is_some() || !traits.is_empty() {
return self.collect_attr(attr, traits, Annotatable::Item(item),
AstFragmentKind::Items, together_with).make_items();
AstFragmentKind::Items, after_derive).make_items();
}
match item.node {
@ -1386,10 +1373,10 @@ impl<'a, 'b> Folder for InvocationCollector<'a, 'b> {
fn fold_trait_item(&mut self, item: ast::TraitItem) -> SmallVec<[ast::TraitItem; 1]> {
let item = configure!(self, item);
let (attr, traits, item, together_with) = self.classify_item(item);
let (attr, traits, item, after_derive) = self.classify_item(item);
if attr.is_some() || !traits.is_empty() {
return self.collect_attr(attr, traits, Annotatable::TraitItem(P(item)),
AstFragmentKind::TraitItems, together_with).make_trait_items()
AstFragmentKind::TraitItems, after_derive).make_trait_items()
}
match item.node {
@ -1405,10 +1392,10 @@ impl<'a, 'b> Folder for InvocationCollector<'a, 'b> {
fn fold_impl_item(&mut self, item: ast::ImplItem) -> SmallVec<[ast::ImplItem; 1]> {
let item = configure!(self, item);
let (attr, traits, item, together_with) = self.classify_item(item);
let (attr, traits, item, after_derive) = self.classify_item(item);
if attr.is_some() || !traits.is_empty() {
return self.collect_attr(attr, traits, Annotatable::ImplItem(P(item)),
AstFragmentKind::ImplItems, together_with).make_impl_items();
AstFragmentKind::ImplItems, after_derive).make_impl_items();
}
match item.node {
@ -1440,11 +1427,11 @@ impl<'a, 'b> Folder for InvocationCollector<'a, 'b> {
fn fold_foreign_item(&mut self, foreign_item: ast::ForeignItem)
-> SmallVec<[ast::ForeignItem; 1]>
{
let (attr, traits, foreign_item, together_with) = self.classify_item(foreign_item);
let (attr, traits, foreign_item, after_derive) = self.classify_item(foreign_item);
if attr.is_some() || !traits.is_empty() {
return self.collect_attr(attr, traits, Annotatable::ForeignItem(P(foreign_item)),
AstFragmentKind::ForeignItems, together_with)
AstFragmentKind::ForeignItems, after_derive)
.make_foreign_items();
}

View File

@ -995,10 +995,6 @@ pub const BUILTIN_ATTRIBUTES: &'static [(&'static str, AttributeType, AttributeG
"the `#[rustc_test_marker]` attribute \
is used internally to track tests",
cfg_fn!(rustc_attrs))),
("rustc_test_marker2", Normal, Gated(Stability::Unstable,
"rustc_attrs",
"temporarily used by rustc to report some errors",
cfg_fn!(rustc_attrs))),
("rustc_transparent_macro", Whitelisted, Gated(Stability::Unstable,
"rustc_attrs",
"used internally for testing macro hygiene",

View File

@ -49,7 +49,7 @@ pub fn expand_test_or_bench(
// If we're not in test configuration, remove the annotated item
if !cx.ecfg.should_test { return vec![]; }
let mut item =
let item =
if let Annotatable::Item(i) = item { i }
else {
cx.parse_sess.span_diagnostic.span_fatal(item.span(),
@ -192,12 +192,6 @@ pub fn expand_test_or_bench(
debug!("Synthetic test item:\n{}\n", pprust::item_to_string(&test_const));
// Temporarily add another marker to the original item for error reporting
let marker2 = cx.attribute(
attr_sp, cx.meta_word(attr_sp, Symbol::intern("rustc_test_marker2"))
);
item.attrs.push(marker2);
vec![
// Access to libtest under a gensymed name
Annotatable::Item(test_extern),

View File

@ -19,8 +19,8 @@
#[macro_use] #[no_link]
extern crate macro_crate_test;
#[derive(PartialEq, Clone, Debug)]
#[rustc_into_multi_foo]
#[derive(PartialEq, Clone, Debug)]
fn foo() -> AnotherFakeTypeThatHadBetterGoAway {}
// Check that the `#[into_multi_foo]`-generated `foo2` is configured away

View File

@ -1,9 +1,5 @@
// aux-build:attr_proc_macro.rs
// compile-flags:--test
#![feature(test)]
extern crate test;
extern crate attr_proc_macro;
use attr_proc_macro::*;
@ -15,18 +11,4 @@ struct Before;
#[attr_proc_macro] //~ ERROR macro attributes must be placed before `#[derive]`
struct After;
#[attr_proc_macro] //~ ERROR macro attributes cannot be used together with `#[test]` or `#[bench]`
#[test]
fn test_before() {}
#[test]
#[attr_proc_macro] //~ ERROR macro attributes cannot be used together with `#[test]` or `#[bench]`
fn test_after() {}
#[attr_proc_macro] //~ ERROR macro attributes cannot be used together with `#[test]` or `#[bench]`
#[bench]
fn bench_before(b: &mut test::Bencher) {}
#[bench]
#[attr_proc_macro] //~ ERROR macro attributes cannot be used together with `#[test]` or `#[bench]`
fn bench_after(b: &mut test::Bencher) {}
fn main() {}

View File

@ -1,32 +1,8 @@
error: macro attributes must be placed before `#[derive]`
--> $DIR/attribute-order-restricted.rs:15:1
--> $DIR/attribute-order-restricted.rs:11:1
|
LL | #[attr_proc_macro] //~ ERROR macro attributes must be placed before `#[derive]`
| ^^^^^^^^^^^^^^^^^^
error: macro attributes cannot be used together with `#[test]` or `#[bench]`
--> $DIR/attribute-order-restricted.rs:18:1
|
LL | #[attr_proc_macro] //~ ERROR macro attributes cannot be used together with `#[test]` or `#[bench]`
| ^^^^^^^^^^^^^^^^^^
error: macro attributes cannot be used together with `#[test]` or `#[bench]`
--> $DIR/attribute-order-restricted.rs:23:1
|
LL | #[attr_proc_macro] //~ ERROR macro attributes cannot be used together with `#[test]` or `#[bench]`
| ^^^^^^^^^^^^^^^^^^
error: macro attributes cannot be used together with `#[test]` or `#[bench]`
--> $DIR/attribute-order-restricted.rs:26:1
|
LL | #[attr_proc_macro] //~ ERROR macro attributes cannot be used together with `#[test]` or `#[bench]`
| ^^^^^^^^^^^^^^^^^^
error: macro attributes cannot be used together with `#[test]` or `#[bench]`
--> $DIR/attribute-order-restricted.rs:31:1
|
LL | #[attr_proc_macro] //~ ERROR macro attributes cannot be used together with `#[test]` or `#[bench]`
| ^^^^^^^^^^^^^^^^^^
error: aborting due to 5 previous errors
error: aborting due to previous error

View File

@ -1,20 +1,3 @@
error[E0659]: `panic` is ambiguous
--> $DIR/shadow_builtin_macros.rs:43:5
|
LL | panic!(); //~ ERROR `panic` is ambiguous
| ^^^^^ ambiguous name
|
note: `panic` could refer to the name defined here
--> $DIR/shadow_builtin_macros.rs:40:9
|
LL | macro_rules! panic { () => {} }
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
LL | } }
LL | m!();
| ----- in this macro invocation
= note: `panic` is also a builtin macro
= note: macro-expanded macros do not shadow
error[E0659]: `panic` is ambiguous
--> $DIR/shadow_builtin_macros.rs:25:14
|
@ -43,6 +26,23 @@ LL | ::two_macros::m!(use foo::panic;);
= note: `panic` is also a builtin macro
= note: macro-expanded macro imports do not shadow
error[E0659]: `panic` is ambiguous
--> $DIR/shadow_builtin_macros.rs:43:5
|
LL | panic!(); //~ ERROR `panic` is ambiguous
| ^^^^^ ambiguous name
|
note: `panic` could refer to the name defined here
--> $DIR/shadow_builtin_macros.rs:40:9
|
LL | macro_rules! panic { () => {} }
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
LL | } }
LL | m!();
| ----- in this macro invocation
= note: `panic` is also a builtin macro
= note: macro-expanded macros do not shadow
error[E0659]: `n` is ambiguous
--> $DIR/shadow_builtin_macros.rs:59:5
|