@@ -16,6 +16,12 @@ use std::path::Path;
1616
1717use regex:: { Regex , escape} ;
1818
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+
1925#[ derive( Debug , PartialEq , Clone ) ]
2026pub enum Status {
2127 Stable ,
@@ -37,9 +43,10 @@ impl fmt::Display for Status {
3743#[ derive( Debug , Clone ) ]
3844pub struct Feature {
3945 pub level : Status ,
40- pub since : String ,
46+ pub since : Option < Version > ,
4147 pub has_gate_test : bool ,
4248 pub tracking_issue : Option < u32 > ,
49+ pub group : Option < String > ,
4350}
4451
4552pub type Features = HashMap < String , Feature > ;
@@ -136,14 +143,16 @@ pub fn check(path: &Path, bad: &mut bool, quiet: bool) {
136143 name,
137144 "lang" ,
138145 feature. level,
139- feature. since) ) ;
146+ feature. since. as_ref( ) . map_or( "None" . to_owned( ) ,
147+ |since| since. to_string( ) ) ) ) ;
140148 }
141149 for ( name, feature) in lib_features {
142150 lines. push ( format ! ( "{:<32} {:<8} {:<12} {:<8}" ,
143151 name,
144152 "lib" ,
145153 feature. level,
146- feature. since) ) ;
154+ feature. since. as_ref( ) . map_or( "None" . to_owned( ) ,
155+ |since| since. to_string( ) ) ) ) ;
147156 }
148157
149158 lines. sort ( ) ;
@@ -188,6 +197,8 @@ pub fn collect_lang_features(base_src_path: &Path, bad: &mut bool) -> Features {
188197 // without one inside `// no tracking issue START` and `// no tracking issue END`.
189198 let mut next_feature_omits_tracking_issue = false ;
190199
200+ let mut next_feature_group = None ;
201+
191202 contents. lines ( ) . zip ( 1 ..)
192203 . filter_map ( |( line, line_number) | {
193204 let line = line. trim ( ) ;
@@ -205,6 +216,15 @@ pub fn collect_lang_features(base_src_path: &Path, bad: &mut bool) -> Features {
205216 _ => { }
206217 }
207218
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+
208228 let mut parts = line. split ( ',' ) ;
209229 let level = match parts. next ( ) . map ( |l| l. trim ( ) . trim_start_matches ( '(' ) ) {
210230 Some ( "active" ) => Status :: Unstable ,
@@ -213,7 +233,20 @@ pub fn collect_lang_features(base_src_path: &Path, bad: &mut bool) -> Features {
213233 _ => return None ,
214234 } ;
215235 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+ } ;
217250 let issue_str = parts. next ( ) . unwrap ( ) . trim ( ) ;
218251 let tracking_issue = if issue_str. starts_with ( "None" ) {
219252 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 {
233266 Some ( ( name. to_owned ( ) ,
234267 Feature {
235268 level,
236- since : since . to_owned ( ) ,
269+ since,
237270 has_gate_test : false ,
238271 tracking_issue,
272+ group : next_feature_group. clone ( ) ,
239273 } ) )
240274 } )
241275 . collect ( )
@@ -250,9 +284,10 @@ pub fn collect_lib_features(base_src_path: &Path) -> Features {
250284 // add it to the set of known library features so we can still generate docs.
251285 lib_features. insert ( "compiler_builtins_lib" . to_owned ( ) , Feature {
252286 level : Status :: Unstable ,
253- since : String :: new ( ) ,
287+ since : None ,
254288 has_gate_test : false ,
255289 tracking_issue : None ,
290+ group : None ,
256291 } ) ;
257292
258293 map_lib_features ( base_src_path,
@@ -351,12 +386,13 @@ fn map_lib_features(base_src_path: &Path,
351386 } ;
352387 let feature = Feature {
353388 level : Status :: Unstable ,
354- since : " None" . to_owned ( ) ,
389+ since : None ,
355390 has_gate_test : false ,
356391 // FIXME(#57563): #57563 is now used as a common tracking issue,
357392 // although we would like to have specific tracking issues for each
358393 // `rustc_const_unstable` in the future.
359394 tracking_issue : Some ( 57563 ) ,
395+ group : None ,
360396 } ;
361397 mf ( Ok ( ( feature_name, feature) ) , file, i + 1 ) ;
362398 continue ;
@@ -372,20 +408,24 @@ fn map_lib_features(base_src_path: &Path,
372408 Some ( name) => name,
373409 None => err ! ( "malformed stability attribute" ) ,
374410 } ;
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+ } ,
377416 None if level == Status :: Stable => {
378417 err ! ( "malformed stability attribute" ) ;
379418 }
380- None => " None" ,
419+ None => None ,
381420 } ;
382421 let tracking_issue = find_attr_val ( line, "issue" ) . map ( |s| s. parse ( ) . unwrap ( ) ) ;
383422
384423 let feature = Feature {
385424 level,
386- since : since . to_owned ( ) ,
425+ since,
387426 has_gate_test : false ,
388427 tracking_issue,
428+ group : None ,
389429 } ;
390430 if line. contains ( ']' ) {
391431 mf ( Ok ( ( feature_name, feature) ) , file, i + 1 ) ;
0 commit comments