Auto merge of #38914 - est31:tidy-gate-tests, r=nikomatsakis
Make tidy check for lang gate tests Add gate tests to the checks that tidy performs. Excerpt from the commit message of the main commit: Require compile-fail tests for new lang features Its non trivial to test lang feature gates, and people forget to add such tests. So we extend the features lint of the tidy tool to ensure that all new lang features contain a new compile-fail test. Of course, one could drop this requirement and just grep all tests in run-pass for #![feature(abc)] and then run this test again, removing the mention, requiring that it fails. But this only tests for the existence of a compilation failure. Manual tests ensure that also the correct lines spawn the error, and also test the actual error message. For library features, it makes no sense to require such a test, as here code is used that is generic for all library features. The tidy lint extension now checks the compile-fail test suite for occurences of "gate-test-X" where X is a feature. Alternatively, it also accepts file names with the form "feature-gate-X.rs". If a lang feature is found that has no such check, we emit a tidy error. I've applied the markings to all tests I could find in the test suite. I left a small (20 elements) whitelist of features that right now have no gate test, or where I couldn't find one. Once this PR gets merged, I'd like to close issue #22820 and open a new one on suggestion of @nikomatsakis to track the removal of all elements from that whitelist (already have a draft). Writing such a small test can be a good opportunity for a first contribution, so I won't touch it (let others have the fun xD). cc @brson , @pnkfelix (they both discussed about this in the issue linked above).
This commit is contained in:
commit
6fe23719fe
53 changed files with 225 additions and 20 deletions
|
@ -45,6 +45,10 @@ whole, instead of just a few lines inside the test.
|
|||
* `should-fail` indicates that the test should fail; used for "meta testing",
|
||||
where we test the compiletest program itself to check that it will generate
|
||||
errors in appropriate scenarios. This header is ignored for pretty-printer tests.
|
||||
* `gate-test-X` where `X` is a feature marks the test as "gate test" for feature X.
|
||||
Such tests are supposed to ensure that the compiler errors when usage of a gated
|
||||
feature is attempted without the proper `#![feature(X)]` tag.
|
||||
Each unstable lang feature is required to have a gate test.
|
||||
|
||||
## Revisions
|
||||
|
||||
|
|
|
@ -8,6 +8,8 @@
|
|||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
// gate-test-asm
|
||||
|
||||
fn main() {
|
||||
unsafe {
|
||||
asm!(""); //~ ERROR inline assembly is not stable enough
|
||||
|
|
|
@ -8,6 +8,8 @@
|
|||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
// gate-test-asm
|
||||
|
||||
fn main() {
|
||||
unsafe {
|
||||
println!("{}", asm!("")); //~ ERROR inline assembly is not stable
|
||||
|
|
|
@ -16,6 +16,8 @@
|
|||
// using `rustc_attrs` feature. There is a separate compile-fail/ test
|
||||
// ensuring that the attribute feature-gating works in this context.)
|
||||
|
||||
// gate-test-generic_param_attrs
|
||||
|
||||
#![feature(rustc_attrs)]
|
||||
#![allow(dead_code)]
|
||||
|
||||
|
|
|
@ -10,6 +10,8 @@
|
|||
|
||||
// Verifies all possible restrictions for statics values.
|
||||
|
||||
// gate-test-drop_types_in_const
|
||||
|
||||
#![feature(box_syntax)]
|
||||
|
||||
use std::marker;
|
||||
|
|
|
@ -8,6 +8,8 @@
|
|||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
// gate-test-concat_idents
|
||||
|
||||
const XY_1: i32 = 10;
|
||||
|
||||
fn main() {
|
||||
|
|
|
@ -8,6 +8,8 @@
|
|||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
// gate-test-concat_idents
|
||||
|
||||
const XY_1: i32 = 10;
|
||||
|
||||
fn main() {
|
||||
|
|
|
@ -8,6 +8,8 @@
|
|||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
// gate-test-const_fn
|
||||
|
||||
// Test use of const fn without feature gate.
|
||||
|
||||
const fn foo() -> usize { 0 } //~ ERROR const fn is unstable
|
||||
|
|
|
@ -8,6 +8,10 @@
|
|||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
// gate-test-intrinsics
|
||||
// gate-test-platform_intrinsics
|
||||
// gate-test-abi_vectorcall
|
||||
|
||||
// Functions
|
||||
extern "rust-intrinsic" fn f1() {} //~ ERROR intrinsics are subject to change
|
||||
extern "platform-intrinsic" fn f2() {} //~ ERROR platform intrinsics are experimental
|
||||
|
|
|
@ -8,6 +8,8 @@
|
|||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
// gate-test-advanced_slice_patterns
|
||||
|
||||
#![feature(slice_patterns)]
|
||||
|
||||
fn main() {
|
||||
|
|
|
@ -8,6 +8,8 @@
|
|||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
// gate-test-allow_internal_unstable
|
||||
|
||||
macro_rules! bar {
|
||||
() => {
|
||||
// more layers don't help:
|
||||
|
|
|
@ -8,6 +8,8 @@
|
|||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
// gate-test-associated_type_defaults
|
||||
|
||||
trait Foo {
|
||||
type Bar = u8; //~ ERROR associated type defaults are unstable
|
||||
}
|
||||
|
|
|
@ -8,6 +8,8 @@
|
|||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
// gate-test-box_syntax
|
||||
|
||||
// Check that `box EXPR` is feature-gated.
|
||||
//
|
||||
// See also feature-gate-placement-expr.rs
|
||||
|
|
|
@ -8,6 +8,8 @@
|
|||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
// gate-test-box_patterns
|
||||
|
||||
fn main() {
|
||||
let box x = Box::new('c'); //~ ERROR box pattern syntax is experimental
|
||||
println!("x: {}", x);
|
||||
|
|
|
@ -8,6 +8,8 @@
|
|||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
// gate-test-dropck_parametricity
|
||||
|
||||
// Ensure that attempts to use the unsafe attribute are feature-gated.
|
||||
|
||||
// Example adapted from RFC 1238 text (just left out the feature gate).
|
||||
|
|
|
@ -8,6 +8,8 @@
|
|||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
// gate-test-dropck_eyepatch
|
||||
|
||||
// Check that `may_dangle` is rejected if `dropck_eyepatch` feature gate is absent.
|
||||
|
||||
#![feature(generic_param_attrs)]
|
||||
|
|
|
@ -8,6 +8,8 @@
|
|||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
// gate-test-placement_in_syntax
|
||||
|
||||
// Check that `in PLACE { EXPR }` is feature-gated.
|
||||
//
|
||||
// See also feature-gate-box-expr.rs
|
||||
|
|
|
@ -8,6 +8,8 @@
|
|||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
// gate-test-associated_consts
|
||||
|
||||
trait MyTrait {
|
||||
const C: bool;
|
||||
//~^ associated constants are experimental
|
||||
|
|
|
@ -10,6 +10,8 @@
|
|||
|
||||
// Check that literals in attributes don't parse without the feature gate.
|
||||
|
||||
// gate-test-attr_literals
|
||||
|
||||
#![feature(rustc_attrs)]
|
||||
#![allow(dead_code)]
|
||||
#![allow(unused_variables)]
|
||||
|
|
|
@ -10,6 +10,8 @@
|
|||
|
||||
// Test that the use of the box syntax is gated by `box_syntax` feature gate.
|
||||
|
||||
// gate-test-box_syntax
|
||||
|
||||
fn main() {
|
||||
let x = box 3;
|
||||
//~^ ERROR box expression syntax is experimental; you can call `Box::new` instead.
|
||||
|
|
|
@ -8,6 +8,8 @@
|
|||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
// gate-test-concat_idents
|
||||
|
||||
fn main() {
|
||||
concat_idents!(a, b); //~ ERROR `concat_idents` is not stable enough
|
||||
}
|
||||
|
|
|
@ -11,6 +11,8 @@
|
|||
// Test that `#[link_args]` attribute is gated by `link_args`
|
||||
// feature gate.
|
||||
|
||||
// gate-test-link_args
|
||||
|
||||
#[link_args = "aFdEfSeVEEE"]
|
||||
extern {}
|
||||
//~^ ERROR the `link_args` attribute is not portable across platforms
|
||||
|
|
|
@ -8,6 +8,8 @@
|
|||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
// gate-test-link_llvm_intrinsics
|
||||
|
||||
extern {
|
||||
#[link_name = "llvm.sqrt.f32"]
|
||||
fn sqrt(x: f32) -> f32;
|
||||
|
|
|
@ -8,6 +8,8 @@
|
|||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
// gate-test-naked_functions
|
||||
|
||||
#[naked]
|
||||
//~^ the `#[naked]` attribute is an experimental feature
|
||||
fn naked() {}
|
||||
|
|
|
@ -8,6 +8,8 @@
|
|||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
// gate-test-no_core
|
||||
|
||||
#![no_core] //~ ERROR no_core is experimental
|
||||
|
||||
fn main() {}
|
||||
|
|
|
@ -8,6 +8,8 @@
|
|||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
// gate-test-non_ascii_idents
|
||||
|
||||
extern crate core as bäz; //~ ERROR non-ascii idents
|
||||
|
||||
use föö::bar; //~ ERROR non-ascii idents
|
||||
|
|
|
@ -8,6 +8,8 @@
|
|||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
// gate-test-plugin_registrar
|
||||
|
||||
// Test that `#[plugin_registrar]` attribute is gated by `plugin_registrar`
|
||||
// feature gate.
|
||||
|
||||
|
|
|
@ -8,6 +8,8 @@
|
|||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
// gate-test-target_feature
|
||||
|
||||
#[target_feature = "+sse2"]
|
||||
//~^ the `#[target_feature]` attribute is an experimental feature
|
||||
fn foo() {}
|
||||
|
|
|
@ -8,6 +8,8 @@
|
|||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
// gate-test-thread_local
|
||||
|
||||
// Test that `#[thread_local]` attribute is gated by `thread_local`
|
||||
// feature gate.
|
||||
//
|
||||
|
|
|
@ -8,6 +8,7 @@
|
|||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
// gate-test-trace_macros
|
||||
|
||||
fn main() {
|
||||
trace_macros!(true); //~ ERROR: `trace_macros` is not stable
|
||||
|
|
|
@ -7,6 +7,9 @@
|
|||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
// gate-test-i128_type
|
||||
|
||||
fn test1() -> i128 { //~ ERROR 128-bit type is unstable
|
||||
0
|
||||
}
|
||||
|
|
|
@ -7,6 +7,9 @@
|
|||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
// gate-test-i128_type
|
||||
|
||||
fn test2() {
|
||||
0i128; //~ ERROR 128-bit integers are not stable
|
||||
}
|
||||
|
|
|
@ -8,6 +8,8 @@
|
|||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
// gate-test-conservative_impl_trait
|
||||
|
||||
fn foo() -> impl Fn() { || {} }
|
||||
//~^ ERROR `impl Trait` is experimental
|
||||
|
||||
|
|
|
@ -8,6 +8,8 @@
|
|||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
// gate-test-link_cfg
|
||||
|
||||
#[link(name = "foo", cfg(foo))]
|
||||
//~^ ERROR: is feature gated
|
||||
extern {}
|
||||
|
|
|
@ -8,6 +8,8 @@
|
|||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
// gate-test-linkage
|
||||
|
||||
extern {
|
||||
#[linkage = "extern_weak"] static foo: isize;
|
||||
//~^ ERROR: the `linkage` attribute is experimental and not portable
|
||||
|
|
|
@ -8,6 +8,8 @@
|
|||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
// gate-test-log_syntax
|
||||
|
||||
fn main() {
|
||||
log_syntax!() //~ ERROR `log_syntax!` is not stable enough
|
||||
}
|
||||
|
|
|
@ -8,6 +8,8 @@
|
|||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
// gate-test-log_syntax
|
||||
|
||||
fn main() {
|
||||
println!("{}", log_syntax!()); //~ ERROR `log_syntax!` is not stable
|
||||
}
|
||||
|
|
|
@ -10,6 +10,8 @@
|
|||
|
||||
// Test that ! errors when used in illegal positions with feature(never_type) disabled
|
||||
|
||||
// gate-test-never_type
|
||||
|
||||
trait Foo {
|
||||
type Wub;
|
||||
}
|
||||
|
|
|
@ -8,6 +8,8 @@
|
|||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
// gate-test-no_core
|
||||
|
||||
#![no_core] //~ ERROR no_core is experimental
|
||||
|
||||
fn main() {}
|
||||
|
|
|
@ -8,6 +8,8 @@
|
|||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
// gate-test-relaxed_adts
|
||||
|
||||
struct S(u8);
|
||||
|
||||
fn main() {
|
||||
|
|
|
@ -8,6 +8,9 @@
|
|||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
// gate-test-needs_panic_runtime
|
||||
// gate-test-panic_runtime
|
||||
|
||||
#![panic_runtime] //~ ERROR: is an experimental feature
|
||||
#![needs_panic_runtime] //~ ERROR: is an experimental feature
|
||||
|
||||
|
|
|
@ -8,6 +8,8 @@
|
|||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
// gate-test-pub_restricted
|
||||
|
||||
pub(crate) //~ ERROR experimental
|
||||
mod foo {}
|
||||
|
||||
|
|
|
@ -14,6 +14,8 @@
|
|||
|
||||
// revisions: with_gate no_gate
|
||||
|
||||
// gate-test-structural_match
|
||||
|
||||
#![allow(dead_code)]
|
||||
#![deny(future_incompatible)]
|
||||
#![feature(rustc_attrs)]
|
||||
|
|
|
@ -8,6 +8,8 @@
|
|||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
// gate-test-custom_derive
|
||||
|
||||
#[derive_Clone]
|
||||
//~^ ERROR attributes of the form `#[derive_*]` are reserved
|
||||
struct Test;
|
||||
|
|
|
@ -10,6 +10,8 @@
|
|||
|
||||
// Check that specialization must be ungated to use the `default` keyword
|
||||
|
||||
// gate-test-specialization
|
||||
|
||||
trait Foo {
|
||||
fn foo(&self);
|
||||
}
|
||||
|
|
|
@ -10,6 +10,8 @@
|
|||
|
||||
// Check that writing an overlapping impl is not allow unless specialization is ungated.
|
||||
|
||||
// gate-test-specialization
|
||||
|
||||
trait Foo {
|
||||
fn foo(&self);
|
||||
}
|
||||
|
|
|
@ -8,6 +8,8 @@
|
|||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
// gate-test-drop_types_in_const
|
||||
|
||||
#![feature(box_syntax)]
|
||||
|
||||
static mut a: Box<isize> = box 3;
|
||||
|
|
|
@ -8,6 +8,8 @@
|
|||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
// gate-test-struct_field_attributes
|
||||
|
||||
struct Foo {
|
||||
present: (),
|
||||
}
|
||||
|
|
|
@ -8,6 +8,8 @@
|
|||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
// gate-test-type_ascription
|
||||
|
||||
// Type ascription is feature gated
|
||||
|
||||
fn main() {
|
||||
|
|
|
@ -8,6 +8,8 @@
|
|||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
// gate-test-abi_unadjusted
|
||||
|
||||
extern "unadjusted" fn foo() {
|
||||
//~^ ERROR: unadjusted ABI is an implementation detail and perma-unstable
|
||||
}
|
||||
|
|
|
@ -8,6 +8,8 @@
|
|||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
// gate-test-untagged_unions
|
||||
|
||||
union U { //~ ERROR unions are unstable and possibly buggy
|
||||
a: u8,
|
||||
}
|
||||
|
|
|
@ -8,6 +8,8 @@
|
|||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
// gate-test-windows_subsystem
|
||||
|
||||
#![windows_subsystem = "console"]
|
||||
//~^ ERROR: the windows subsystem attribute is currently unstable
|
||||
|
||||
|
|
|
@ -16,6 +16,7 @@
|
|||
//! * The set of library features is disjoint from the set of language features
|
||||
//! * Library features have at most one stability level
|
||||
//! * Library features have at most one `since` value
|
||||
//! * All unstable lang features have tests to ensure they are actually unstable
|
||||
|
||||
use std::collections::HashMap;
|
||||
use std::fmt;
|
||||
|
@ -26,6 +27,7 @@ use std::path::Path;
|
|||
#[derive(PartialEq)]
|
||||
enum Status {
|
||||
Stable,
|
||||
Removed,
|
||||
Unstable,
|
||||
}
|
||||
|
||||
|
@ -34,27 +36,22 @@ impl fmt::Display for Status {
|
|||
let as_str = match *self {
|
||||
Status::Stable => "stable",
|
||||
Status::Unstable => "unstable",
|
||||
Status::Removed => "removed",
|
||||
};
|
||||
fmt::Display::fmt(as_str, f)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
struct Feature {
|
||||
name: String,
|
||||
level: Status,
|
||||
since: String,
|
||||
}
|
||||
|
||||
struct LibFeature {
|
||||
level: Status,
|
||||
since: String,
|
||||
has_gate_test: bool,
|
||||
}
|
||||
|
||||
pub fn check(path: &Path, bad: &mut bool) {
|
||||
let features = collect_lang_features(&path.join("libsyntax/feature_gate.rs"));
|
||||
let mut 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, Feature>::new();
|
||||
|
||||
let mut contents = String::new();
|
||||
super::walk(path,
|
||||
|
@ -97,7 +94,7 @@ pub fn check(path: &Path, bad: &mut bool) {
|
|||
None => "None",
|
||||
};
|
||||
|
||||
if features.iter().any(|f| f.name == feature_name) {
|
||||
if features.contains_key(feature_name) {
|
||||
err("duplicating a lang feature");
|
||||
}
|
||||
if let Some(ref s) = lib_features.get(feature_name) {
|
||||
|
@ -110,21 +107,105 @@ pub fn check(path: &Path, bad: &mut bool) {
|
|||
continue;
|
||||
}
|
||||
lib_features.insert(feature_name.to_owned(),
|
||||
LibFeature {
|
||||
Feature {
|
||||
level: level,
|
||||
since: since.to_owned(),
|
||||
has_gate_test: false,
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
super::walk(&path.join("test/compile-fail"),
|
||||
&mut |path| super::filter_dirs(path),
|
||||
&mut |file| {
|
||||
let filename = file.file_name().unwrap().to_string_lossy();
|
||||
if !filename.ends_with(".rs") || filename == "features.rs" ||
|
||||
filename == "diagnostic_list.rs" {
|
||||
return;
|
||||
}
|
||||
|
||||
let filen_underscore = filename.replace("-","_").replace(".rs","");
|
||||
test_filen_gate(&filen_underscore, &mut features);
|
||||
|
||||
contents.truncate(0);
|
||||
t!(t!(File::open(&file), &file).read_to_string(&mut contents));
|
||||
|
||||
for (i, line) in contents.lines().enumerate() {
|
||||
let mut err = |msg: &str| {
|
||||
println!("{}:{}: {}", file.display(), i + 1, msg);
|
||||
*bad = true;
|
||||
};
|
||||
|
||||
let gate_test_str = "gate-test-";
|
||||
|
||||
if !line.contains(gate_test_str) {
|
||||
continue;
|
||||
}
|
||||
|
||||
let feature_name = match line.find(gate_test_str) {
|
||||
Some(i) => {
|
||||
&line[i+gate_test_str.len()..line[i+1..].find(' ').unwrap_or(line.len())]
|
||||
},
|
||||
None => continue,
|
||||
};
|
||||
let found_feature = features.get_mut(feature_name)
|
||||
.map(|v| { v.has_gate_test = true; () })
|
||||
.is_some();
|
||||
|
||||
let found_lib_feature = features.get_mut(feature_name)
|
||||
.map(|v| { v.has_gate_test = true; () })
|
||||
.is_some();
|
||||
|
||||
if !(found_feature || found_lib_feature) {
|
||||
err(&format!("gate-test test found referencing a nonexistent feature '{}'",
|
||||
feature_name));
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// FIXME get this whitelist empty.
|
||||
let whitelist = vec![
|
||||
"abi_ptx", "simd", "safe_suggestion", "macro_reexport",
|
||||
"more_struct_aliases", "static_recursion", "reflect",
|
||||
"quote", "cfg_target_has_atomic", "custom_attribute",
|
||||
"default_type_parameter_fallback", "pushpop_unsafe",
|
||||
"use_extern_macros", "staged_api", "const_indexing",
|
||||
"unboxed_closures", "stmt_expr_attributes",
|
||||
"cfg_target_thread_local", "unwind_attributes",
|
||||
"inclusive_range_syntax"
|
||||
];
|
||||
|
||||
// Only check the number of lang features.
|
||||
// Obligatory testing for library features is dumb.
|
||||
let gate_untested = features.iter()
|
||||
.filter(|&(_, f)| f.level == Status::Unstable)
|
||||
.filter(|&(_, f)| !f.has_gate_test)
|
||||
.filter(|&(n, _)| !whitelist.contains(&n.as_str()))
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
for &(name, _) in gate_untested.iter() {
|
||||
println!("Expected a gate test for the feature '{}'.", name);
|
||||
println!("Hint: create a file named 'feature-gate-{}.rs' in the compile-fail\
|
||||
\n test suite, with its failures due to missing usage of\
|
||||
\n #![feature({})].", name, name);
|
||||
println!("Hint: If you already have such a test and don't want to rename it,\
|
||||
\n you can also add a // gate-test-{} line to the test file.",
|
||||
name);
|
||||
}
|
||||
|
||||
if gate_untested.len() > 0 {
|
||||
println!("Found {} features without a gate test.", gate_untested.len());
|
||||
*bad = true;
|
||||
}
|
||||
|
||||
if *bad {
|
||||
return;
|
||||
}
|
||||
|
||||
let mut lines = Vec::new();
|
||||
for feature in features {
|
||||
for (name, feature) in features.iter() {
|
||||
lines.push(format!("{:<32} {:<8} {:<12} {:<8}",
|
||||
feature.name,
|
||||
name,
|
||||
"lang",
|
||||
feature.level,
|
||||
feature.since));
|
||||
|
@ -150,7 +231,20 @@ fn find_attr_val<'a>(line: &'a str, attr: &str) -> Option<&'a str> {
|
|||
.map(|(i, j)| &line[i..j])
|
||||
}
|
||||
|
||||
fn collect_lang_features(path: &Path) -> Vec<Feature> {
|
||||
fn test_filen_gate(filen_underscore: &str,
|
||||
features: &mut HashMap<String, Feature>) -> bool {
|
||||
if filen_underscore.starts_with("feature_gate") {
|
||||
for (n, f) in features.iter_mut() {
|
||||
if filen_underscore == format!("feature_gate_{}", n) {
|
||||
f.has_gate_test = true;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
fn collect_lang_features(path: &Path) -> HashMap<String, Feature> {
|
||||
let mut contents = String::new();
|
||||
t!(t!(File::open(path)).read_to_string(&mut contents));
|
||||
|
||||
|
@ -159,17 +253,18 @@ fn collect_lang_features(path: &Path) -> Vec<Feature> {
|
|||
let mut parts = line.trim().split(",");
|
||||
let level = match parts.next().map(|l| l.trim().trim_left_matches('(')) {
|
||||
Some("active") => Status::Unstable,
|
||||
Some("removed") => Status::Unstable,
|
||||
Some("removed") => Status::Removed,
|
||||
Some("accepted") => Status::Stable,
|
||||
_ => return None,
|
||||
};
|
||||
let name = parts.next().unwrap().trim();
|
||||
let since = parts.next().unwrap().trim().trim_matches('"');
|
||||
Some(Feature {
|
||||
name: name.to_owned(),
|
||||
level: level,
|
||||
since: since.to_owned(),
|
||||
})
|
||||
Some((name.to_owned(),
|
||||
Feature {
|
||||
level: level,
|
||||
since: since.to_owned(),
|
||||
has_gate_test: false,
|
||||
}))
|
||||
})
|
||||
.collect()
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue