1
Fork 0

tidy/features: fix checking of lang features

Removes the `STATUSES` static which duplicates truth from the pattern
match in `collect_lang_features`.

Fixes existing duplicates by renaming:
- never_type{,_impls} on `impl`s on `!`
- concat_idents{,_macro} on `macro_rules! concat_idents`

Fixes #37013.
This commit is contained in:
Tamir Duberstein 2016-10-14 18:14:29 -04:00
parent 7367db6fcc
commit bef1911b15
No known key found for this signature in database
GPG key ID: 1C1E98CC8E17BB89
5 changed files with 72 additions and 57 deletions

View file

@ -706,24 +706,24 @@ mod impls {
ord_impl! { char usize u8 u16 u32 u64 isize i8 i16 i32 i64 } ord_impl! { char usize u8 u16 u32 u64 isize i8 i16 i32 i64 }
#[unstable(feature = "never_type", issue = "35121")] #[unstable(feature = "never_type_impls", issue = "35121")]
impl PartialEq for ! { impl PartialEq for ! {
fn eq(&self, _: &!) -> bool { fn eq(&self, _: &!) -> bool {
*self *self
} }
} }
#[unstable(feature = "never_type", issue = "35121")] #[unstable(feature = "never_type_impls", issue = "35121")]
impl Eq for ! {} impl Eq for ! {}
#[unstable(feature = "never_type", issue = "35121")] #[unstable(feature = "never_type_impls", issue = "35121")]
impl PartialOrd for ! { impl PartialOrd for ! {
fn partial_cmp(&self, _: &!) -> Option<Ordering> { fn partial_cmp(&self, _: &!) -> Option<Ordering> {
*self *self
} }
} }
#[unstable(feature = "never_type", issue = "35121")] #[unstable(feature = "never_type_impls", issue = "35121")]
impl Ord for ! { impl Ord for ! {
fn cmp(&self, _: &!) -> Ordering { fn cmp(&self, _: &!) -> Ordering {
*self *self

View file

@ -1356,14 +1356,14 @@ macro_rules! fmt_refs {
fmt_refs! { Debug, Display, Octal, Binary, LowerHex, UpperHex, LowerExp, UpperExp } fmt_refs! { Debug, Display, Octal, Binary, LowerHex, UpperHex, LowerExp, UpperExp }
#[unstable(feature = "never_type", issue = "35121")] #[unstable(feature = "never_type_impls", issue = "35121")]
impl Debug for ! { impl Debug for ! {
fn fmt(&self, _: &mut Formatter) -> Result { fn fmt(&self, _: &mut Formatter) -> Result {
*self *self
} }
} }
#[unstable(feature = "never_type", issue = "35121")] #[unstable(feature = "never_type_impls", issue = "35121")]
impl Display for ! { impl Display for ! {
fn fmt(&self, _: &mut Formatter) -> Result { fn fmt(&self, _: &mut Formatter) -> Result {
*self *self

View file

@ -553,7 +553,7 @@ pub mod builtin {
/// For more information, see the documentation for [`std::concat_idents!`]. /// For more information, see the documentation for [`std::concat_idents!`].
/// ///
/// [`std::concat_idents!`]: ../std/macro.concat_idents.html /// [`std::concat_idents!`]: ../std/macro.concat_idents.html
#[unstable(feature = "concat_idents", issue = "29599")] #[unstable(feature = "concat_idents_macro", issue = "29599")]
#[macro_export] #[macro_export]
macro_rules! concat_idents { macro_rules! concat_idents {
($($e:ident),*) => ({ /* compiler built-in */ }) ($($e:ident),*) => ({ /* compiler built-in */ })

View file

@ -286,7 +286,7 @@ pub mod builtin {
/// // fn concat_idents!(new, fun, name) { } // not usable in this way! /// // fn concat_idents!(new, fun, name) { } // not usable in this way!
/// # } /// # }
/// ``` /// ```
#[unstable(feature = "concat_idents", issue = "29599")] #[unstable(feature = "concat_idents_macro", issue = "29599")]
#[macro_export] #[macro_export]
macro_rules! concat_idents { macro_rules! concat_idents {
($($e:ident),*) => ({ /* compiler built-in */ }) ($($e:ident),*) => ({ /* compiler built-in */ })

View file

@ -18,27 +18,42 @@
//! * Library features have at most one `since` value //! * Library features have at most one `since` value
use std::collections::HashMap; use std::collections::HashMap;
use std::fmt;
use std::fs::File; use std::fs::File;
use std::io::prelude::*; use std::io::prelude::*;
use std::path::Path; use std::path::Path;
const STATUSES: &'static [&'static str] = &[ #[derive(PartialEq)]
"Active", "Deprecated", "Removed", "Accepted", enum Status {
]; Stable,
Unstable,
}
impl fmt::Display for Status {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
let as_str = match *self {
Status::Stable => "stable",
Status::Unstable => "unstable",
};
fmt::Display::fmt(as_str, f)
}
}
struct Feature { struct Feature {
name: String, name: String,
level: Status,
since: String, since: String,
status: String,
} }
struct LibFeature { struct LibFeature {
level: String, level: Status,
since: String, since: String,
} }
pub fn check(path: &Path, bad: &mut bool) { pub fn check(path: &Path, bad: &mut bool) {
let features = collect_lang_features(&path.join("libsyntax/feature_gate.rs")); let features = collect_lang_features(&path.join("libsyntax/feature_gate.rs"));
assert!(!features.is_empty());
let mut lib_features = HashMap::<String, LibFeature>::new(); let mut lib_features = HashMap::<String, LibFeature>::new();
let mut contents = String::new(); let mut contents = String::new();
@ -48,7 +63,7 @@ pub fn check(path: &Path, bad: &mut bool) {
let filename = file.file_name().unwrap().to_string_lossy(); let filename = file.file_name().unwrap().to_string_lossy();
if !filename.ends_with(".rs") || filename == "features.rs" || if !filename.ends_with(".rs") || filename == "features.rs" ||
filename == "diagnostic_list.rs" { filename == "diagnostic_list.rs" {
return return;
} }
contents.truncate(0); contents.truncate(0);
@ -60,24 +75,24 @@ pub fn check(path: &Path, bad: &mut bool) {
*bad = true; *bad = true;
}; };
let level = if line.contains("[unstable(") { let level = if line.contains("[unstable(") {
"unstable" Status::Unstable
} else if line.contains("[stable(") { } else if line.contains("[stable(") {
"stable" Status::Stable
} else { } else {
continue continue;
}; };
let feature_name = match find_attr_val(line, "feature") { let feature_name = match find_attr_val(line, "feature") {
Some(name) => name, Some(name) => name,
None => { None => {
err("malformed stability attribute"); err("malformed stability attribute");
continue continue;
} }
}; };
let since = match find_attr_val(line, "since") { let since = match find_attr_val(line, "since") {
Some(name) => name, Some(name) => name,
None if level == "stable" => { None if level == Status::Stable => {
err("malformed stability attribute"); err("malformed stability attribute");
continue continue;
} }
None => "None", None => "None",
}; };
@ -92,27 +107,34 @@ pub fn check(path: &Path, bad: &mut bool) {
if s.since != since { if s.since != since {
err("different `since` than before"); err("different `since` than before");
} }
continue continue;
} }
lib_features.insert(feature_name.to_owned(), LibFeature { lib_features.insert(feature_name.to_owned(),
level: level.to_owned(), LibFeature {
since: since.to_owned(), level: level,
}); since: since.to_owned(),
});
} }
}); });
if *bad { if *bad {
return return;
} }
let mut lines = Vec::new(); let mut lines = Vec::new();
for feature in features { for feature in features {
lines.push(format!("{:<32} {:<8} {:<12} {:<8}", lines.push(format!("{:<32} {:<8} {:<12} {:<8}",
feature.name, "lang", feature.status, feature.since)); feature.name,
"lang",
feature.level,
feature.since));
} }
for (name, feature) in lib_features { for (name, feature) in lib_features {
lines.push(format!("{:<32} {:<8} {:<12} {:<8}", lines.push(format!("{:<32} {:<8} {:<12} {:<8}",
name, "lib", feature.level, feature.since)); name,
"lib",
feature.level,
feature.since));
} }
lines.sort(); lines.sort();
@ -122,39 +144,32 @@ pub fn check(path: &Path, bad: &mut bool) {
} }
fn find_attr_val<'a>(line: &'a str, attr: &str) -> Option<&'a str> { fn find_attr_val<'a>(line: &'a str, attr: &str) -> Option<&'a str> {
line.find(attr).and_then(|i| { line.find(attr)
line[i..].find("\"").map(|j| i + j + 1) .and_then(|i| line[i..].find('"').map(|j| i + j + 1))
}).and_then(|i| { .and_then(|i| line[i..].find('"').map(|j| (i, i + j)))
line[i..].find("\"").map(|j| (i, i + j)) .map(|(i, j)| &line[i..j])
}).map(|(i, j)| {
&line[i..j]
})
} }
fn collect_lang_features(path: &Path) -> Vec<Feature> { fn collect_lang_features(path: &Path) -> Vec<Feature> {
let mut contents = String::new(); let mut contents = String::new();
t!(t!(File::open(path)).read_to_string(&mut contents)); t!(t!(File::open(path)).read_to_string(&mut contents));
let mut features = Vec::new(); contents.lines()
for line in contents.lines().map(|l| l.trim()) { .filter_map(|line| {
if !STATUSES.iter().any(|s| line.starts_with(&format!("({}", s))) { let mut parts = line.trim().split(",");
continue let level = match parts.next().map(|l| l.trim().trim_left_matches('(')) {
} Some("active") => Status::Unstable,
let mut parts = line.split(","); Some("removed") => Status::Unstable,
let status = match &parts.next().unwrap().trim().replace("(", "")[..] { Some("accepted") => Status::Stable,
"active" => "unstable", _ => return None,
"removed" => "unstable", };
"accepted" => "stable", let name = parts.next().unwrap().trim();
s => panic!("unknown status: {}", s), let since = parts.next().unwrap().trim().trim_matches('"');
}; Some(Feature {
let name = parts.next().unwrap().trim().to_owned(); name: name.to_owned(),
let since = parts.next().unwrap().trim().replace("\"", ""); level: level,
since: since.to_owned(),
features.push(Feature { })
name: name, })
since: since, .collect()
status: status.to_owned(),
});
}
return features
} }