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:
parent
7367db6fcc
commit
bef1911b15
5 changed files with 72 additions and 57 deletions
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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 */ })
|
||||||
|
|
|
@ -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 */ })
|
||||||
|
|
|
@ -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
|
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue