17
17
//! 5. f! { ... } functions
18
18
//! 6. extern functions
19
19
//! 7. modules + pub use
20
- //! * Use cfg_if! over #[cfg(...)]
21
20
//! * No manual deriving Copy/Clone
22
21
//! * Only one f! per module
22
+ //! * Multiple s! macros are allowed as long as there isn't a duplicate cfg,
23
+ //! whether as a standalone attribute (#[cfg]) or in a cfg_if!
24
+ //! * s! macros should not just have a positive cfg since they should
25
+ //! just go into the relevant file but combined cfgs with all(...) and
26
+ //! any(...) are allowed
23
27
28
+ use std:: collections:: HashMap ;
24
29
use std:: fs;
25
30
use std:: ops:: Deref ;
26
31
use std:: path:: { Path , PathBuf } ;
@@ -42,8 +47,7 @@ pub struct StyleChecker {
42
47
/// Span of the first item encountered in this state to use in help
43
48
/// diagnostic text.
44
49
state_span : Option < Span > ,
45
- // FIXME: see StyleChecker::set_state
46
- _s_macros : usize ,
50
+ seen_s_macro_cfgs : HashMap < String , Span > ,
47
51
/// Span of the first f! macro seen, used to enforce only one f! macro
48
52
/// per module.
49
53
first_f_macro : Option < Span > ,
@@ -167,13 +171,6 @@ impl StyleChecker {
167
171
) ;
168
172
}
169
173
170
- // FIXME(#4109): multiple should be allowed if at least one is `cfg(not) within `cfg_if`.
171
- // For now just disable this and check by hand.
172
- // if self.s_macros == 2 {
173
- // self.s_macros += 1;
174
- // (self.on_err)(line, "multiple s! macros in one module");
175
- // }
176
-
177
174
if self . state != new_state {
178
175
self . state = new_state;
179
176
self . state_span = Some ( span) ;
@@ -182,22 +179,22 @@ impl StyleChecker {
182
179
183
180
/// Visit the items inside the [ExprCfgIf], restoring the state after
184
181
/// each branch.
185
- fn visit_cfg_expr_if ( & mut self , cfg_expr_if : & ExprCfgIf ) {
182
+ fn visit_expr_cfg_if ( & mut self , expr_cfg_if : & ExprCfgIf ) {
186
183
let initial_state = self . state ;
187
184
188
- for item in & cfg_expr_if . then_branch {
185
+ for item in & expr_cfg_if . then_branch {
189
186
self . visit_item ( item) ;
190
187
}
191
188
self . state = initial_state;
192
189
193
- if let Some ( else_branch) = & cfg_expr_if . else_branch {
190
+ if let Some ( else_branch) = & expr_cfg_if . else_branch {
194
191
match else_branch. deref ( ) {
195
192
ExprCfgElse :: Block ( items) => {
196
193
for item in items {
197
194
self . visit_item ( item) ;
198
195
}
199
196
}
200
- ExprCfgElse :: If ( cfg_expr_if ) => self . visit_cfg_expr_if ( & cfg_expr_if ) ,
197
+ ExprCfgElse :: If ( expr_cfg_if ) => self . visit_expr_cfg_if ( & expr_cfg_if ) ,
201
198
}
202
199
}
203
200
self . state = initial_state;
@@ -222,19 +219,7 @@ impl<'ast> Visit<'ast> for StyleChecker {
222
219
fn visit_meta_list ( & mut self , meta_list : & ' ast syn:: MetaList ) {
223
220
let span = meta_list. span ( ) ;
224
221
let meta_str = meta_list. tokens . to_string ( ) ;
225
- if meta_list. path . is_ident ( "cfg" )
226
- && !( meta_str. contains ( "target_endian" ) || meta_str. contains ( "target_arch" ) )
227
- {
228
- self . error (
229
- "cfg_if! over #[cfg]" . to_string ( ) ,
230
- span,
231
- String :: new ( ) ,
232
- (
233
- None ,
234
- "use cfg_if! and submodules instead of #[cfg]" . to_string ( ) ,
235
- ) ,
236
- ) ;
237
- } else if meta_list. path . is_ident ( "derive" )
222
+ if meta_list. path . is_ident ( "derive" )
238
223
&& ( meta_str. contains ( "Copy" ) || meta_str. contains ( "Clone" ) )
239
224
{
240
225
self . error (
@@ -287,18 +272,76 @@ impl<'ast> Visit<'ast> for StyleChecker {
287
272
visit:: visit_item_type ( self , item_type) ;
288
273
}
289
274
275
+ fn visit_item_macro ( & mut self , item_macro : & ' ast syn:: ItemMacro ) {
276
+ if item_macro. mac . path . is_ident ( "s" ) {
277
+ if item_macro. attrs . is_empty ( ) {
278
+ let span = item_macro. span ( ) ;
279
+ match self . seen_s_macro_cfgs . get ( "" ) {
280
+ Some ( seen_span) => {
281
+ self . error (
282
+ "duplicate s! macro" . to_string ( ) ,
283
+ span,
284
+ format ! ( "other s! macro" ) ,
285
+ ( Some ( * seen_span) , "combine the two" . to_string ( ) ) ,
286
+ ) ;
287
+ }
288
+ None => {
289
+ self . seen_s_macro_cfgs . insert ( String :: new ( ) , span) ;
290
+ }
291
+ }
292
+ } else {
293
+ for attr in & item_macro. attrs {
294
+ if let Ok ( meta_list) = attr. meta . require_list ( ) {
295
+ if meta_list. path . is_ident ( "cfg" ) {
296
+ let span = meta_list. span ( ) ;
297
+ let meta_str = meta_list. tokens . to_string ( ) ;
298
+
299
+ match self . seen_s_macro_cfgs . get ( & meta_str) {
300
+ Some ( seen_span) => {
301
+ self . error (
302
+ "duplicate #[cfg] for s! macro" . to_string ( ) ,
303
+ span,
304
+ "duplicated #[cfg]" . to_string ( ) ,
305
+ ( Some ( * seen_span) , "combine the two" . to_string ( ) ) ,
306
+ ) ;
307
+ }
308
+ None => {
309
+ self . seen_s_macro_cfgs . insert ( meta_str. clone ( ) , span) ;
310
+ }
311
+ }
312
+
313
+ if !meta_str. starts_with ( "not" )
314
+ && !meta_str. starts_with ( "any" )
315
+ && !meta_str. starts_with ( "all" )
316
+ {
317
+ self . error (
318
+ "positive #[cfg] for s! macro" . to_string ( ) ,
319
+ span,
320
+ String :: new ( ) ,
321
+ ( None , "move it to the relevant file" . to_string ( ) ) ,
322
+ ) ;
323
+ }
324
+ }
325
+ }
326
+ }
327
+ }
328
+ }
329
+
330
+ visit:: visit_item_macro ( self , item_macro) ;
331
+ }
332
+
290
333
fn visit_macro ( & mut self , mac : & ' ast syn:: Macro ) {
291
334
let span = mac. span ( ) ;
292
335
if mac. path . is_ident ( "cfg_if" ) {
293
- let cfg_expr_if : ExprCfgIf = mac
336
+ let expr_cfg_if : ExprCfgIf = mac
294
337
. parse_body ( )
295
338
. expect ( "cfg_if! should be parsed since it compiled" ) ;
296
339
297
- self . visit_cfg_expr_if ( & cfg_expr_if ) ;
340
+ self . visit_expr_cfg_if ( & expr_cfg_if ) ;
298
341
} else {
299
342
let new_state = if mac. path . is_ident ( "s" ) {
300
- // FIXME: see StyleChecker::set_state
301
- // self.s_macros += 1;
343
+ // multiple macros are allowed if they have proper #[cfg(...)]
344
+ // attributes, see Self::visit_item_macro
302
345
State :: Structs
303
346
} else if mac. path . is_ident ( "s_no_extra_traits" ) {
304
347
// multiple macros of this type are allowed
@@ -362,7 +405,11 @@ impl Parse for ExprCfgIf {
362
405
let then_branch: Vec < syn:: Item > = {
363
406
let mut items = Vec :: new ( ) ;
364
407
while !content. is_empty ( ) {
365
- items. push ( content. parse ( ) ?) ;
408
+ let mut value = content. parse ( ) ?;
409
+ if let syn:: Item :: Macro ( item_macro) = & mut value {
410
+ item_macro. attrs . push ( attr. clone ( ) ) ;
411
+ }
412
+ items. push ( value) ;
366
413
}
367
414
items
368
415
} ;
0 commit comments