@@ -16,6 +16,12 @@ use std::path::Path;
16
16
17
17
use regex:: { Regex , escape} ;
18
18
19
+ mod version;
20
+ use self :: version:: Version ;
21
+
22
+ const FEATURE_GROUP_START_PREFIX : & str = "// feature group start:" ;
23
+ const FEATURE_GROUP_END_PREFIX : & str = "// feature group end" ;
24
+
19
25
#[ derive( Debug , PartialEq , Clone ) ]
20
26
pub enum Status {
21
27
Stable ,
@@ -37,9 +43,10 @@ impl fmt::Display for Status {
37
43
#[ derive( Debug , Clone ) ]
38
44
pub struct Feature {
39
45
pub level : Status ,
40
- pub since : String ,
46
+ pub since : Option < Version > ,
41
47
pub has_gate_test : bool ,
42
48
pub tracking_issue : Option < u32 > ,
49
+ pub group : Option < String > ,
43
50
}
44
51
45
52
pub type Features = HashMap < String , Feature > ;
@@ -136,14 +143,16 @@ pub fn check(path: &Path, bad: &mut bool, quiet: bool) {
136
143
name,
137
144
"lang" ,
138
145
feature. level,
139
- feature. since) ) ;
146
+ feature. since. as_ref( ) . map_or( "None" . to_owned( ) ,
147
+ |since| since. to_string( ) ) ) ) ;
140
148
}
141
149
for ( name, feature) in lib_features {
142
150
lines. push ( format ! ( "{:<32} {:<8} {:<12} {:<8}" ,
143
151
name,
144
152
"lib" ,
145
153
feature. level,
146
- feature. since) ) ;
154
+ feature. since. as_ref( ) . map_or( "None" . to_owned( ) ,
155
+ |since| since. to_string( ) ) ) ) ;
147
156
}
148
157
149
158
lines. sort ( ) ;
@@ -188,6 +197,8 @@ pub fn collect_lang_features(base_src_path: &Path, bad: &mut bool) -> Features {
188
197
// without one inside `// no tracking issue START` and `// no tracking issue END`.
189
198
let mut next_feature_omits_tracking_issue = false ;
190
199
200
+ let mut next_feature_group = None ;
201
+
191
202
contents. lines ( ) . zip ( 1 ..)
192
203
. filter_map ( |( line, line_number) | {
193
204
let line = line. trim ( ) ;
@@ -205,6 +216,15 @@ pub fn collect_lang_features(base_src_path: &Path, bad: &mut bool) -> Features {
205
216
_ => { }
206
217
}
207
218
219
+ if line. starts_with ( FEATURE_GROUP_START_PREFIX ) {
220
+ let group = line. trim_start_matches ( FEATURE_GROUP_START_PREFIX ) . trim ( ) ;
221
+ next_feature_group = Some ( group. to_owned ( ) ) ;
222
+ return None ;
223
+ } else if line. starts_with ( FEATURE_GROUP_END_PREFIX ) {
224
+ next_feature_group = None ;
225
+ return None ;
226
+ }
227
+
208
228
let mut parts = line. split ( ',' ) ;
209
229
let level = match parts. next ( ) . map ( |l| l. trim ( ) . trim_start_matches ( '(' ) ) {
210
230
Some ( "active" ) => Status :: Unstable ,
@@ -213,7 +233,20 @@ pub fn collect_lang_features(base_src_path: &Path, bad: &mut bool) -> Features {
213
233
_ => return None ,
214
234
} ;
215
235
let name = parts. next ( ) . unwrap ( ) . trim ( ) ;
216
- let since = parts. next ( ) . unwrap ( ) . trim ( ) . trim_matches ( '"' ) ;
236
+ let since_str = parts. next ( ) . unwrap ( ) . trim ( ) . trim_matches ( '"' ) ;
237
+ let since = match since_str. parse ( ) {
238
+ Ok ( since) => Some ( since) ,
239
+ Err ( err) => {
240
+ tidy_error ! (
241
+ bad,
242
+ "libsyntax/feature_gate.rs:{}: failed to parse since: {} ({})" ,
243
+ line_number,
244
+ since_str,
245
+ err,
246
+ ) ;
247
+ None
248
+ }
249
+ } ;
217
250
let issue_str = parts. next ( ) . unwrap ( ) . trim ( ) ;
218
251
let tracking_issue = if issue_str. starts_with ( "None" ) {
219
252
if level == Status :: Unstable && !next_feature_omits_tracking_issue {
@@ -233,9 +266,10 @@ pub fn collect_lang_features(base_src_path: &Path, bad: &mut bool) -> Features {
233
266
Some ( ( name. to_owned ( ) ,
234
267
Feature {
235
268
level,
236
- since : since . to_owned ( ) ,
269
+ since,
237
270
has_gate_test : false ,
238
271
tracking_issue,
272
+ group : next_feature_group. clone ( ) ,
239
273
} ) )
240
274
} )
241
275
. collect ( )
@@ -250,9 +284,10 @@ pub fn collect_lib_features(base_src_path: &Path) -> Features {
250
284
// add it to the set of known library features so we can still generate docs.
251
285
lib_features. insert ( "compiler_builtins_lib" . to_owned ( ) , Feature {
252
286
level : Status :: Unstable ,
253
- since : String :: new ( ) ,
287
+ since : None ,
254
288
has_gate_test : false ,
255
289
tracking_issue : None ,
290
+ group : None ,
256
291
} ) ;
257
292
258
293
map_lib_features ( base_src_path,
@@ -351,12 +386,13 @@ fn map_lib_features(base_src_path: &Path,
351
386
} ;
352
387
let feature = Feature {
353
388
level : Status :: Unstable ,
354
- since : " None" . to_owned ( ) ,
389
+ since : None ,
355
390
has_gate_test : false ,
356
391
// FIXME(#57563): #57563 is now used as a common tracking issue,
357
392
// although we would like to have specific tracking issues for each
358
393
// `rustc_const_unstable` in the future.
359
394
tracking_issue : Some ( 57563 ) ,
395
+ group : None ,
360
396
} ;
361
397
mf ( Ok ( ( feature_name, feature) ) , file, i + 1 ) ;
362
398
continue ;
@@ -372,20 +408,24 @@ fn map_lib_features(base_src_path: &Path,
372
408
Some ( name) => name,
373
409
None => err ! ( "malformed stability attribute" ) ,
374
410
} ;
375
- let since = match find_attr_val ( line, "since" ) {
376
- Some ( name) => name,
411
+ let since = match find_attr_val ( line, "since" ) . map ( |x| x. parse ( ) ) {
412
+ Some ( Ok ( since) ) => Some ( since) ,
413
+ Some ( Err ( _err) ) => {
414
+ err ! ( "malformed since attribute" ) ;
415
+ } ,
377
416
None if level == Status :: Stable => {
378
417
err ! ( "malformed stability attribute" ) ;
379
418
}
380
- None => " None" ,
419
+ None => None ,
381
420
} ;
382
421
let tracking_issue = find_attr_val ( line, "issue" ) . map ( |s| s. parse ( ) . unwrap ( ) ) ;
383
422
384
423
let feature = Feature {
385
424
level,
386
- since : since . to_owned ( ) ,
425
+ since,
387
426
has_gate_test : false ,
388
427
tracking_issue,
428
+ group : None ,
389
429
} ;
390
430
if line. contains ( ']' ) {
391
431
mf ( Ok ( ( feature_name, feature) ) , file, i + 1 ) ;
0 commit comments