Skip to content

Commit ca40d7d

Browse files
committed
Move cfg_eval stuff back to rustc_expand
1 parent 758c00e commit ca40d7d

File tree

3 files changed

+251
-256
lines changed

3 files changed

+251
-256
lines changed
Lines changed: 1 addition & 253 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,10 @@
11
use crate::util::check_builtin_macro_attribute;
22

33
use rustc_ast as ast;
4-
use rustc_ast::mut_visit::MutVisitor;
5-
use rustc_ast::tokenstream::CanSynthesizeMissingTokens;
6-
use rustc_ast::visit::Visitor;
7-
use rustc_ast::{mut_visit, visit};
8-
use rustc_ast::{AstLike, Attribute};
94
use rustc_expand::base::{Annotatable, ExtCtxt};
10-
use rustc_expand::config::StripUnconfigured;
11-
use rustc_expand::configure;
12-
use rustc_parse::parser::ForceCollect;
13-
use rustc_session::utils::FlattenNonterminals;
14-
15-
use rustc_ast::ptr::P;
5+
use rustc_expand::config::cfg_eval;
166
use rustc_span::symbol::sym;
177
use rustc_span::Span;
18-
use smallvec::SmallVec;
198

209
crate fn expand(
2110
ecx: &mut ExtCtxt<'_>,
@@ -26,244 +15,3 @@ crate fn expand(
2615
check_builtin_macro_attribute(ecx, meta_item, sym::cfg_eval);
2716
cfg_eval(ecx, annotatable)
2817
}
29-
30-
crate fn cfg_eval(ecx: &ExtCtxt<'_>, annotatable: Annotatable) -> Vec<Annotatable> {
31-
let mut visitor = CfgEval {
32-
cfg: &mut StripUnconfigured {
33-
sess: ecx.sess,
34-
features: ecx.ecfg.features,
35-
config_tokens: true,
36-
},
37-
};
38-
let annotatable = visitor.configure_annotatable(annotatable);
39-
vec![annotatable]
40-
}
41-
42-
struct CfgEval<'a, 'b> {
43-
cfg: &'a mut StripUnconfigured<'b>,
44-
}
45-
46-
fn flat_map_annotatable(vis: &mut impl MutVisitor, annotatable: Annotatable) -> Annotatable {
47-
// Since the item itself has already been configured by the InvocationCollector,
48-
// we know that fold result vector will contain exactly one element
49-
match annotatable {
50-
Annotatable::Item(item) => Annotatable::Item(vis.flat_map_item(item).pop().unwrap()),
51-
Annotatable::TraitItem(item) => {
52-
Annotatable::TraitItem(vis.flat_map_trait_item(item).pop().unwrap())
53-
}
54-
Annotatable::ImplItem(item) => {
55-
Annotatable::ImplItem(vis.flat_map_impl_item(item).pop().unwrap())
56-
}
57-
Annotatable::ForeignItem(item) => {
58-
Annotatable::ForeignItem(vis.flat_map_foreign_item(item).pop().unwrap())
59-
}
60-
Annotatable::Stmt(stmt) => {
61-
Annotatable::Stmt(stmt.map(|stmt| vis.flat_map_stmt(stmt).pop().unwrap()))
62-
}
63-
Annotatable::Expr(mut expr) => Annotatable::Expr({
64-
vis.visit_expr(&mut expr);
65-
expr
66-
}),
67-
Annotatable::Arm(arm) => Annotatable::Arm(vis.flat_map_arm(arm).pop().unwrap()),
68-
Annotatable::ExprField(field) => {
69-
Annotatable::ExprField(vis.flat_map_expr_field(field).pop().unwrap())
70-
}
71-
Annotatable::PatField(fp) => {
72-
Annotatable::PatField(vis.flat_map_pat_field(fp).pop().unwrap())
73-
}
74-
Annotatable::GenericParam(param) => {
75-
Annotatable::GenericParam(vis.flat_map_generic_param(param).pop().unwrap())
76-
}
77-
Annotatable::Param(param) => Annotatable::Param(vis.flat_map_param(param).pop().unwrap()),
78-
Annotatable::FieldDef(sf) => {
79-
Annotatable::FieldDef(vis.flat_map_field_def(sf).pop().unwrap())
80-
}
81-
Annotatable::Variant(v) => Annotatable::Variant(vis.flat_map_variant(v).pop().unwrap()),
82-
}
83-
}
84-
85-
struct CfgFinder {
86-
has_cfg_or_cfg_attr: bool,
87-
}
88-
89-
impl CfgFinder {
90-
fn has_cfg_or_cfg_attr(annotatable: &Annotatable) -> bool {
91-
let mut finder = CfgFinder { has_cfg_or_cfg_attr: false };
92-
match annotatable {
93-
Annotatable::Item(item) => finder.visit_item(&item),
94-
Annotatable::TraitItem(item) => finder.visit_assoc_item(&item, visit::AssocCtxt::Trait),
95-
Annotatable::ImplItem(item) => finder.visit_assoc_item(&item, visit::AssocCtxt::Impl),
96-
Annotatable::ForeignItem(item) => finder.visit_foreign_item(&item),
97-
Annotatable::Stmt(stmt) => finder.visit_stmt(&stmt),
98-
Annotatable::Expr(expr) => finder.visit_expr(&expr),
99-
Annotatable::Arm(arm) => finder.visit_arm(&arm),
100-
Annotatable::ExprField(field) => finder.visit_expr_field(&field),
101-
Annotatable::PatField(field) => finder.visit_pat_field(&field),
102-
Annotatable::GenericParam(param) => finder.visit_generic_param(&param),
103-
Annotatable::Param(param) => finder.visit_param(&param),
104-
Annotatable::FieldDef(field) => finder.visit_field_def(&field),
105-
Annotatable::Variant(variant) => finder.visit_variant(&variant),
106-
};
107-
finder.has_cfg_or_cfg_attr
108-
}
109-
}
110-
111-
impl<'ast> visit::Visitor<'ast> for CfgFinder {
112-
fn visit_attribute(&mut self, attr: &'ast Attribute) {
113-
// We want short-circuiting behavior, so don't use the '|=' operator.
114-
self.has_cfg_or_cfg_attr = self.has_cfg_or_cfg_attr
115-
|| attr
116-
.ident()
117-
.map_or(false, |ident| ident.name == sym::cfg || ident.name == sym::cfg_attr);
118-
}
119-
}
120-
121-
impl CfgEval<'_, '_> {
122-
fn configure<T: AstLike>(&mut self, node: T) -> Option<T> {
123-
self.cfg.configure(node)
124-
}
125-
126-
pub fn configure_annotatable(&mut self, mut annotatable: Annotatable) -> Annotatable {
127-
// Tokenizing and re-parsing the `Annotatable` can have a significant
128-
// performance impact, so try to avoid it if possible
129-
if !CfgFinder::has_cfg_or_cfg_attr(&annotatable) {
130-
return annotatable;
131-
}
132-
133-
// The majority of parsed attribute targets will never need to have early cfg-expansion
134-
// run (e.g. they are not part of a `#[derive]` or `#[cfg_eval]` macro inoput).
135-
// Therefore, we normally do not capture the necessary information about `#[cfg]`
136-
// and `#[cfg_attr]` attributes during parsing.
137-
//
138-
// Therefore, when we actually *do* run early cfg-expansion, we need to tokenize
139-
// and re-parse the attribute target, this time capturing information about
140-
// the location of `#[cfg]` and `#[cfg_attr]` in the token stream. The tokenization
141-
// process is lossless, so this process is invisible to proc-macros.
142-
143-
// FIXME - get rid of this clone
144-
let nt = annotatable.clone().into_nonterminal();
145-
146-
let mut orig_tokens = rustc_parse::nt_to_tokenstream(
147-
&nt,
148-
&self.cfg.sess.parse_sess,
149-
CanSynthesizeMissingTokens::No,
150-
);
151-
152-
// 'Flatten' all nonterminals (i.e. `TokenKind::Interpolated`)
153-
// to `None`-delimited groups containing the corresponding tokens. This
154-
// is normally delayed until the proc-macro server actually needs to
155-
// provide a `TokenKind::Interpolated` to a proc-macro. We do this earlier,
156-
// so that we can handle cases like:
157-
//
158-
// ```rust
159-
// #[cfg_eval] #[cfg] $item
160-
//```
161-
//
162-
// where `$item` is `#[cfg_attr] struct Foo {}`. We want to make
163-
// sure to evaluate *all* `#[cfg]` and `#[cfg_attr]` attributes - the simplest
164-
// way to do this is to do a single parse of a stream without any nonterminals.
165-
let mut flatten = FlattenNonterminals {
166-
nt_to_tokenstream: rustc_parse::nt_to_tokenstream,
167-
parse_sess: &self.cfg.sess.parse_sess,
168-
synthesize_tokens: CanSynthesizeMissingTokens::No,
169-
};
170-
orig_tokens = flatten.process_token_stream(orig_tokens);
171-
172-
// Re-parse the tokens, setting the `capture_cfg` flag to save extra information
173-
// to the captured `AttrAnnotatedTokenStream` (specifically, we capture
174-
// `AttrAnnotatedTokenTree::AttributesData` for all occurences of `#[cfg]` and `#[cfg_attr]`)
175-
let mut parser =
176-
rustc_parse::stream_to_parser(&self.cfg.sess.parse_sess, orig_tokens, None);
177-
parser.capture_cfg = true;
178-
annotatable = match annotatable {
179-
Annotatable::Item(_) => {
180-
Annotatable::Item(parser.parse_item(ForceCollect::Yes).unwrap().unwrap())
181-
}
182-
Annotatable::TraitItem(_) => Annotatable::TraitItem(
183-
parser.parse_trait_item(ForceCollect::Yes).unwrap().unwrap().unwrap(),
184-
),
185-
Annotatable::ImplItem(_) => Annotatable::ImplItem(
186-
parser.parse_impl_item(ForceCollect::Yes).unwrap().unwrap().unwrap(),
187-
),
188-
Annotatable::ForeignItem(_) => Annotatable::ForeignItem(
189-
parser.parse_foreign_item(ForceCollect::Yes).unwrap().unwrap().unwrap(),
190-
),
191-
Annotatable::Stmt(_) => {
192-
Annotatable::Stmt(P(parser.parse_stmt(ForceCollect::Yes).unwrap().unwrap()))
193-
}
194-
Annotatable::Expr(_) => Annotatable::Expr(parser.parse_expr_force_collect().unwrap()),
195-
_ => unreachable!(),
196-
};
197-
198-
// Now that we have our re-parsed `AttrAnnotatedTokenStream`, recursively configuring
199-
// our attribute target will correctly the tokens as well.
200-
flat_map_annotatable(self, annotatable)
201-
}
202-
}
203-
204-
impl MutVisitor for CfgEval<'_, '_> {
205-
fn visit_expr(&mut self, expr: &mut P<ast::Expr>) {
206-
self.cfg.configure_expr(expr);
207-
mut_visit::noop_visit_expr(expr, self);
208-
}
209-
210-
fn filter_map_expr(&mut self, expr: P<ast::Expr>) -> Option<P<ast::Expr>> {
211-
let mut expr = configure!(self, expr);
212-
mut_visit::noop_visit_expr(&mut expr, self);
213-
Some(expr)
214-
}
215-
216-
fn flat_map_generic_param(
217-
&mut self,
218-
param: ast::GenericParam,
219-
) -> SmallVec<[ast::GenericParam; 1]> {
220-
mut_visit::noop_flat_map_generic_param(configure!(self, param), self)
221-
}
222-
223-
fn flat_map_stmt(&mut self, stmt: ast::Stmt) -> SmallVec<[ast::Stmt; 1]> {
224-
mut_visit::noop_flat_map_stmt(configure!(self, stmt), self)
225-
}
226-
227-
fn flat_map_item(&mut self, item: P<ast::Item>) -> SmallVec<[P<ast::Item>; 1]> {
228-
mut_visit::noop_flat_map_item(configure!(self, item), self)
229-
}
230-
231-
fn flat_map_impl_item(&mut self, item: P<ast::AssocItem>) -> SmallVec<[P<ast::AssocItem>; 1]> {
232-
mut_visit::noop_flat_map_assoc_item(configure!(self, item), self)
233-
}
234-
235-
fn flat_map_trait_item(&mut self, item: P<ast::AssocItem>) -> SmallVec<[P<ast::AssocItem>; 1]> {
236-
mut_visit::noop_flat_map_assoc_item(configure!(self, item), self)
237-
}
238-
239-
fn flat_map_foreign_item(
240-
&mut self,
241-
foreign_item: P<ast::ForeignItem>,
242-
) -> SmallVec<[P<ast::ForeignItem>; 1]> {
243-
mut_visit::noop_flat_map_foreign_item(configure!(self, foreign_item), self)
244-
}
245-
246-
fn flat_map_arm(&mut self, arm: ast::Arm) -> SmallVec<[ast::Arm; 1]> {
247-
mut_visit::noop_flat_map_arm(configure!(self, arm), self)
248-
}
249-
250-
fn flat_map_expr_field(&mut self, field: ast::ExprField) -> SmallVec<[ast::ExprField; 1]> {
251-
mut_visit::noop_flat_map_expr_field(configure!(self, field), self)
252-
}
253-
254-
fn flat_map_pat_field(&mut self, fp: ast::PatField) -> SmallVec<[ast::PatField; 1]> {
255-
mut_visit::noop_flat_map_pat_field(configure!(self, fp), self)
256-
}
257-
258-
fn flat_map_param(&mut self, p: ast::Param) -> SmallVec<[ast::Param; 1]> {
259-
mut_visit::noop_flat_map_param(configure!(self, p), self)
260-
}
261-
262-
fn flat_map_field_def(&mut self, sf: ast::FieldDef) -> SmallVec<[ast::FieldDef; 1]> {
263-
mut_visit::noop_flat_map_field_def(configure!(self, sf), self)
264-
}
265-
266-
fn flat_map_variant(&mut self, variant: ast::Variant) -> SmallVec<[ast::Variant; 1]> {
267-
mut_visit::noop_flat_map_variant(configure!(self, variant), self)
268-
}
269-
}

compiler/rustc_builtin_macros/src/derive.rs

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,7 @@
1-
use crate::cfg_eval::cfg_eval;
2-
31
use rustc_ast::{self as ast, attr, token, ItemKind, MetaItemKind, NestedMetaItem, StmtKind};
42
use rustc_errors::{struct_span_err, Applicability};
53
use rustc_expand::base::{Annotatable, ExpandResult, ExtCtxt, Indeterminate, MultiItemModifier};
4+
use rustc_expand::config::cfg_eval;
65
use rustc_feature::AttributeTemplate;
76
use rustc_parse::validate_attr;
87
use rustc_session::Session;

0 commit comments

Comments
 (0)