Let macro_use bypass module scope

This commit is contained in:
uHOOCCOOHu 2019-09-05 11:35:13 +08:00
parent a66214b34e
commit 0d23286caf
No known key found for this signature in database
GPG Key ID: CED392DE0C483D00
2 changed files with 52 additions and 35 deletions

View File

@ -166,6 +166,33 @@ where
self.global_macro_scope.insert(name, macro_id);
}
/// Import macros from `#[macro_use] extern crate`.
///
/// They are non-scoped, and will only be inserted into mutable `global_macro_scope`.
fn import_macros_from_extern_crate(&mut self, import: &raw::ImportData) {
log::debug!(
"importing macros from extern crate: {:?} ({:?})",
import,
self.def_map.edition,
);
let res = self.def_map.resolve_name_in_extern_prelude(
&import
.path
.as_ident()
.expect("extern crate should have been desugared to one-element path"),
);
if let Some(ModuleDef::Module(m)) = res.take_types() {
tested_by!(macro_rules_from_other_crates_are_visible_with_macro_use);
let item_map = self.db.crate_def_map(m.krate);
for (name, &macro_id) in &item_map.exported_macros {
self.global_macro_scope.insert(name.clone(), macro_id);
}
}
}
fn resolve_imports(&mut self) -> ReachedFixedPoint {
let mut imports = std::mem::replace(&mut self.unresolved_imports, Vec::new());
let mut resolved = Vec::new();
@ -299,21 +326,6 @@ where
}
}
// `#[macro_use] extern crate` glob imports all macros exported,
// ignoring their scopes
if import.is_extern_crate && import.is_macro_use {
if let Some(ModuleDef::Module(m)) =
def.a().and_then(|item| item.take_types())
{
tested_by!(macro_rules_from_other_crates_are_visible_with_macro_use);
let item_map = self.db.crate_def_map(m.krate);
for (name, &macro_id) in &item_map.exported_macros {
self.define_macro(module_id, name.clone(), macro_id, false);
}
}
}
let resolution = match def {
Either::A(item) => {
Either::A(Resolution { def: item, import: Some(import_id) })
@ -513,11 +525,17 @@ where
for item in items {
match *item {
raw::RawItem::Module(m) => self.collect_module(&self.raw_items[m]),
raw::RawItem::Import(import) => self.def_collector.unresolved_imports.push((
self.module_id,
import,
self.raw_items[import].clone(),
)),
raw::RawItem::Import(import_id) => {
let import = self.raw_items[import_id].clone();
// This should be processed eagerly instead of deferred to resolving.
// Otherwise, since it will only mutate `global_macro_scope`
// without `update` names in `mod`s, unresolved macros cannot be expanded.
if import.is_extern_crate && import.is_macro_use {
self.def_collector.import_macros_from_extern_crate(&import);
}
self.def_collector.unresolved_imports.push((self.module_id, import_id, import));
}
raw::RawItem::Def(def) => self.define_def(&self.raw_items[def]),
raw::RawItem::Macro(mac) => self.collect_macro(&self.raw_items[mac]),
}

View File

@ -147,25 +147,31 @@ fn macro_rules_from_other_crates_are_visible_with_macro_use() {
#[macro_use]
extern crate foo;
structs!(Foo, Bar)
structs!(Foo);
structs_priv!(Bar);
structs_not_exported!(MacroNotResolved1);
crates::structs!(MacroNotResolved2);
mod bar;
//- /bar.rs
use crate::*;
structs!(Baz);
crates::structs!(MacroNotResolved3);
//- /lib.rs
#[macro_export]
macro_rules! structs {
($($i:ident),*) => {
$(struct $i { field: u32 } )*
}
($i:ident) => { struct $i; }
}
macro_rules! structs_not_exported {
($i:ident) => { struct $i; }
}
mod priv_mod {
#[macro_export]
macro_rules! baz {
() => {};
macro_rules! structs_priv {
($i:ident) => { struct $i; }
}
}
",
@ -179,16 +185,9 @@ fn macro_rules_from_other_crates_are_visible_with_macro_use() {
Bar: t v
Foo: t v
bar: t
baz: m
foo: t
structs: m
crate::bar
Bar: t v
Foo: t v
bar: t
baz: m
foo: t
structs: m
Baz: t v
"###);
}