Skip to content

Commit

Permalink
Auto merge of #52234 - petrochenkov:macuse2, r=<try>
Browse files Browse the repository at this point in the history
[Experiment] resolve: Modularize crate-local `#[macro_export] macro_rules`

Based on #50911, cc #50911 (comment)

`#[macro_export] macro_rules` items are collected from the whole crate and are planted into the root module as items, so the external view of the crate is symmetric with its internal view and something like `$crate::my_macro` where `my_macro` is `#[macro_export] macro_rules` works both locally and from other crates.
  • Loading branch information
bors committed Jul 10, 2018
2 parents e5f6498 + ee16ce1 commit bcc0707
Show file tree
Hide file tree
Showing 59 changed files with 461 additions and 322 deletions.
3 changes: 1 addition & 2 deletions src/doc/unstable-book/src/language-features/proc-macro.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,7 @@ The two new procedural macro kinds are:
* Attribute-like procedural macros which can be applied to any item which built-in attributes can
be applied to, and which can take arguments in their invocation as well.

Additionally, this feature flag implicitly enables the [`use_extern_macros`](language-features/use-extern-macros.html) feature,
which allows macros to be imported like any other item with `use` statements, as compared to
Procedural macros can be imported like any other item with `use` statements, as compared to
applying `#[macro_use]` to an `extern crate` declaration. It is important to note that procedural macros may
**only** be imported in this manner, and will throw an error otherwise.

Expand Down
27 changes: 17 additions & 10 deletions src/librustc_resolve/build_reduced_graph.rs
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@ impl<'a> ToNameBinding<'a> for (Module<'a>, ty::Visibility, Span, Mark) {
vis: self.1,
span: self.2,
expansion: self.3,
is_macro_export: false,
})
}
}
Expand All @@ -63,6 +64,19 @@ impl<'a> ToNameBinding<'a> for (Def, ty::Visibility, Span, Mark) {
vis: self.1,
span: self.2,
expansion: self.3,
is_macro_export: false,
})
}
}

impl<'a> ToNameBinding<'a> for (Def, ty::Visibility, Span, Mark, bool) {
fn to_name_binding(self, arenas: &'a ResolverArenas<'a>) -> &'a NameBinding<'a> {
arenas.alloc_name_binding(NameBinding {
kind: NameBindingKind::Def(self.0),
vis: self.1,
span: self.2,
expansion: self.3,
is_macro_export: self.4,
})
}
}
Expand Down Expand Up @@ -641,19 +655,12 @@ impl<'a> Resolver<'a> {
-> bool {
let allow_shadowing = expansion == Mark::root();
let legacy_imports = self.legacy_macro_imports(&item.attrs);
let mut used = legacy_imports != LegacyMacroImports::default();
let used = legacy_imports != LegacyMacroImports::default();

// `#[macro_use]` is only allowed at the crate root.
if self.current_module.parent.is_some() && used {
span_err!(self.session, item.span, E0468,
"an `extern crate` loading macros must be at the crate root");
} else if !self.use_extern_macros && !used &&
self.cstore.dep_kind_untracked(module.def_id().unwrap().krate)
.macros_only() {
let msg = "proc macro crates and `#[no_link]` crates have no effect without \
`#[macro_use]`";
self.session.span_warn(item.span, msg);
used = true; // Avoid the normal unused extern crate warning
}

let (graph_root, arenas) = (self.graph_root, self.arenas);
Expand Down Expand Up @@ -681,8 +688,7 @@ impl<'a> Resolver<'a> {
} else {
for (name, span) in legacy_imports.imports {
let ident = Ident::with_empty_ctxt(name);
let result = self.resolve_ident_in_module(module, ident, MacroNS,
false, false, span);
let result = self.resolve_ident_in_module(module, ident, MacroNS, false, span);
if let Ok(binding) = result {
let directive = macro_use_directive(span);
self.potentially_unused_imports.push(directive);
Expand Down Expand Up @@ -750,6 +756,7 @@ impl<'a, 'b> BuildReducedGraphVisitor<'a, 'b> {
fn visit_invoc(&mut self, id: ast::NodeId) -> &'b InvocationData<'b> {
let mark = id.placeholder_to_mark();
self.resolver.current_module.unresolved_invocations.borrow_mut().insert(mark);
self.resolver.unresolved_invocations_macro_export.insert(mark);
let invocation = self.resolver.invocations[&mark];
invocation.module.set(self.resolver.current_module);
invocation.legacy_scope.set(self.legacy_scope);
Expand Down
45 changes: 24 additions & 21 deletions src/librustc_resolve/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1100,6 +1100,7 @@ impl<'a> fmt::Debug for ModuleData<'a> {
pub struct NameBinding<'a> {
kind: NameBindingKind<'a>,
expansion: Mark,
is_macro_export: bool,
span: Span,
vis: ty::Visibility,
}
Expand Down Expand Up @@ -1141,12 +1142,20 @@ struct UseError<'a> {
better: bool,
}

#[derive(Clone, Copy, Debug)]
enum AmbiguityErrorKind {
RecordUse,
ResolveLexical,
ResolveInModule,
}

struct AmbiguityError<'a> {
span: Span,
name: Name,
lexical: bool,
b1: &'a NameBinding<'a>,
b2: &'a NameBinding<'a>,
kind: AmbiguityErrorKind,
}

impl<'a> NameBinding<'a> {
Expand Down Expand Up @@ -1380,13 +1389,10 @@ pub struct Resolver<'a> {
/// `use` injections for proc macros wrongly imported with #[macro_use]
proc_mac_errors: Vec<macros::ProcMacError>,

gated_errors: FxHashSet<Span>,
disallowed_shadowing: Vec<&'a LegacyBinding<'a>>,

arenas: &'a ResolverArenas<'a>,
dummy_binding: &'a NameBinding<'a>,
/// true if `#![feature(use_extern_macros)]`
use_extern_macros: bool,

crate_loader: &'a mut CrateLoader,
macro_names: FxHashSet<Ident>,
Expand All @@ -1396,7 +1402,6 @@ pub struct Resolver<'a> {
macro_map: FxHashMap<DefId, Lrc<SyntaxExtension>>,
macro_defs: FxHashMap<Mark, DefId>,
local_macro_def_scopes: FxHashMap<NodeId, Module<'a>>,
macro_exports: Vec<Export>,
pub whitelisted_legacy_custom_derives: Vec<Name>,
pub found_unresolved_macro: bool,

Expand Down Expand Up @@ -1429,6 +1434,9 @@ pub struct Resolver<'a> {

/// Only supposed to be used by rustdoc, otherwise should be false.
pub ignore_extern_prelude_feature: bool,

/// Macro invocations in the whole crate that can expand into a `#[macro_export] macro_rules`.
unresolved_invocations_macro_export: FxHashSet<Mark>,
}

/// Nothing really interesting here, it just provides memory for the rest of the crate.
Expand Down Expand Up @@ -1698,7 +1706,6 @@ impl<'a> Resolver<'a> {
ambiguity_errors: Vec::new(),
use_injections: Vec::new(),
proc_mac_errors: Vec::new(),
gated_errors: FxHashSet(),
disallowed_shadowing: Vec::new(),

arenas,
Expand All @@ -1707,19 +1714,15 @@ impl<'a> Resolver<'a> {
expansion: Mark::root(),
span: DUMMY_SP,
vis: ty::Visibility::Public,
is_macro_export: false,
}),

// The `proc_macro` and `decl_macro` features imply `use_extern_macros`
use_extern_macros:
features.use_extern_macros || features.proc_macro || features.decl_macro,

crate_loader,
macro_names: FxHashSet(),
global_macros: FxHashMap(),
all_macros: FxHashMap(),
lexical_macro_resolutions: Vec::new(),
macro_map: FxHashMap(),
macro_exports: Vec::new(),
invocations,
macro_defs,
local_macro_def_scopes: FxHashMap(),
Expand All @@ -1734,6 +1737,7 @@ impl<'a> Resolver<'a> {
current_type_ascription: Vec::new(),
injected_crate: None,
ignore_extern_prelude_feature: false,
unresolved_invocations_macro_export: FxHashSet(),
}
}

Expand All @@ -1753,9 +1757,7 @@ impl<'a> Resolver<'a> {
fn per_ns<F: FnMut(&mut Self, Namespace)>(&mut self, mut f: F) {
f(self, TypeNS);
f(self, ValueNS);
if self.use_extern_macros {
f(self, MacroNS);
}
f(self, MacroNS);
}

fn macro_def(&self, mut ctxt: SyntaxContext) -> DefId {
Expand Down Expand Up @@ -1807,6 +1809,7 @@ impl<'a> Resolver<'a> {
NameBindingKind::Ambiguity { b1, b2 } => {
self.ambiguity_errors.push(AmbiguityError {
span, name: ident.name, lexical: false, b1, b2,
kind: AmbiguityErrorKind::RecordUse
});
true
}
Expand Down Expand Up @@ -1967,7 +1970,6 @@ impl<'a> Resolver<'a> {
module: Module<'a>,
mut ident: Ident,
ns: Namespace,
ignore_unresolved_invocations: bool,
record_used: bool,
span: Span)
-> Result<&'a NameBinding<'a>, Determinacy> {
Expand All @@ -1977,7 +1979,7 @@ impl<'a> Resolver<'a> {
self.current_module = self.macro_def_scope(def);
}
let result = self.resolve_ident_in_module_unadjusted(
module, ident, ns, ignore_unresolved_invocations, record_used, span,
module, ident, ns, false, record_used, span,
);
self.current_module = orig_current_module;
result
Expand Down Expand Up @@ -2470,7 +2472,7 @@ impl<'a> Resolver<'a> {
// If there is a TraitRef in scope for an impl, then the method must be in the
// trait.
if let Some((module, _)) = self.current_trait_ref {
if self.resolve_ident_in_module(module, ident, ns, false, false, span).is_err() {
if self.resolve_ident_in_module(module, ident, ns, false, span).is_err() {
let path = &self.current_trait_ref.as_ref().unwrap().1.path;
resolve_error(self, span, err(ident.name, &path_names_to_string(path)));
}
Expand Down Expand Up @@ -3420,7 +3422,7 @@ impl<'a> Resolver<'a> {
}

let binding = if let Some(module) = module {
self.resolve_ident_in_module(module, ident, ns, false, record_used, path_span)
self.resolve_ident_in_module(module, ident, ns, record_used, path_span)
} else if opt_ns == Some(MacroNS) {
self.resolve_lexical_macro_path_segment(ident, ns, record_used, path_span)
.map(MacroBinding::binding)
Expand Down Expand Up @@ -3714,7 +3716,7 @@ impl<'a> Resolver<'a> {
// Look for associated items in the current trait.
if let Some((module, _)) = self.current_trait_ref {
if let Ok(binding) =
self.resolve_ident_in_module(module, ident, ns, false, false, module.span) {
self.resolve_ident_in_module(module, ident, ns, false, module.span) {
let def = binding.def();
if filter_fn(def) {
return Some(if self.has_self.contains(&def.def_id()) {
Expand Down Expand Up @@ -4027,7 +4029,7 @@ impl<'a> Resolver<'a> {
let mut found_traits = Vec::new();
// Look for the current trait.
if let Some((module, _)) = self.current_trait_ref {
if self.resolve_ident_in_module(module, ident, ns, false, false, module.span).is_ok() {
if self.resolve_ident_in_module(module, ident, ns, false, module.span).is_ok() {
let def_id = module.def_id().unwrap();
found_traits.push(TraitCandidate { def_id: def_id, import_id: None });
}
Expand Down Expand Up @@ -4300,7 +4302,7 @@ impl<'a> Resolver<'a> {
self.report_proc_macro_import(krate);
let mut reported_spans = FxHashSet();

for &AmbiguityError { span, name, b1, b2, lexical } in &self.ambiguity_errors {
for &AmbiguityError { span, name, b1, b2, lexical, kind } in &self.ambiguity_errors {
if !reported_spans.insert(span) { continue }
let participle = |binding: &NameBinding| {
if binding.is_import() { "imported" } else { "defined" }
Expand All @@ -4317,7 +4319,8 @@ impl<'a> Resolver<'a> {
if b1.is_import() { "imports" } else { "items" })
};

let mut err = struct_span_err!(self.session, span, E0659, "`{}` is ambiguous", name);
let mut err = struct_span_err!(self.session, span, E0659,
"`{}` is ambiguous {:?}", name, kind);
err.span_note(b1.span, &msg1);
match b2.def() {
Def::Macro(..) if b2.span.is_dummy() =>
Expand Down
Loading

0 comments on commit bcc0707

Please sign in to comment.