11use crate :: util:: check_builtin_macro_attribute;
22
33use 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 } ;
94use 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;
166use rustc_span:: symbol:: sym;
177use rustc_span:: Span ;
18- use smallvec:: SmallVec ;
198
209crate 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- }
0 commit comments