Skip to content

Commit df7fd99

Browse files
committed
Auto merge of #108221 - petrochenkov:cratecfg, r=michaelwoerister
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 on the crate itself are then expanded normally during the main expansion pass, like attributes on any other nodes. This is a continuation of #92473 and one more step to very unstable crate-level proc macro attributes maybe actually working. Previously crate attributes were pre-configured simultaneously with feature extraction, and then written directly into `ast::Crate`.
2 parents 99c49d9 + aca1b1e commit df7fd99

File tree

20 files changed

+207
-128
lines changed

20 files changed

+207
-128
lines changed

compiler/rustc_builtin_macros/src/cmdline_attrs.rs

+1-3
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ use rustc_ast::{self as ast, AttrItem, AttrStyle};
66
use rustc_session::parse::ParseSess;
77
use rustc_span::FileName;
88

9-
pub fn inject(mut krate: ast::Crate, parse_sess: &ParseSess, attrs: &[String]) -> ast::Crate {
9+
pub fn inject(krate: &mut ast::Crate, parse_sess: &ParseSess, attrs: &[String]) {
1010
for raw_attr in attrs {
1111
let mut parser = rustc_parse::new_parser_from_source_str(
1212
parse_sess,
@@ -36,6 +36,4 @@ pub fn inject(mut krate: ast::Crate, parse_sess: &ParseSess, attrs: &[String]) -
3636
start_span.to(end_span),
3737
));
3838
}
39-
40-
krate
4139
}

compiler/rustc_builtin_macros/src/proc_macro_harness.rs

+5-7
Original file line numberDiff line numberDiff line change
@@ -43,14 +43,14 @@ struct CollectProcMacros<'a> {
4343
}
4444

4545
pub fn inject(
46+
krate: &mut ast::Crate,
4647
sess: &Session,
4748
resolver: &mut dyn ResolverExpand,
48-
mut krate: ast::Crate,
4949
is_proc_macro_crate: bool,
5050
has_proc_macro_decls: bool,
5151
is_test_crate: bool,
5252
handler: &rustc_errors::Handler,
53-
) -> ast::Crate {
53+
) {
5454
let ecfg = ExpansionConfig::default("proc_macro".to_string());
5555
let mut cx = ExtCtxt::new(sess, ecfg, resolver, None);
5656

@@ -64,22 +64,20 @@ pub fn inject(
6464
};
6565

6666
if has_proc_macro_decls || is_proc_macro_crate {
67-
visit::walk_crate(&mut collect, &krate);
67+
visit::walk_crate(&mut collect, krate);
6868
}
6969
let macros = collect.macros;
7070

7171
if !is_proc_macro_crate {
72-
return krate;
72+
return;
7373
}
7474

7575
if is_test_crate {
76-
return krate;
76+
return;
7777
}
7878

7979
let decls = mk_decls(&mut cx, &macros);
8080
krate.items.push(decls);
81-
82-
krate
8381
}
8482

8583
impl<'a> CollectProcMacros<'a> {

compiler/rustc_builtin_macros/src/standard_library_imports.rs

+9-8
Original file line numberDiff line numberDiff line change
@@ -9,17 +9,19 @@ use rustc_span::DUMMY_SP;
99
use thin_vec::thin_vec;
1010

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

1820
// the first name in this list is the crate name of the crate with the prelude
19-
let names: &[Symbol] = if attr::contains_name(&krate.attrs, sym::no_core) {
20-
return krate;
21-
} else if attr::contains_name(&krate.attrs, sym::no_std) {
22-
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) {
2325
&[sym::core]
2426
} else {
2527
&[sym::core, sym::compiler_builtins]
@@ -88,6 +90,5 @@ pub fn inject(
8890
);
8991

9092
krate.items.insert(0, use_item);
91-
92-
krate
93+
krate.items.len() - orig_num_items
9394
}

compiler/rustc_builtin_macros/src/test_harness.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ struct TestCtxt<'a> {
3737

3838
/// Traverse the crate, collecting all the test functions, eliding any
3939
/// existing main functions, and synthesizing a main test harness
40-
pub fn inject(sess: &Session, resolver: &mut dyn ResolverExpand, krate: &mut ast::Crate) {
40+
pub fn inject(krate: &mut ast::Crate, sess: &Session, resolver: &mut dyn ResolverExpand) {
4141
let span_diagnostic = sess.diagnostic();
4242
let panic_strategy = sess.panic_strategy();
4343
let platform_panic_strategy = sess.target.panic_strategy;

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

+22-47
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,39 +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(
196-
sess: &Session,
197-
mut krate: ast::Crate,
198-
lint_node_id: NodeId,
199-
) -> (ast::Crate, Features) {
200-
let mut strip_unconfigured =
201-
StripUnconfigured { sess, features: None, config_tokens: false, lint_node_id };
202-
203-
let unconfigured_attrs = krate.attrs.clone();
204-
let diag = &sess.parse_sess.span_diagnostic;
205-
let err_count = diag.err_count();
206-
let features = match strip_unconfigured.configure_krate_attrs(krate.attrs) {
207-
None => {
208-
// The entire crate is unconfigured.
209-
krate.attrs = ast::AttrVec::new();
210-
krate.items = ThinVec::new();
211-
Features::default()
212-
}
213-
Some(attrs) => {
214-
krate.attrs = attrs;
215-
let features = get_features(sess, &krate.attrs);
216-
if err_count == diag.err_count() {
217-
// Avoid reconfiguring malformed `cfg_attr`s.
218-
strip_unconfigured.features = Some(&features);
219-
// Run configuration again, this time with features available
220-
// so that we can perform feature-gating.
221-
strip_unconfigured.configure_krate_attrs(unconfigured_attrs);
222-
}
223-
features
224-
}
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,
225199
};
226-
(krate, features)
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() }
227203
}
228204

229205
#[macro_export]
@@ -254,11 +230,6 @@ impl<'a> StripUnconfigured<'a> {
254230
}
255231
}
256232

257-
fn configure_krate_attrs(&self, mut attrs: ast::AttrVec) -> Option<ast::AttrVec> {
258-
attrs.flat_map_in_place(|attr| self.process_cfg_attr(attr));
259-
self.in_cfg(&attrs).then_some(attrs)
260-
}
261-
262233
/// Performs cfg-expansion on `stream`, producing a new `AttrTokenStream`.
263234
/// This is only used during the invocation of `derive` proc-macros,
264235
/// which require that we cfg-expand their entire input.
@@ -281,7 +252,7 @@ impl<'a> StripUnconfigured<'a> {
281252
.iter()
282253
.flat_map(|tree| match tree.clone() {
283254
AttrTokenTree::Attributes(mut data) => {
284-
data.attrs.flat_map_in_place(|attr| self.process_cfg_attr(attr));
255+
data.attrs.flat_map_in_place(|attr| self.process_cfg_attr(&attr));
285256

286257
if self.in_cfg(&data.attrs) {
287258
data.tokens = LazyAttrTokenStream::new(
@@ -319,12 +290,16 @@ impl<'a> StripUnconfigured<'a> {
319290
/// the syntax of any `cfg_attr` is incorrect.
320291
fn process_cfg_attrs<T: HasAttrs>(&self, node: &mut T) {
321292
node.visit_attrs(|attrs| {
322-
attrs.flat_map_in_place(|attr| self.process_cfg_attr(attr));
293+
attrs.flat_map_in_place(|attr| self.process_cfg_attr(&attr));
323294
});
324295
}
325296

326-
fn process_cfg_attr(&self, attr: Attribute) -> Vec<Attribute> {
327-
if attr.has_name(sym::cfg_attr) { self.expand_cfg_attr(attr, true) } else { vec![attr] }
297+
fn process_cfg_attr(&self, attr: &Attribute) -> Vec<Attribute> {
298+
if attr.has_name(sym::cfg_attr) {
299+
self.expand_cfg_attr(attr, true)
300+
} else {
301+
vec![attr.clone()]
302+
}
328303
}
329304

330305
/// Parse and expand a single `cfg_attr` attribute into a list of attributes
@@ -334,9 +309,9 @@ impl<'a> StripUnconfigured<'a> {
334309
/// Gives a compiler warning when the `cfg_attr` contains no attributes and
335310
/// is in the original source file. Gives a compiler error if the syntax of
336311
/// the attribute is incorrect.
337-
pub(crate) fn expand_cfg_attr(&self, attr: Attribute, recursive: bool) -> Vec<Attribute> {
312+
pub(crate) fn expand_cfg_attr(&self, attr: &Attribute, recursive: bool) -> Vec<Attribute> {
338313
let Some((cfg_predicate, expanded_attrs)) =
339-
rustc_parse::parse_cfg_attr(&attr, &self.sess.parse_sess) else {
314+
rustc_parse::parse_cfg_attr(attr, &self.sess.parse_sess) else {
340315
return vec![];
341316
};
342317

@@ -365,10 +340,10 @@ impl<'a> StripUnconfigured<'a> {
365340
// `#[cfg_attr(false, cfg_attr(true, some_attr))]`.
366341
expanded_attrs
367342
.into_iter()
368-
.flat_map(|item| self.process_cfg_attr(self.expand_cfg_attr_item(&attr, item)))
343+
.flat_map(|item| self.process_cfg_attr(&self.expand_cfg_attr_item(attr, item)))
369344
.collect()
370345
} else {
371-
expanded_attrs.into_iter().map(|item| self.expand_cfg_attr_item(&attr, item)).collect()
346+
expanded_attrs.into_iter().map(|item| self.expand_cfg_attr_item(attr, item)).collect()
372347
}
373348
}
374349

compiler/rustc_expand/src/expand.rs

+12-4
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> {
@@ -1688,7 +1696,7 @@ impl<'a, 'b> InvocationCollector<'a, 'b> {
16881696
res
16891697
}
16901698

1691-
fn expand_cfg_attr(&self, node: &mut impl HasAttrs, attr: ast::Attribute, pos: usize) {
1699+
fn expand_cfg_attr(&self, node: &mut impl HasAttrs, attr: &ast::Attribute, pos: usize) {
16921700
node.visit_attrs(|attrs| {
16931701
// Repeated `insert` calls is inefficient, but the number of
16941702
// insertions is almost always 0 or 1 in practice.
@@ -1712,7 +1720,7 @@ impl<'a, 'b> InvocationCollector<'a, 'b> {
17121720
Default::default()
17131721
}
17141722
sym::cfg_attr => {
1715-
self.expand_cfg_attr(&mut node, attr, pos);
1723+
self.expand_cfg_attr(&mut node, &attr, pos);
17161724
continue;
17171725
}
17181726
_ => {
@@ -1756,11 +1764,11 @@ 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 => {
1763-
self.expand_cfg_attr(node, attr, pos);
1771+
self.expand_cfg_attr(node, &attr, pos);
17641772
continue;
17651773
}
17661774
_ => visit_clobber(node, |node| {

0 commit comments

Comments
 (0)