10
10
//! * Language features in a group are sorted by feature name.
11
11
12
12
use crate :: walk:: { filter_dirs, walk, walk_many} ;
13
- use std:: collections:: HashMap ;
13
+ use std:: collections:: hash_map :: { Entry , HashMap } ;
14
14
use std:: fmt;
15
15
use std:: fs;
16
16
use std:: num:: NonZeroU32 ;
@@ -280,13 +280,14 @@ fn test_filen_gate(filen_underscore: &str, features: &mut Features) -> bool {
280
280
}
281
281
282
282
pub fn collect_lang_features ( base_compiler_path : & Path , bad : & mut bool ) -> Features {
283
- let mut all = collect_lang_features_in ( base_compiler_path, "active.rs" , bad) ;
284
- all. extend ( collect_lang_features_in ( base_compiler_path, "accepted.rs" , bad) ) ;
285
- all. extend ( collect_lang_features_in ( base_compiler_path, "removed.rs" , bad) ) ;
286
- all
283
+ let mut features = Features :: new ( ) ;
284
+ collect_lang_features_in ( & mut features, base_compiler_path, "active.rs" , bad) ;
285
+ collect_lang_features_in ( & mut features, base_compiler_path, "accepted.rs" , bad) ;
286
+ collect_lang_features_in ( & mut features, base_compiler_path, "removed.rs" , bad) ;
287
+ features
287
288
}
288
289
289
- fn collect_lang_features_in ( base : & Path , file : & str , bad : & mut bool ) -> Features {
290
+ fn collect_lang_features_in ( features : & mut Features , base : & Path , file : & str , bad : & mut bool ) {
290
291
let path = base. join ( "rustc_feature" ) . join ( "src" ) . join ( file) ;
291
292
let contents = t ! ( fs:: read_to_string( & path) ) ;
292
293
@@ -298,135 +299,145 @@ fn collect_lang_features_in(base: &Path, file: &str, bad: &mut bool) -> Features
298
299
let mut in_feature_group = false ;
299
300
let mut prev_names = vec ! [ ] ;
300
301
301
- contents
302
- . lines ( )
303
- . zip ( 1 ..)
304
- . filter_map ( |( line, line_number) | {
305
- let line = line. trim ( ) ;
306
-
307
- // Within -start and -end, the tracking issue can be omitted.
308
- match line {
309
- "// no-tracking-issue-start" => {
310
- next_feature_omits_tracking_issue = true ;
311
- return None ;
312
- }
313
- "// no-tracking-issue-end" => {
314
- next_feature_omits_tracking_issue = false ;
315
- return None ;
316
- }
317
- _ => { }
302
+ let lines = contents. lines ( ) . zip ( 1 ..) ;
303
+ for ( line, line_number) in lines {
304
+ let line = line. trim ( ) ;
305
+
306
+ // Within -start and -end, the tracking issue can be omitted.
307
+ match line {
308
+ "// no-tracking-issue-start" => {
309
+ next_feature_omits_tracking_issue = true ;
310
+ continue ;
318
311
}
312
+ "// no-tracking-issue-end" => {
313
+ next_feature_omits_tracking_issue = false ;
314
+ continue ;
315
+ }
316
+ _ => { }
317
+ }
319
318
320
- if line. starts_with ( FEATURE_GROUP_START_PREFIX ) {
321
- if in_feature_group {
322
- tidy_error ! (
323
- bad,
324
- "{}:{}: \
319
+ if line. starts_with ( FEATURE_GROUP_START_PREFIX ) {
320
+ if in_feature_group {
321
+ tidy_error ! (
322
+ bad,
323
+ "{}:{}: \
325
324
new feature group is started without ending the previous one",
326
- path. display( ) ,
327
- line_number,
328
- ) ;
329
- }
330
-
331
- in_feature_group = true ;
332
- prev_names = vec ! [ ] ;
333
- return None ;
334
- } else if line. starts_with ( FEATURE_GROUP_END_PREFIX ) {
335
- in_feature_group = false ;
336
- prev_names = vec ! [ ] ;
337
- return None ;
325
+ path. display( ) ,
326
+ line_number,
327
+ ) ;
338
328
}
339
329
340
- let mut parts = line. split ( ',' ) ;
341
- let level = match parts. next ( ) . map ( |l| l. trim ( ) . trim_start_matches ( '(' ) ) {
342
- Some ( "active" ) => Status :: Unstable ,
343
- Some ( "incomplete" ) => Status :: Unstable ,
344
- Some ( "removed" ) => Status :: Removed ,
345
- Some ( "accepted" ) => Status :: Stable ,
346
- _ => return None ,
347
- } ;
348
- let name = parts. next ( ) . unwrap ( ) . trim ( ) ;
349
-
350
- let since_str = parts. next ( ) . unwrap ( ) . trim ( ) . trim_matches ( '"' ) ;
351
- let since = match since_str. parse ( ) {
352
- Ok ( since) => Some ( since) ,
353
- Err ( err) => {
354
- tidy_error ! (
355
- bad,
356
- "{}:{}: failed to parse since: {} ({:?})" ,
357
- path. display( ) ,
358
- line_number,
359
- since_str,
360
- err,
361
- ) ;
362
- None
363
- }
364
- } ;
365
- if in_feature_group {
366
- if prev_names. last ( ) > Some ( & name) {
367
- // This assumes the user adds the feature name at the end of the list, as we're
368
- // not looking ahead.
369
- let correct_index = match prev_names. binary_search ( & name) {
370
- Ok ( _) => {
371
- // This only occurs when the feature name has already been declared.
372
- tidy_error ! (
373
- bad,
374
- "{}:{}: duplicate feature {}" ,
375
- path. display( ) ,
376
- line_number,
377
- name,
378
- ) ;
379
- // skip any additional checks for this line
380
- return None ;
381
- }
382
- Err ( index) => index,
383
- } ;
330
+ in_feature_group = true ;
331
+ prev_names = vec ! [ ] ;
332
+ continue ;
333
+ } else if line. starts_with ( FEATURE_GROUP_END_PREFIX ) {
334
+ in_feature_group = false ;
335
+ prev_names = vec ! [ ] ;
336
+ continue ;
337
+ }
384
338
385
- let correct_placement = if correct_index == 0 {
386
- "at the beginning of the feature group" . to_owned ( )
387
- } else if correct_index == prev_names. len ( ) {
388
- // I don't believe this is reachable given the above assumption, but it
389
- // doesn't hurt to be safe.
390
- "at the end of the feature group" . to_owned ( )
391
- } else {
392
- format ! (
393
- "between {} and {}" ,
394
- prev_names[ correct_index - 1 ] ,
395
- prev_names[ correct_index] ,
396
- )
397
- } ;
339
+ let mut parts = line. split ( ',' ) ;
340
+ let level = match parts. next ( ) . map ( |l| l. trim ( ) . trim_start_matches ( '(' ) ) {
341
+ Some ( "active" ) => Status :: Unstable ,
342
+ Some ( "incomplete" ) => Status :: Unstable ,
343
+ Some ( "removed" ) => Status :: Removed ,
344
+ Some ( "accepted" ) => Status :: Stable ,
345
+ _ => continue ,
346
+ } ;
347
+ let name = parts. next ( ) . unwrap ( ) . trim ( ) ;
348
+
349
+ let since_str = parts. next ( ) . unwrap ( ) . trim ( ) . trim_matches ( '"' ) ;
350
+ let since = match since_str. parse ( ) {
351
+ Ok ( since) => Some ( since) ,
352
+ Err ( err) => {
353
+ tidy_error ! (
354
+ bad,
355
+ "{}:{}: failed to parse since: {} ({:?})" ,
356
+ path. display( ) ,
357
+ line_number,
358
+ since_str,
359
+ err,
360
+ ) ;
361
+ None
362
+ }
363
+ } ;
364
+ if in_feature_group {
365
+ if prev_names. last ( ) > Some ( & name) {
366
+ // This assumes the user adds the feature name at the end of the list, as we're
367
+ // not looking ahead.
368
+ let correct_index = match prev_names. binary_search ( & name) {
369
+ Ok ( _) => {
370
+ // This only occurs when the feature name has already been declared.
371
+ tidy_error ! (
372
+ bad,
373
+ "{}:{}: duplicate feature {}" ,
374
+ path. display( ) ,
375
+ line_number,
376
+ name,
377
+ ) ;
378
+ // skip any additional checks for this line
379
+ continue ;
380
+ }
381
+ Err ( index) => index,
382
+ } ;
398
383
399
- tidy_error ! (
400
- bad,
401
- "{}:{}: feature {} is not sorted by feature name (should be {})" ,
402
- path. display( ) ,
403
- line_number,
404
- name,
405
- correct_placement,
406
- ) ;
407
- }
408
- prev_names. push ( name) ;
384
+ let correct_placement = if correct_index == 0 {
385
+ "at the beginning of the feature group" . to_owned ( )
386
+ } else if correct_index == prev_names. len ( ) {
387
+ // I don't believe this is reachable given the above assumption, but it
388
+ // doesn't hurt to be safe.
389
+ "at the end of the feature group" . to_owned ( )
390
+ } else {
391
+ format ! (
392
+ "between {} and {}" ,
393
+ prev_names[ correct_index - 1 ] ,
394
+ prev_names[ correct_index] ,
395
+ )
396
+ } ;
397
+
398
+ tidy_error ! (
399
+ bad,
400
+ "{}:{}: feature {} is not sorted by feature name (should be {})" ,
401
+ path. display( ) ,
402
+ line_number,
403
+ name,
404
+ correct_placement,
405
+ ) ;
409
406
}
407
+ prev_names. push ( name) ;
408
+ }
410
409
411
- let issue_str = parts. next ( ) . unwrap ( ) . trim ( ) ;
412
- let tracking_issue = if issue_str. starts_with ( "None" ) {
413
- if level == Status :: Unstable && !next_feature_omits_tracking_issue {
414
- tidy_error ! (
415
- bad,
416
- "{}:{}: no tracking issue for feature {}" ,
417
- path. display( ) ,
418
- line_number,
419
- name,
420
- ) ;
421
- }
422
- None
423
- } else {
424
- let s = issue_str. split ( '(' ) . nth ( 1 ) . unwrap ( ) . split ( ')' ) . next ( ) . unwrap ( ) ;
425
- Some ( s. parse ( ) . unwrap ( ) )
426
- } ;
427
- Some ( ( name. to_owned ( ) , Feature { level, since, has_gate_test : false , tracking_issue } ) )
428
- } )
429
- . collect ( )
410
+ let issue_str = parts. next ( ) . unwrap ( ) . trim ( ) ;
411
+ let tracking_issue = if issue_str. starts_with ( "None" ) {
412
+ if level == Status :: Unstable && !next_feature_omits_tracking_issue {
413
+ tidy_error ! (
414
+ bad,
415
+ "{}:{}: no tracking issue for feature {}" ,
416
+ path. display( ) ,
417
+ line_number,
418
+ name,
419
+ ) ;
420
+ }
421
+ None
422
+ } else {
423
+ let s = issue_str. split ( '(' ) . nth ( 1 ) . unwrap ( ) . split ( ')' ) . next ( ) . unwrap ( ) ;
424
+ Some ( s. parse ( ) . unwrap ( ) )
425
+ } ;
426
+ match features. entry ( name. to_owned ( ) ) {
427
+ Entry :: Occupied ( e) => {
428
+ tidy_error ! (
429
+ bad,
430
+ "{}:{} feature {name} already specified with status '{}'" ,
431
+ path. display( ) ,
432
+ line_number,
433
+ e. get( ) . level,
434
+ ) ;
435
+ }
436
+ Entry :: Vacant ( e) => {
437
+ e. insert ( Feature { level, since, has_gate_test : false , tracking_issue } ) ;
438
+ }
439
+ }
440
+ }
430
441
}
431
442
432
443
fn get_and_check_lib_features (
0 commit comments