Skip to content

Commit aca1b1e

Browse files
committed
rustc_interface: Add a new query pre_configure
It partially expands crate attributes before the main expansion pass (without modifying the crate), and the produced preliminary crate attribute list is used for querying a few attributes that are required very early. Crate-level cfg attributes are then expanded normally during the main expansion pass, like attributes on any other nodes.
1 parent f26da39 commit aca1b1e

File tree

12 files changed

+108
-84
lines changed

12 files changed

+108
-84
lines changed

compiler/rustc_builtin_macros/src/standard_library_imports.rs

+12-5
Original file line numberDiff line numberDiff line change
@@ -8,14 +8,20 @@ use rustc_span::symbol::{kw, sym, Ident, Symbol};
88
use rustc_span::DUMMY_SP;
99
use thin_vec::thin_vec;
1010

11-
pub fn inject(krate: &mut ast::Crate, resolver: &mut dyn ResolverExpand, sess: &Session) {
11+
pub fn inject(
12+
krate: &mut ast::Crate,
13+
pre_configured_attrs: &[ast::Attribute],
14+
resolver: &mut dyn ResolverExpand,
15+
sess: &Session,
16+
) -> usize {
17+
let orig_num_items = krate.items.len();
1218
let edition = sess.parse_sess.edition;
1319

1420
// the first name in this list is the crate name of the crate with the prelude
15-
let names: &[Symbol] = if attr::contains_name(&krate.attrs, sym::no_core) {
16-
return;
17-
} else if attr::contains_name(&krate.attrs, sym::no_std) {
18-
if attr::contains_name(&krate.attrs, sym::compiler_builtins) {
21+
let names: &[Symbol] = if attr::contains_name(pre_configured_attrs, sym::no_core) {
22+
return 0;
23+
} else if attr::contains_name(pre_configured_attrs, sym::no_std) {
24+
if attr::contains_name(pre_configured_attrs, sym::compiler_builtins) {
1925
&[sym::core]
2026
} else {
2127
&[sym::core, sym::compiler_builtins]
@@ -84,4 +90,5 @@ pub fn inject(krate: &mut ast::Crate, resolver: &mut dyn ResolverExpand, sess: &
8490
);
8591

8692
krate.items.insert(0, use_item);
93+
krate.items.len() - orig_num_items
8794
}

compiler/rustc_driver_impl/src/lib.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -353,7 +353,7 @@ fn run_compiler(
353353

354354
{
355355
let plugins = queries.register_plugins()?;
356-
let (_, lint_store) = &*plugins.borrow();
356+
let (.., lint_store) = &*plugins.borrow();
357357

358358
// Lint plugins are registered; now we can process command line flags.
359359
if sess.opts.describe_lints {

compiler/rustc_expand/src/base.rs

+2
Original file line numberDiff line numberDiff line change
@@ -1002,6 +1002,7 @@ pub struct ExpansionData {
10021002
pub struct ExtCtxt<'a> {
10031003
pub sess: &'a Session,
10041004
pub ecfg: expand::ExpansionConfig<'a>,
1005+
pub num_standard_library_imports: usize,
10051006
pub reduced_recursion_limit: Option<Limit>,
10061007
pub root_path: PathBuf,
10071008
pub resolver: &'a mut dyn ResolverExpand,
@@ -1030,6 +1031,7 @@ impl<'a> ExtCtxt<'a> {
10301031
ExtCtxt {
10311032
sess,
10321033
ecfg,
1034+
num_standard_library_imports: 0,
10331035
reduced_recursion_limit: None,
10341036
resolver,
10351037
lint_store,

compiler/rustc_expand/src/config.rs

+11-29
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,6 @@ use rustc_session::Session;
2424
use rustc_span::edition::{Edition, ALL_EDITIONS};
2525
use rustc_span::symbol::{sym, Symbol};
2626
use rustc_span::{Span, DUMMY_SP};
27-
use thin_vec::ThinVec;
2827

2928
/// A folder that strips out items that do not belong in the current configuration.
3029
pub struct StripUnconfigured<'a> {
@@ -37,7 +36,7 @@ pub struct StripUnconfigured<'a> {
3736
pub lint_node_id: NodeId,
3837
}
3938

40-
fn get_features(sess: &Session, krate_attrs: &[ast::Attribute]) -> Features {
39+
pub fn features(sess: &Session, krate_attrs: &[Attribute]) -> Features {
4140
fn feature_removed(sess: &Session, span: Span, reason: Option<&str>) {
4241
sess.emit_err(FeatureRemoved {
4342
span,
@@ -191,33 +190,16 @@ fn get_features(sess: &Session, krate_attrs: &[ast::Attribute]) -> Features {
191190
features
192191
}
193192

194-
/// `cfg_attr`-process the crate's attributes and compute the crate's features.
195-
pub fn features(sess: &Session, krate: &mut ast::Crate, lint_node_id: NodeId) -> Features {
196-
let mut strip_unconfigured =
197-
StripUnconfigured { sess, features: None, config_tokens: false, lint_node_id };
198-
199-
let mut unconfigured_attrs = krate.attrs.clone();
200-
let diag = &sess.parse_sess.span_diagnostic;
201-
let err_count = diag.err_count();
202-
203-
krate.attrs.flat_map_in_place(|attr| strip_unconfigured.process_cfg_attr(&attr));
204-
if !strip_unconfigured.in_cfg(&krate.attrs) {
205-
// The entire crate is unconfigured.
206-
krate.attrs = ast::AttrVec::new();
207-
krate.items = ThinVec::new();
208-
Features::default()
209-
} else {
210-
let features = get_features(sess, &krate.attrs);
211-
if err_count == diag.err_count() {
212-
// Avoid reconfiguring malformed `cfg_attr`s.
213-
strip_unconfigured.features = Some(&features);
214-
// Run configuration again, this time with features available
215-
// so that we can perform feature-gating.
216-
unconfigured_attrs.flat_map_in_place(|attr| strip_unconfigured.process_cfg_attr(&attr));
217-
strip_unconfigured.in_cfg(&unconfigured_attrs);
218-
}
219-
features
220-
}
193+
pub fn pre_configure_attrs(sess: &Session, attrs: &[Attribute]) -> ast::AttrVec {
194+
let strip_unconfigured = StripUnconfigured {
195+
sess,
196+
features: None,
197+
config_tokens: false,
198+
lint_node_id: ast::CRATE_NODE_ID,
199+
};
200+
let attrs: ast::AttrVec =
201+
attrs.iter().flat_map(|attr| strip_unconfigured.process_cfg_attr(attr)).collect();
202+
if strip_unconfigured.in_cfg(&attrs) { attrs } else { ast::AttrVec::new() }
221203
}
222204

223205
#[macro_export]

compiler/rustc_expand/src/expand.rs

+9-1
Original file line numberDiff line numberDiff line change
@@ -1038,6 +1038,9 @@ trait InvocationCollectorNode: HasAttrs + HasNodeId + Sized {
10381038
) -> Result<Self::OutputTy, Self> {
10391039
Ok(noop_flat_map(node, collector))
10401040
}
1041+
fn expand_cfg_false(&mut self, collector: &mut InvocationCollector<'_, '_>, span: Span) {
1042+
collector.cx.emit_err(RemoveNodeNotSupported { span, descr: Self::descr() });
1043+
}
10411044
}
10421045

10431046
impl InvocationCollectorNode for P<ast::Item> {
@@ -1378,6 +1381,11 @@ impl InvocationCollectorNode for ast::Crate {
13781381
fn noop_visit<V: MutVisitor>(&mut self, visitor: &mut V) {
13791382
noop_visit_crate(self, visitor)
13801383
}
1384+
fn expand_cfg_false(&mut self, collector: &mut InvocationCollector<'_, '_>, _span: Span) {
1385+
self.attrs.clear();
1386+
// Standard prelude imports are left in the crate for backward compatibility.
1387+
self.items.truncate(collector.cx.num_standard_library_imports);
1388+
}
13811389
}
13821390

13831391
impl InvocationCollectorNode for P<ast::Ty> {
@@ -1756,7 +1764,7 @@ impl<'a, 'b> InvocationCollector<'a, 'b> {
17561764
continue;
17571765
}
17581766

1759-
self.cx.emit_err(RemoveNodeNotSupported { span, descr: Node::descr() });
1767+
node.expand_cfg_false(self, span);
17601768
continue;
17611769
}
17621770
sym::cfg_attr => {

compiler/rustc_interface/src/passes.rs

+27-24
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@ use crate::interface::{Compiler, Result};
33
use crate::proc_macro_decls;
44
use crate::util;
55

6-
use ast::CRATE_NODE_ID;
76
use rustc_ast::{self as ast, visit};
87
use rustc_borrowck as mir_borrowck;
98
use rustc_codegen_ssa::traits::CodegenBackend;
@@ -76,22 +75,14 @@ pub fn register_plugins<'a>(
7675
sess: &'a Session,
7776
metadata_loader: &'a dyn MetadataLoader,
7877
register_lints: impl Fn(&Session, &mut LintStore),
79-
krate: &mut ast::Crate,
78+
pre_configured_attrs: &[ast::Attribute],
8079
crate_name: Symbol,
8180
) -> Result<LintStore> {
82-
sess.time("attributes_injection", || {
83-
rustc_builtin_macros::cmdline_attrs::inject(
84-
krate,
85-
&sess.parse_sess,
86-
&sess.opts.unstable_opts.crate_attr,
87-
)
88-
});
89-
90-
let features = rustc_expand::config::features(sess, krate, CRATE_NODE_ID);
9181
// these need to be set "early" so that expansion sees `quote` if enabled.
82+
let features = rustc_expand::config::features(sess, pre_configured_attrs);
9283
sess.init_features(features);
9384

94-
let crate_types = util::collect_crate_types(sess, &krate.attrs);
85+
let crate_types = util::collect_crate_types(sess, pre_configured_attrs);
9586
sess.init_crate_types(crate_types);
9687

9788
let stable_crate_id = StableCrateId::new(
@@ -117,8 +108,9 @@ pub fn register_plugins<'a>(
117108
let mut lint_store = rustc_lint::new_lint_store(sess.enable_internal_lints());
118109
register_lints(sess, &mut lint_store);
119110

120-
let registrars = sess
121-
.time("plugin_loading", || plugin::load::load_plugins(sess, metadata_loader, &krate.attrs));
111+
let registrars = sess.time("plugin_loading", || {
112+
plugin::load::load_plugins(sess, metadata_loader, pre_configured_attrs)
113+
});
122114
sess.time("plugin_registration", || {
123115
let mut registry = plugin::Registry { lint_store: &mut lint_store };
124116
for registrar in registrars {
@@ -173,19 +165,29 @@ impl LintStoreExpand for LintStoreExpandImpl<'_> {
173165
/// harness if one is to be provided, injection of a dependency on the
174166
/// standard library and prelude, and name resolution.
175167
#[instrument(level = "trace", skip(krate, resolver))]
176-
fn configure_and_expand(mut krate: ast::Crate, resolver: &mut Resolver<'_, '_>) -> ast::Crate {
168+
fn configure_and_expand(
169+
mut krate: ast::Crate,
170+
pre_configured_attrs: &[ast::Attribute],
171+
resolver: &mut Resolver<'_, '_>,
172+
) -> ast::Crate {
177173
let tcx = resolver.tcx();
178174
let sess = tcx.sess;
179175
let lint_store = unerased_lint_store(tcx);
180176
let crate_name = tcx.crate_name(LOCAL_CRATE);
181-
pre_expansion_lint(sess, lint_store, tcx.registered_tools(()), &krate, crate_name);
177+
let lint_check_node = (&krate, pre_configured_attrs);
178+
pre_expansion_lint(sess, lint_store, tcx.registered_tools(()), lint_check_node, crate_name);
182179
rustc_builtin_macros::register_builtin_macros(resolver);
183180

184-
sess.time("crate_injection", || {
185-
rustc_builtin_macros::standard_library_imports::inject(&mut krate, resolver, sess)
181+
let num_standard_library_imports = sess.time("crate_injection", || {
182+
rustc_builtin_macros::standard_library_imports::inject(
183+
&mut krate,
184+
pre_configured_attrs,
185+
resolver,
186+
sess,
187+
)
186188
});
187189

188-
util::check_attr_crate_type(sess, &krate.attrs, &mut resolver.lint_buffer());
190+
util::check_attr_crate_type(sess, pre_configured_attrs, &mut resolver.lint_buffer());
189191

190192
// Expand all macros
191193
krate = sess.time("macro_expand_crate", || {
@@ -222,7 +224,7 @@ fn configure_and_expand(mut krate: ast::Crate, resolver: &mut Resolver<'_, '_>)
222224

223225
// Create the config for macro expansion
224226
let features = sess.features_untracked();
225-
let recursion_limit = get_recursion_limit(&krate.attrs, sess);
227+
let recursion_limit = get_recursion_limit(pre_configured_attrs, sess);
226228
let cfg = rustc_expand::expand::ExpansionConfig {
227229
features: Some(features),
228230
recursion_limit,
@@ -235,6 +237,7 @@ fn configure_and_expand(mut krate: ast::Crate, resolver: &mut Resolver<'_, '_>)
235237

236238
let lint_store = LintStoreExpandImpl(lint_store);
237239
let mut ecx = ExtCtxt::new(sess, cfg, resolver, Some(&lint_store));
240+
ecx.num_standard_library_imports = num_standard_library_imports;
238241
// Expand macros now!
239242
let krate = sess.time("expand_crate", || ecx.monotonic_expander().expand_crate(krate));
240243

@@ -356,7 +359,7 @@ fn early_lint_checks(tcx: TyCtxt<'_>, (): ()) {
356359
tcx.registered_tools(()),
357360
Some(lint_buffer),
358361
rustc_lint::BuiltinCombinedEarlyLintPass::new(),
359-
&**krate,
362+
(&**krate, &*krate.attrs),
360363
)
361364
}
362365

@@ -557,9 +560,9 @@ fn resolver_for_lowering<'tcx>(
557560
) -> &'tcx Steal<(ty::ResolverAstLowering, Lrc<ast::Crate>)> {
558561
let arenas = Resolver::arenas();
559562
let _ = tcx.registered_tools(()); // Uses `crate_for_resolver`.
560-
let krate = tcx.crate_for_resolver(()).steal();
561-
let mut resolver = Resolver::new(tcx, &krate, &arenas);
562-
let krate = configure_and_expand(krate, &mut resolver);
563+
let (krate, pre_configured_attrs) = tcx.crate_for_resolver(()).steal();
564+
let mut resolver = Resolver::new(tcx, &pre_configured_attrs, krate.spans.inner_span, &arenas);
565+
let krate = configure_and_expand(krate, &pre_configured_attrs, &mut resolver);
563566

564567
// Make sure we don't mutate the cstore from here on.
565568
tcx.untracked().cstore.leak();

compiler/rustc_interface/src/queries.rs

+31-10
Original file line numberDiff line numberDiff line change
@@ -88,8 +88,9 @@ pub struct Queries<'tcx> {
8888

8989
dep_graph_future: Query<Option<DepGraphFuture>>,
9090
parse: Query<ast::Crate>,
91+
pre_configure: Query<(ast::Crate, ast::AttrVec)>,
9192
crate_name: Query<Symbol>,
92-
register_plugins: Query<(ast::Crate, Lrc<LintStore>)>,
93+
register_plugins: Query<(ast::Crate, ast::AttrVec, Lrc<LintStore>)>,
9394
dep_graph: Query<DepGraph>,
9495
// This just points to what's in `gcx_cell`.
9596
gcx: Query<&'tcx GlobalCtxt<'tcx>>,
@@ -106,6 +107,7 @@ impl<'tcx> Queries<'tcx> {
106107
hir_arena: WorkerLocal::new(|_| rustc_hir::Arena::default()),
107108
dep_graph_future: Default::default(),
108109
parse: Default::default(),
110+
pre_configure: Default::default(),
109111
crate_name: Default::default(),
110112
register_plugins: Default::default(),
111113
dep_graph: Default::default(),
@@ -133,17 +135,36 @@ impl<'tcx> Queries<'tcx> {
133135
.compute(|| passes::parse(self.session()).map_err(|mut parse_error| parse_error.emit()))
134136
}
135137

136-
pub fn register_plugins(&self) -> Result<QueryResult<'_, (ast::Crate, Lrc<LintStore>)>> {
138+
pub fn pre_configure(&self) -> Result<QueryResult<'_, (ast::Crate, ast::AttrVec)>> {
139+
self.pre_configure.compute(|| {
140+
let mut krate = self.parse()?.steal();
141+
142+
let sess = self.session();
143+
rustc_builtin_macros::cmdline_attrs::inject(
144+
&mut krate,
145+
&sess.parse_sess,
146+
&sess.opts.unstable_opts.crate_attr,
147+
);
148+
149+
let pre_configured_attrs =
150+
rustc_expand::config::pre_configure_attrs(sess, &krate.attrs);
151+
Ok((krate, pre_configured_attrs))
152+
})
153+
}
154+
155+
pub fn register_plugins(
156+
&self,
157+
) -> Result<QueryResult<'_, (ast::Crate, ast::AttrVec, Lrc<LintStore>)>> {
137158
self.register_plugins.compute(|| {
138159
let crate_name = *self.crate_name()?.borrow();
139-
let mut krate = self.parse()?.steal();
160+
let (krate, pre_configured_attrs) = self.pre_configure()?.steal();
140161

141162
let empty: &(dyn Fn(&Session, &mut LintStore) + Sync + Send) = &|_, _| {};
142163
let lint_store = passes::register_plugins(
143164
self.session(),
144165
&*self.codegen_backend().metadata_loader(),
145166
self.compiler.register_lints.as_deref().unwrap_or_else(|| empty),
146-
&mut krate,
167+
&pre_configured_attrs,
147168
crate_name,
148169
)?;
149170

@@ -154,17 +175,17 @@ impl<'tcx> Queries<'tcx> {
154175
// called, which happens within passes::register_plugins().
155176
self.dep_graph_future().ok();
156177

157-
Ok((krate, Lrc::new(lint_store)))
178+
Ok((krate, pre_configured_attrs, Lrc::new(lint_store)))
158179
})
159180
}
160181

161182
fn crate_name(&self) -> Result<QueryResult<'_, Symbol>> {
162183
self.crate_name.compute(|| {
163184
Ok({
164-
let parse_result = self.parse()?;
165-
let krate = parse_result.borrow();
185+
let pre_configure_result = self.pre_configure()?;
186+
let (_, pre_configured_attrs) = &*pre_configure_result.borrow();
166187
// parse `#[crate_name]` even if `--crate-name` was passed, to make sure it matches.
167-
find_crate_name(self.session(), &krate.attrs)
188+
find_crate_name(self.session(), pre_configured_attrs)
168189
})
169190
})
170191
}
@@ -188,7 +209,7 @@ impl<'tcx> Queries<'tcx> {
188209
pub fn global_ctxt(&'tcx self) -> Result<QueryResult<'_, &'tcx GlobalCtxt<'tcx>>> {
189210
self.gcx.compute(|| {
190211
let crate_name = *self.crate_name()?.borrow();
191-
let (krate, lint_store) = self.register_plugins()?.steal();
212+
let (krate, pre_configured_attrs, lint_store) = self.register_plugins()?.steal();
192213

193214
let sess = self.session();
194215

@@ -215,7 +236,7 @@ impl<'tcx> Queries<'tcx> {
215236
feed.crate_name(crate_name);
216237

217238
let feed = tcx.feed_unit_query();
218-
feed.crate_for_resolver(tcx.arena.alloc(Steal::new(krate)));
239+
feed.crate_for_resolver(tcx.arena.alloc(Steal::new((krate, pre_configured_attrs))));
219240
feed.metadata_loader(
220241
tcx.arena.alloc(Steal::new(self.codegen_backend().metadata_loader())),
221242
);

compiler/rustc_lint/src/early.rs

+5-5
Original file line numberDiff line numberDiff line change
@@ -341,23 +341,23 @@ pub trait EarlyCheckNode<'a>: Copy {
341341
'a: 'b;
342342
}
343343

344-
impl<'a> EarlyCheckNode<'a> for &'a ast::Crate {
344+
impl<'a> EarlyCheckNode<'a> for (&'a ast::Crate, &'a [ast::Attribute]) {
345345
fn id(self) -> ast::NodeId {
346346
ast::CRATE_NODE_ID
347347
}
348348
fn attrs<'b>(self) -> &'b [ast::Attribute]
349349
where
350350
'a: 'b,
351351
{
352-
&self.attrs
352+
&self.1
353353
}
354354
fn check<'b, T: EarlyLintPass>(self, cx: &mut EarlyContextAndPass<'b, T>)
355355
where
356356
'a: 'b,
357357
{
358-
lint_callback!(cx, check_crate, self);
359-
ast_visit::walk_crate(cx, self);
360-
lint_callback!(cx, check_crate_post, self);
358+
lint_callback!(cx, check_crate, self.0);
359+
ast_visit::walk_crate(cx, self.0);
360+
lint_callback!(cx, check_crate_post, self.0);
361361
}
362362
}
363363

0 commit comments

Comments
 (0)