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:
commit
60c846046e
@ -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",
|
||||
|
@ -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",
|
||||
}
|
||||
}
|
||||
|
@ -1012,6 +1012,7 @@ impl_stable_hash_for!(enum hir::def::NonMacroAttrKind {
|
||||
Builtin,
|
||||
Tool,
|
||||
DeriveHelper,
|
||||
LegacyPluginHelper,
|
||||
Custom,
|
||||
});
|
||||
|
||||
|
@ -10,6 +10,7 @@ crate-type = ["dylib"]
|
||||
test = false
|
||||
|
||||
[dependencies]
|
||||
bitflags = "1.0"
|
||||
log = "0.4"
|
||||
syntax = { path = "../libsyntax" }
|
||||
rustc = { path = "../librustc" }
|
||||
|
@ -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 };
|
||||
|
@ -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),
|
||||
|
@ -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);
|
||||
|
@ -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();
|
||||
}
|
||||
|
||||
|
@ -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",
|
||||
|
@ -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),
|
||||
|
@ -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
|
||||
|
@ -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() {}
|
||||
|
@ -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
|
||||
|
||||
|
@ -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
|
||||
|
|
||||
|
Loading…
Reference in New Issue
Block a user