Skip to content

Commit 141c6cc

Browse files
committed
expand: Turn ast::Crate into a first class expansion target
And stop creating a fake `mod` item for the crate root when expanding a crate.
1 parent 4919988 commit 141c6cc

File tree

20 files changed

+203
-159
lines changed

20 files changed

+203
-159
lines changed

compiler/rustc_ast/src/ast.rs

+2
Original file line numberDiff line numberDiff line change
@@ -517,6 +517,8 @@ pub struct Crate {
517517
pub attrs: Vec<Attribute>,
518518
pub items: Vec<P<Item>>,
519519
pub span: Span,
520+
// Placeholder ID if the crate node is a macro placeholder.
521+
pub is_placeholder: Option<NodeId>,
520522
}
521523

522524
/// Possible values inside of compile-time attribute lists.

compiler/rustc_ast/src/ast_like.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
use super::ptr::P;
22
use super::token::Nonterminal;
33
use super::tokenstream::LazyTokenStream;
4-
use super::{Arm, ExprField, FieldDef, GenericParam, Param, PatField, Variant};
4+
use super::{Arm, Crate, ExprField, FieldDef, GenericParam, Param, PatField, Variant};
55
use super::{AssocItem, Expr, ForeignItem, Item, Local, MacCallStmt};
66
use super::{AttrItem, AttrKind, Block, Pat, Path, Ty, Visibility};
77
use super::{AttrVec, Attribute, Stmt, StmtKind};
@@ -276,7 +276,7 @@ derive_has_tokens_and_attrs! {
276276
// These ast nodes only support inert attributes, so they don't
277277
// store tokens (since nothing can observe them)
278278
derive_has_attrs_no_tokens! {
279-
FieldDef, Arm, ExprField, PatField, Variant, Param, GenericParam
279+
FieldDef, Arm, ExprField, PatField, Variant, Param, GenericParam, Crate
280280
}
281281

282282
// These AST nodes don't support attributes, but can

compiler/rustc_ast/src/mut_visit.rs

+8-29
Original file line numberDiff line numberDiff line change
@@ -284,6 +284,10 @@ pub trait MutVisitor: Sized {
284284
/// Use a map-style function (`FnOnce(T) -> T`) to overwrite a `&mut T`. Useful
285285
/// when using a `flat_map_*` or `filter_map_*` method within a `visit_`
286286
/// method. Abort the program if the closure panics.
287+
///
288+
/// FIXME: Abort on panic means that any fatal error inside `visit_clobber` will abort the compiler.
289+
/// Instead of aborting on catching a panic we need to reset the visited node to some valid but
290+
/// possibly meaningless value and rethrow the panic.
287291
//
288292
// No `noop_` prefix because there isn't a corresponding method in `MutVisitor`.
289293
pub fn visit_clobber<T, F>(t: &mut T, f: F)
@@ -1105,36 +1109,11 @@ pub fn noop_visit_fn_header<T: MutVisitor>(header: &mut FnHeader, vis: &mut T) {
11051109
visit_unsafety(unsafety, vis);
11061110
}
11071111

1108-
// FIXME: Avoid visiting the crate as a `Mod` item, flat map only the inner items if possible,
1109-
// or make crate visiting first class if necessary.
11101112
pub fn noop_visit_crate<T: MutVisitor>(krate: &mut Crate, vis: &mut T) {
1111-
visit_clobber(krate, |Crate { attrs, items, span }| {
1112-
let item_vis =
1113-
Visibility { kind: VisibilityKind::Public, span: span.shrink_to_lo(), tokens: None };
1114-
let item = P(Item {
1115-
ident: Ident::empty(),
1116-
attrs,
1117-
id: DUMMY_NODE_ID,
1118-
vis: item_vis,
1119-
span,
1120-
kind: ItemKind::Mod(Unsafe::No, ModKind::Loaded(items, Inline::Yes, span)),
1121-
tokens: None,
1122-
});
1123-
let items = vis.flat_map_item(item);
1124-
1125-
let len = items.len();
1126-
if len == 0 {
1127-
Crate { attrs: vec![], items: vec![], span }
1128-
} else if len == 1 {
1129-
let Item { attrs, span, kind, .. } = items.into_iter().next().unwrap().into_inner();
1130-
match kind {
1131-
ItemKind::Mod(_, ModKind::Loaded(items, ..)) => Crate { attrs, items, span },
1132-
_ => panic!("visitor converted a module to not a module"),
1133-
}
1134-
} else {
1135-
panic!("a crate cannot expand to more than one item");
1136-
}
1137-
});
1113+
let Crate { attrs, items, span, is_placeholder: _ } = krate;
1114+
visit_attrs(attrs, vis);
1115+
items.flat_map_in_place(|item| vis.flat_map_item(item));
1116+
vis.visit_span(span);
11381117
}
11391118

11401119
// Mutates one item into possibly many items.

compiler/rustc_ast/src/visit.rs

+3
Original file line numberDiff line numberDiff line change
@@ -211,6 +211,9 @@ pub trait Visitor<'ast>: Sized {
211211
fn visit_pat_field(&mut self, fp: &'ast PatField) {
212212
walk_pat_field(self, fp)
213213
}
214+
fn visit_crate(&mut self, krate: &'ast Crate) {
215+
walk_crate(self, krate)
216+
}
214217
}
215218

216219
#[macro_export]

compiler/rustc_ast_pretty/src/pprust/mod.rs

+9
Original file line numberDiff line numberDiff line change
@@ -75,3 +75,12 @@ pub fn attribute_to_string(attr: &ast::Attribute) -> String {
7575
pub fn to_string(f: impl FnOnce(&mut State<'_>)) -> String {
7676
State::new().to_string(f)
7777
}
78+
79+
pub fn crate_to_string_for_macros(krate: &ast::Crate) -> String {
80+
State::new().to_string(|s| {
81+
s.print_inner_attributes(&krate.attrs);
82+
for item in &krate.items {
83+
s.print_item(item);
84+
}
85+
})
86+
}

compiler/rustc_builtin_macros/src/cfg_eval.rs

+5
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,10 @@ fn flat_map_annotatable(
7777
Annotatable::Param(param) => vis.flat_map_param(param).pop().map(Annotatable::Param),
7878
Annotatable::FieldDef(sf) => vis.flat_map_field_def(sf).pop().map(Annotatable::FieldDef),
7979
Annotatable::Variant(v) => vis.flat_map_variant(v).pop().map(Annotatable::Variant),
80+
Annotatable::Crate(mut krate) => {
81+
vis.visit_crate(&mut krate);
82+
Some(Annotatable::Crate(krate))
83+
}
8084
}
8185
}
8286

@@ -101,6 +105,7 @@ impl CfgFinder {
101105
Annotatable::Param(param) => finder.visit_param(&param),
102106
Annotatable::FieldDef(field) => finder.visit_field_def(&field),
103107
Annotatable::Variant(variant) => finder.visit_variant(&variant),
108+
Annotatable::Crate(krate) => finder.visit_crate(krate),
104109
};
105110
finder.has_cfg_or_cfg_attr
106111
}

compiler/rustc_builtin_macros/src/test_harness.rs

+30-28
Original file line numberDiff line numberDiff line change
@@ -84,9 +84,35 @@ struct TestHarnessGenerator<'a> {
8484
tests: Vec<Test>,
8585
}
8686

87+
impl TestHarnessGenerator<'_> {
88+
fn add_test_cases(&mut self, node_id: ast::NodeId, span: Span, prev_tests: Vec<Test>) {
89+
let mut tests = mem::replace(&mut self.tests, prev_tests);
90+
91+
if !tests.is_empty() {
92+
// Create an identifier that will hygienically resolve the test
93+
// case name, even in another module.
94+
let expn_id = self.cx.ext_cx.resolver.expansion_for_ast_pass(
95+
span,
96+
AstPass::TestHarness,
97+
&[],
98+
Some(node_id),
99+
);
100+
for test in &mut tests {
101+
// See the comment on `mk_main` for why we're using
102+
// `apply_mark` directly.
103+
test.ident.span =
104+
test.ident.span.apply_mark(expn_id.to_expn_id(), Transparency::Opaque);
105+
}
106+
self.cx.test_cases.extend(tests);
107+
}
108+
}
109+
}
110+
87111
impl<'a> MutVisitor for TestHarnessGenerator<'a> {
88112
fn visit_crate(&mut self, c: &mut ast::Crate) {
113+
let prev_tests = mem::take(&mut self.tests);
89114
noop_visit_crate(c, self);
115+
self.add_test_cases(ast::CRATE_NODE_ID, c.span, prev_tests);
90116

91117
// Create a main function to run our tests
92118
c.items.push(mk_main(&mut self.cx));
@@ -103,34 +129,10 @@ impl<'a> MutVisitor for TestHarnessGenerator<'a> {
103129

104130
// We don't want to recurse into anything other than mods, since
105131
// mods or tests inside of functions will break things
106-
if let ast::ItemKind::Mod(..) = item.kind {
107-
let tests = mem::take(&mut self.tests);
132+
if let ast::ItemKind::Mod(_, ModKind::Loaded(.., span)) = item.kind {
133+
let prev_tests = mem::take(&mut self.tests);
108134
noop_visit_item_kind(&mut item.kind, self);
109-
let mut tests = mem::replace(&mut self.tests, tests);
110-
111-
if !tests.is_empty() {
112-
let parent =
113-
if item.id == ast::DUMMY_NODE_ID { ast::CRATE_NODE_ID } else { item.id };
114-
// Create an identifier that will hygienically resolve the test
115-
// case name, even in another module.
116-
let inner_span = match item.kind {
117-
ast::ItemKind::Mod(_, ModKind::Loaded(.., span)) => span,
118-
_ => unreachable!(),
119-
};
120-
let expn_id = self.cx.ext_cx.resolver.expansion_for_ast_pass(
121-
inner_span,
122-
AstPass::TestHarness,
123-
&[],
124-
Some(parent),
125-
);
126-
for test in &mut tests {
127-
// See the comment on `mk_main` for why we're using
128-
// `apply_mark` directly.
129-
test.ident.span =
130-
test.ident.span.apply_mark(expn_id.to_expn_id(), Transparency::Opaque);
131-
}
132-
self.cx.test_cases.extend(tests);
133-
}
135+
self.add_test_cases(item.id, span, prev_tests);
134136
}
135137
smallvec![P(item)]
136138
}
@@ -146,7 +148,7 @@ fn entry_point_type(sess: &Session, item: &ast::Item, depth: usize) -> EntryPoin
146148
} else if sess.contains_name(&item.attrs, sym::rustc_main) {
147149
EntryPointType::MainAttr
148150
} else if item.ident.name == sym::main {
149-
if depth == 1 {
151+
if depth == 0 {
150152
// This is a top-level function so can be 'main'
151153
EntryPointType::MainNamed
152154
} else {

compiler/rustc_expand/src/base.rs

+18-1
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,7 @@ pub enum Annotatable {
4848
Param(ast::Param),
4949
FieldDef(ast::FieldDef),
5050
Variant(ast::Variant),
51+
Crate(ast::Crate),
5152
}
5253

5354
impl Annotatable {
@@ -66,6 +67,7 @@ impl Annotatable {
6667
Annotatable::Param(ref p) => p.span,
6768
Annotatable::FieldDef(ref sf) => sf.span,
6869
Annotatable::Variant(ref v) => v.span,
70+
Annotatable::Crate(ref c) => c.span,
6971
}
7072
}
7173

@@ -84,6 +86,7 @@ impl Annotatable {
8486
Annotatable::Param(p) => p.visit_attrs(f),
8587
Annotatable::FieldDef(sf) => sf.visit_attrs(f),
8688
Annotatable::Variant(v) => v.visit_attrs(f),
89+
Annotatable::Crate(c) => c.visit_attrs(f),
8790
}
8891
}
8992

@@ -102,6 +105,7 @@ impl Annotatable {
102105
Annotatable::Param(p) => visitor.visit_param(p),
103106
Annotatable::FieldDef(sf) => visitor.visit_field_def(sf),
104107
Annotatable::Variant(v) => visitor.visit_variant(v),
108+
Annotatable::Crate(c) => visitor.visit_crate(c),
105109
}
106110
}
107111

@@ -122,7 +126,8 @@ impl Annotatable {
122126
| Annotatable::GenericParam(..)
123127
| Annotatable::Param(..)
124128
| Annotatable::FieldDef(..)
125-
| Annotatable::Variant(..) => panic!("unexpected annotatable"),
129+
| Annotatable::Variant(..)
130+
| Annotatable::Crate(..) => panic!("unexpected annotatable"),
126131
}
127132
}
128133

@@ -220,6 +225,13 @@ impl Annotatable {
220225
_ => panic!("expected variant"),
221226
}
222227
}
228+
229+
pub fn expect_crate(self) -> ast::Crate {
230+
match self {
231+
Annotatable::Crate(krate) => krate,
232+
_ => panic!("expected krate"),
233+
}
234+
}
223235
}
224236

225237
/// Result of an expansion that may need to be retried.
@@ -419,6 +431,11 @@ pub trait MacResult {
419431
fn make_variants(self: Box<Self>) -> Option<SmallVec<[ast::Variant; 1]>> {
420432
None
421433
}
434+
435+
fn make_crate(self: Box<Self>) -> Option<ast::Crate> {
436+
// Fn-like macros cannot produce a crate.
437+
unreachable!()
438+
}
422439
}
423440

424441
macro_rules! make_MacEager {

0 commit comments

Comments
 (0)