Skip to content

Commit d493c1b

Browse files
Lift #[macro_export] macros to top level in HIR
1 parent 0f5e7cd commit d493c1b

File tree

3 files changed

+162
-81
lines changed

3 files changed

+162
-81
lines changed

compiler/rustc_ast_lowering/src/item.rs

Lines changed: 67 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ use rustc_data_structures::fx::FxHashSet;
1010
use rustc_errors::struct_span_err;
1111
use rustc_hir as hir;
1212
use rustc_hir::def::{DefKind, Res};
13-
use rustc_hir::def_id::LocalDefId;
13+
use rustc_hir::def_id::{LocalDefId, CRATE_DEF_ID};
1414
use rustc_span::source_map::{respan, DesugaringKind};
1515
use rustc_span::symbol::{kw, sym, Ident};
1616
use rustc_span::Span;
@@ -26,44 +26,44 @@ pub(super) struct ItemLowerer<'a, 'lowering, 'hir> {
2626
}
2727

2828
impl ItemLowerer<'_, '_, '_> {
29-
fn with_trait_impl_ref(&mut self, impl_ref: &Option<TraitRef>, f: impl FnOnce(&mut Self)) {
29+
fn with_trait_impl_ref<T>(
30+
&mut self,
31+
impl_ref: &Option<TraitRef>,
32+
f: impl FnOnce(&mut Self) -> T,
33+
) -> T {
3034
let old = self.lctx.is_in_trait_impl;
3135
self.lctx.is_in_trait_impl = impl_ref.is_some();
32-
f(self);
36+
let ret = f(self);
3337
self.lctx.is_in_trait_impl = old;
38+
ret
3439
}
3540
}
3641

3742
impl<'a> Visitor<'a> for ItemLowerer<'a, '_, '_> {
3843
fn visit_item(&mut self, item: &'a Item) {
39-
let mut item_hir_id = None;
40-
self.lctx.with_hir_id_owner(item.id, |lctx| {
41-
lctx.without_in_scope_lifetime_defs(|lctx| {
42-
if let Some(hir_item) = lctx.lower_item(item) {
43-
let id = lctx.insert_item(hir_item);
44-
item_hir_id = Some(id);
45-
}
46-
})
44+
let hir_item = self.lctx.with_hir_id_owner(item.id, |lctx| {
45+
lctx.without_in_scope_lifetime_defs(|lctx| lctx.lower_item(item))
4746
});
48-
49-
if let Some(hir_id) = item_hir_id {
50-
self.lctx.with_parent_item_lifetime_defs(hir_id, |this| {
51-
let this = &mut ItemLowerer { lctx: this };
52-
match item.kind {
53-
ItemKind::Mod(..) => {
54-
let def_id = this.lctx.lower_node_id(item.id).expect_owner();
55-
let old_current_module =
56-
mem::replace(&mut this.lctx.current_module, def_id);
57-
visit::walk_item(this, item);
58-
this.lctx.current_module = old_current_module;
59-
}
60-
ItemKind::Impl(box ImplKind { ref of_trait, .. }) => {
61-
this.with_trait_impl_ref(of_trait, |this| visit::walk_item(this, item));
62-
}
63-
_ => visit::walk_item(this, item),
47+
let force_top_level = self.lctx.check_force_top_level(item);
48+
let hir_id = self.lctx.insert_item(hir_item, force_top_level);
49+
50+
let was_at_top_level = mem::replace(&mut self.lctx.is_at_top_level, false);
51+
self.lctx.with_parent_item_lifetime_defs(hir_id, |this| {
52+
let this = &mut ItemLowerer { lctx: this };
53+
match item.kind {
54+
ItemKind::Mod(..) => {
55+
let def_id = this.lctx.lower_node_id(item.id).expect_owner();
56+
let old_current_module = mem::replace(&mut this.lctx.current_module, def_id);
57+
visit::walk_item(this, item);
58+
this.lctx.current_module = old_current_module;
6459
}
65-
});
66-
}
60+
ItemKind::Impl(box ImplKind { ref of_trait, .. }) => {
61+
this.with_trait_impl_ref(of_trait, |this| visit::walk_item(this, item));
62+
}
63+
_ => visit::walk_item(this, item),
64+
}
65+
});
66+
self.lctx.is_at_top_level = was_at_top_level;
6767
}
6868

6969
fn visit_fn(&mut self, fk: FnKind<'a>, sp: Span, _: NodeId) {
@@ -113,7 +113,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
113113
fn with_parent_item_lifetime_defs<T>(
114114
&mut self,
115115
parent_hir_id: hir::ItemId,
116-
f: impl FnOnce(&mut LoweringContext<'_, '_>) -> T,
116+
f: impl FnOnce(&mut Self) -> T,
117117
) -> T {
118118
let old_len = self.in_scope_lifetimes.len();
119119

@@ -137,10 +137,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
137137
// Clears (and restores) the `in_scope_lifetimes` field. Used when
138138
// visiting nested items, which never inherit in-scope lifetimes
139139
// from their surrounding environment.
140-
fn without_in_scope_lifetime_defs<T>(
141-
&mut self,
142-
f: impl FnOnce(&mut LoweringContext<'_, '_>) -> T,
143-
) -> T {
140+
fn without_in_scope_lifetime_defs<T>(&mut self, f: impl FnOnce(&mut Self) -> T) -> T {
144141
let old_in_scope_lifetimes = mem::replace(&mut self.in_scope_lifetimes, vec![]);
145142

146143
// this vector is only used when walking over impl headers,
@@ -157,10 +154,23 @@ impl<'hir> LoweringContext<'_, 'hir> {
157154
}
158155

159156
pub(super) fn lower_mod(&mut self, items: &[P<Item>], inner: Span) -> hir::Mod<'hir> {
160-
hir::Mod {
161-
inner,
162-
item_ids: self.arena.alloc_from_iter(items.iter().flat_map(|x| self.lower_item_id(x))),
157+
let mut items: Vec<_> = items
158+
.iter()
159+
.filter_map(|x| {
160+
if self.check_force_top_level(&x) { None } else { Some(self.lower_item_id(&x)) }
161+
})
162+
.flatten()
163+
.collect();
164+
165+
if self.current_hir_id_owner.0 == CRATE_DEF_ID {
166+
let top_level_items = self.top_level_items.clone();
167+
for item in top_level_items {
168+
let id = self.lower_item_id(&item)[0];
169+
items.push(id);
170+
}
163171
}
172+
173+
hir::Mod { inner, item_ids: self.arena.alloc_from_iter(items.into_iter()) }
164174
}
165175

166176
pub(super) fn lower_item_id(&mut self, i: &Item) -> SmallVec<[hir::ItemId; 1]> {
@@ -208,13 +218,15 @@ impl<'hir> LoweringContext<'_, 'hir> {
208218
}
209219
}
210220

211-
pub fn lower_item(&mut self, i: &Item) -> Option<hir::Item<'hir>> {
221+
pub fn lower_item(&mut self, i: &Item) -> hir::Item<'hir> {
222+
let was_at_top_level = mem::replace(&mut self.is_at_top_level, false);
212223
let mut ident = i.ident;
213224
let mut vis = self.lower_visibility(&i.vis, None);
214225
let hir_id = self.lower_node_id(i.id);
215226
let attrs = self.lower_attrs(hir_id, &i.attrs);
216227
let kind = self.lower_item_kind(i.span, i.id, hir_id, &mut ident, attrs, &mut vis, &i.kind);
217-
Some(hir::Item { def_id: hir_id.expect_owner(), ident, kind, vis, span: i.span })
228+
self.is_at_top_level = was_at_top_level;
229+
hir::Item { def_id: hir_id.expect_owner(), ident, kind, vis, span: i.span }
218230
}
219231

220232
fn lower_item_kind(
@@ -285,7 +297,8 @@ impl<'hir> LoweringContext<'_, 'hir> {
285297
}
286298
ItemKind::Mod(_, ref mod_kind) => match mod_kind {
287299
ModKind::Loaded(items, _, inner_span) => {
288-
hir::ItemKind::Mod(self.lower_mod(items, *inner_span))
300+
let module = self.lower_mod(items, *inner_span);
301+
hir::ItemKind::Mod(module)
289302
}
290303
ModKind::Unloaded => panic!("`mod` items should have been loaded by now"),
291304
},
@@ -537,13 +550,10 @@ impl<'hir> LoweringContext<'_, 'hir> {
537550
this.attrs.insert(new_id, attrs);
538551
}
539552

540-
this.insert_item(hir::Item {
541-
def_id: new_id.expect_owner(),
542-
ident,
543-
kind,
544-
vis,
545-
span,
546-
});
553+
this.insert_item(
554+
hir::Item { def_id: new_id.expect_owner(), ident, kind, vis, span },
555+
false,
556+
);
547557
});
548558
}
549559

@@ -611,13 +621,16 @@ impl<'hir> LoweringContext<'_, 'hir> {
611621
this.attrs.insert(new_hir_id, attrs);
612622
}
613623

614-
this.insert_item(hir::Item {
615-
def_id: new_hir_id.expect_owner(),
616-
ident,
617-
kind,
618-
vis,
619-
span: use_tree.span,
620-
});
624+
this.insert_item(
625+
hir::Item {
626+
def_id: new_hir_id.expect_owner(),
627+
ident,
628+
kind,
629+
vis,
630+
span: use_tree.span,
631+
},
632+
false,
633+
);
621634
});
622635
}
623636

compiler/rustc_ast_lowering/src/lib.rs

Lines changed: 52 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@
3636
#![recursion_limit = "256"]
3737

3838
use rustc_ast::node_id::NodeMap;
39+
use rustc_ast::ptr::P;
3940
use rustc_ast::token::{self, Token};
4041
use rustc_ast::tokenstream::{CanSynthesizeMissingTokens, TokenStream, TokenTree};
4142
use rustc_ast::visit::{self, AssocCtxt, Visitor};
@@ -120,8 +121,11 @@ struct LoweringContext<'a, 'hir: 'a> {
120121
/// outside of an `async fn`.
121122
current_item: Option<Span>,
122123

124+
top_level_items: Vec<Item>,
125+
123126
catch_scopes: Vec<NodeId>,
124127
loop_scopes: Vec<NodeId>,
128+
is_at_top_level: bool,
125129
is_in_loop_condition: bool,
126130
is_in_trait_impl: bool,
127131
is_in_dyn_type: bool,
@@ -331,6 +335,7 @@ pub fn lower_crate<'a, 'hir>(
331335
attrs: BTreeMap::default(),
332336
catch_scopes: Vec::new(),
333337
loop_scopes: Vec::new(),
338+
is_at_top_level: true,
334339
is_in_loop_condition: false,
335340
is_in_trait_impl: false,
336341
is_in_dyn_type: false,
@@ -343,6 +348,7 @@ pub fn lower_crate<'a, 'hir>(
343348
generator_kind: None,
344349
task_context: None,
345350
current_item: None,
351+
top_level_items: Vec::new(),
346352
lifetimes_to_define: Vec::new(),
347353
is_collecting_in_band_lifetimes: false,
348354
in_scope_lifetimes: Vec::new(),
@@ -467,13 +473,22 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
467473
.count();
468474
self.lctx.type_def_lifetime_params.insert(def_id.to_def_id(), count);
469475
}
476+
ItemKind::MacroDef(..) => {
477+
if self.lctx.check_force_top_level(item) {
478+
self.lctx.top_level_items.push(item.clone());
479+
}
480+
}
470481
ItemKind::Use(ref use_tree) => {
471482
self.allocate_use_tree_hir_id_counters(use_tree);
472483
}
473484
_ => {}
474485
}
475486

487+
let was_at_top_level = mem::replace(&mut self.lctx.is_at_top_level, false);
488+
476489
visit::walk_item(self, item);
490+
491+
self.lctx.is_at_top_level = was_at_top_level;
477492
}
478493

479494
fn visit_assoc_item(&mut self, item: &'tcx AssocItem, ctxt: AssocCtxt) {
@@ -510,7 +525,10 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
510525
visit::walk_crate(&mut MiscCollector { lctx: &mut self }, c);
511526
visit::walk_crate(&mut item::ItemLowerer { lctx: &mut self }, c);
512527

513-
let module = self.arena.alloc(self.lower_mod(&c.items, c.span));
528+
let mut items: Vec<_> = self.top_level_items.drain(..).map(|item| P(item)).collect();
529+
items.extend(c.items.clone());
530+
531+
let module = self.arena.alloc(self.lower_mod(items.as_slice(), c.span));
514532
self.lower_attrs(hir::CRATE_HIR_ID, &c.attrs);
515533
self.owners.ensure_contains_elem(CRATE_DEF_ID, || None);
516534
self.owners[CRATE_DEF_ID] = Some(hir::OwnerNode::Crate(module));
@@ -561,12 +579,13 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
561579
self.arena.alloc(krate)
562580
}
563581

564-
fn insert_item(&mut self, item: hir::Item<'hir>) -> hir::ItemId {
582+
fn insert_item(&mut self, item: hir::Item<'hir>, force_top_level: bool) -> hir::ItemId {
565583
let id = item.item_id();
566584
let item = self.arena.alloc(item);
585+
let module = if force_top_level { CRATE_DEF_ID } else { self.current_module };
567586
self.owners.ensure_contains_elem(id.def_id, || None);
568587
self.owners[id.def_id] = Some(hir::OwnerNode::Item(item));
569-
self.modules.entry(self.current_module).or_default().items.insert(id);
588+
self.modules.entry(module).or_default().items.insert(id);
570589
id
571590
}
572591

@@ -597,6 +616,19 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
597616
id
598617
}
599618

619+
/// This checks if an item is a `#[macro_use]` macro, and thus always
620+
/// defined at the top level. As a special case, if the macro is already
621+
/// at the top level, it remains at its current level.
622+
fn check_force_top_level(&self, item: &Item) -> bool {
623+
if self.is_at_top_level {
624+
false
625+
} else if let ItemKind::MacroDef(MacroDef { macro_rules, .. }) = item.kind {
626+
macro_rules && self.sess.contains_name(&item.attrs, sym::macro_export)
627+
} else {
628+
false
629+
}
630+
}
631+
600632
fn allocate_hir_id_counter(&mut self, owner: NodeId) -> hir::HirId {
601633
// Set up the counter if needed.
602634
self.item_local_id_counters.entry(owner).or_insert(0);
@@ -1593,7 +1625,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
15931625
// Insert the item into the global item list. This usually happens
15941626
// automatically for all AST items. But this opaque type item
15951627
// does not actually exist in the AST.
1596-
self.insert_item(opaque_ty_item);
1628+
self.insert_item(opaque_ty_item, false);
15971629
}
15981630

15991631
fn lifetimes_from_impl_trait_bounds(
@@ -2382,7 +2414,22 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
23822414
[stmts @ .., Stmt { kind: StmtKind::Expr(e), .. }] => (stmts, Some(&*e)),
23832415
stmts => (stmts, None),
23842416
};
2385-
let stmts = self.arena.alloc_from_iter(stmts.iter().flat_map(|stmt| self.lower_stmt(stmt)));
2417+
let stmts: Vec<_> = stmts
2418+
.iter()
2419+
.filter_map(|stmt| {
2420+
if let StmtKind::Item(ref item) = stmt.kind {
2421+
if self.check_force_top_level(item) {
2422+
None
2423+
} else {
2424+
Some(self.lower_stmt(stmt))
2425+
}
2426+
} else {
2427+
Some(self.lower_stmt(stmt))
2428+
}
2429+
})
2430+
.flatten()
2431+
.collect();
2432+
let stmts = self.arena.alloc_from_iter(stmts.into_iter());
23862433
let expr = expr.map(|e| self.lower_expr(e));
23872434
let rules = self.lower_block_check_mode(&b.rules);
23882435
let hir_id = self.lower_node_id(b.id);

0 commit comments

Comments
 (0)