Add a lint for library features
Does a sanity check of the version numbers.
This commit is contained in:
parent
7b73ec4698
commit
11f4d62a06
|
@ -300,6 +300,7 @@ tidy:
|
||||||
| grep '^$(S)src/libbacktrace' -v \
|
| grep '^$(S)src/libbacktrace' -v \
|
||||||
| grep '^$(S)src/rust-installer' -v \
|
| grep '^$(S)src/rust-installer' -v \
|
||||||
| xargs $(CFG_PYTHON) $(S)src/etc/check-binaries.py
|
| xargs $(CFG_PYTHON) $(S)src/etc/check-binaries.py
|
||||||
|
$(CFG_PYTHON) $(S)src/etc/featureck.py $(S)src/
|
||||||
|
|
||||||
|
|
||||||
endif
|
endif
|
||||||
|
|
|
@ -0,0 +1,254 @@
|
||||||
|
# Copyright 2015 The Rust Project Developers. See the COPYRIGHT
|
||||||
|
# file at the top-level directory of this distribution and at
|
||||||
|
# http://rust-lang.org/COPYRIGHT.
|
||||||
|
#
|
||||||
|
# Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||||
|
# http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||||
|
# <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.
|
||||||
|
|
||||||
|
# This script does a tree-wide sanity checks against stability
|
||||||
|
# attributes, currently:
|
||||||
|
# * For all feature_name/level pairs the 'since' field is the same
|
||||||
|
# * That no features are both stable and unstable.
|
||||||
|
# * That lib features don't have the same name as lang features
|
||||||
|
# unless they are on the 'joint_features' whitelist
|
||||||
|
# * That features that exist in both lang and lib and are stable
|
||||||
|
# since the same version
|
||||||
|
# * Prints information about features
|
||||||
|
|
||||||
|
import sys, os, re
|
||||||
|
|
||||||
|
src_dir = sys.argv[1]
|
||||||
|
|
||||||
|
# Features that are allowed to exist in both the language and the library
|
||||||
|
joint_features = [ "on_unimpleented" ]
|
||||||
|
|
||||||
|
# Grab the list of language features from the compiler
|
||||||
|
language_gate_statuses = [ "Active", "Deprecated", "Removed", "Accepted" ]
|
||||||
|
feature_gate_source = os.path.join(src_dir, "libsyntax", "feature_gate.rs")
|
||||||
|
language_features = []
|
||||||
|
language_feature_names = []
|
||||||
|
with open(feature_gate_source, 'r') as f:
|
||||||
|
for line in f:
|
||||||
|
original_line = line
|
||||||
|
line = line.strip()
|
||||||
|
is_feature_line = False
|
||||||
|
for status in language_gate_statuses:
|
||||||
|
if status in line and line.startswith("("):
|
||||||
|
is_feature_line = True
|
||||||
|
|
||||||
|
if is_feature_line:
|
||||||
|
line = line.replace("(", "").replace("),", "").replace(")", "")
|
||||||
|
parts = line.split(",")
|
||||||
|
if len(parts) != 3:
|
||||||
|
print "unexpected number of components in line: " + original_line
|
||||||
|
sys.exit(1)
|
||||||
|
feature_name = parts[0].strip().replace('"', "")
|
||||||
|
since = parts[1].strip().replace('"', "")
|
||||||
|
status = parts[2].strip()
|
||||||
|
assert len(feature_name) > 0
|
||||||
|
assert len(since) > 0
|
||||||
|
assert len(status) > 0
|
||||||
|
|
||||||
|
language_feature_names += [feature_name]
|
||||||
|
language_features += [(feature_name, since, status)]
|
||||||
|
|
||||||
|
assert len(language_features) > 0
|
||||||
|
|
||||||
|
errors = False
|
||||||
|
|
||||||
|
lib_features = { }
|
||||||
|
lib_features_and_level = { }
|
||||||
|
for (dirpath, dirnames, filenames) in os.walk(src_dir):
|
||||||
|
# Don't look for feature names in tests
|
||||||
|
if "src/test" in dirpath:
|
||||||
|
continue
|
||||||
|
|
||||||
|
# Takes a long time to traverse LLVM
|
||||||
|
if "src/llvm" in dirpath:
|
||||||
|
continue
|
||||||
|
|
||||||
|
for filename in filenames:
|
||||||
|
if not filename.endswith(".rs"):
|
||||||
|
continue
|
||||||
|
|
||||||
|
path = os.path.join(dirpath, filename)
|
||||||
|
with open(path, 'r') as f:
|
||||||
|
line_num = 0
|
||||||
|
for line in f:
|
||||||
|
line_num += 1
|
||||||
|
level = None
|
||||||
|
if "[unstable(" in line:
|
||||||
|
level = "unstable"
|
||||||
|
elif "[stable(" in line:
|
||||||
|
level = "stable"
|
||||||
|
elif "[deprecated(" in line:
|
||||||
|
level = "deprecated"
|
||||||
|
else:
|
||||||
|
continue
|
||||||
|
|
||||||
|
# This is a stability attribute. For the purposes of this
|
||||||
|
# script we expect both the 'feature' and 'since' attributes on
|
||||||
|
# the same line, e.g.
|
||||||
|
# `#[unstable(feature = "foo", since = "1.0.0")]`
|
||||||
|
|
||||||
|
p = re.compile('feature *= *"(\w*)".*since *= *"([\w\.]*)"')
|
||||||
|
m = p.search(line)
|
||||||
|
if not m is None:
|
||||||
|
feature_name = m.group(1)
|
||||||
|
since = m.group(2)
|
||||||
|
lib_features[feature_name] = feature_name
|
||||||
|
if lib_features_and_level.get((feature_name, level)) is None:
|
||||||
|
# Add it to the observed features
|
||||||
|
lib_features_and_level[(feature_name, level)] = (since, path, line_num, line)
|
||||||
|
else:
|
||||||
|
# Verify that for this combination of feature_name and level the 'since'
|
||||||
|
# attribute matches.
|
||||||
|
(expected_since, source_path, source_line_num, source_line) = \
|
||||||
|
lib_features_and_level.get((feature_name, level))
|
||||||
|
if since != expected_since:
|
||||||
|
print "mismatch in " + level + " feature '" + feature_name + "'"
|
||||||
|
print "line " + str(source_line_num) + " of " + source_path + ":"
|
||||||
|
print source_line
|
||||||
|
print "line " + str(line_num) + " of " + path + ":"
|
||||||
|
print line
|
||||||
|
errors = True
|
||||||
|
|
||||||
|
# Verify that this lib feature doesn't duplicate a lang feature
|
||||||
|
if feature_name in language_feature_names:
|
||||||
|
print "lib feature '" + feature_name + "' duplicates a lang feature"
|
||||||
|
print "line " + str(line_num) + " of " + path + ":"
|
||||||
|
print line
|
||||||
|
errors = True
|
||||||
|
|
||||||
|
else:
|
||||||
|
print "misformed stability attribute"
|
||||||
|
print "line " + str(line_num) + " of " + path + ":"
|
||||||
|
print line
|
||||||
|
errors = True
|
||||||
|
|
||||||
|
# Merge data about both lists
|
||||||
|
# name, lang, lib, status, stable since, partially deprecated
|
||||||
|
|
||||||
|
language_feature_stats = {}
|
||||||
|
|
||||||
|
for f in language_features:
|
||||||
|
name = f[0]
|
||||||
|
lang = True
|
||||||
|
lib = False
|
||||||
|
status = "unstable"
|
||||||
|
stable_since = None
|
||||||
|
partially_deprecated = False
|
||||||
|
|
||||||
|
if f[2] == "Accepted":
|
||||||
|
status = "stable"
|
||||||
|
if status == "stable":
|
||||||
|
stable_since = f[1]
|
||||||
|
|
||||||
|
language_feature_stats[name] = (name, lang, lib, status, stable_since, \
|
||||||
|
partially_deprecated)
|
||||||
|
|
||||||
|
lib_feature_stats = {}
|
||||||
|
|
||||||
|
for f in lib_features:
|
||||||
|
name = f
|
||||||
|
lang = False
|
||||||
|
lib = True
|
||||||
|
status = "unstable"
|
||||||
|
stable_since = None
|
||||||
|
partially_deprecated = False
|
||||||
|
|
||||||
|
is_stable = lib_features_and_level.get((name, "stable")) is not None
|
||||||
|
is_unstable = lib_features_and_level.get((name, "unstable")) is not None
|
||||||
|
is_deprecated = lib_features_and_level.get((name, "deprecated")) is not None
|
||||||
|
|
||||||
|
if is_stable and is_unstable:
|
||||||
|
print "feature '" + name + "' is both stable and unstable"
|
||||||
|
errors = True
|
||||||
|
|
||||||
|
if is_stable:
|
||||||
|
status = "stable"
|
||||||
|
stable_since = lib_features_and_level[(name, "stable")][0]
|
||||||
|
elif is_unstable:
|
||||||
|
status = "unstable"
|
||||||
|
stable_since = lib_features_and_level[(name, "unstable")][0]
|
||||||
|
elif is_deprecated:
|
||||||
|
status = "deprecated"
|
||||||
|
|
||||||
|
if (is_stable or is_unstable) and is_deprecated:
|
||||||
|
partially_deprecated = True
|
||||||
|
|
||||||
|
lib_feature_stats[name] = (name, lang, lib, status, stable_since, \
|
||||||
|
partially_deprecated)
|
||||||
|
|
||||||
|
# Check for overlap in two sets
|
||||||
|
merged_stats = { }
|
||||||
|
|
||||||
|
for name in lib_feature_stats:
|
||||||
|
if language_feature_stats.get(name) is not None:
|
||||||
|
if not name in joint_features:
|
||||||
|
print "feature '" + name + "' is both a lang and lib feature but not whitelisted"
|
||||||
|
errors = True
|
||||||
|
lang_status = lang_feature_stats[name][3]
|
||||||
|
lib_status = lib_feature_stats[name][3]
|
||||||
|
lang_stable_since = lang_feature_stats[name][4]
|
||||||
|
lib_stable_since = lib_feature_stats[name][4]
|
||||||
|
lang_partially_deprecated = lang_feature_stats[name][5]
|
||||||
|
lib_partially_deprecated = lib_feature_stats[name][5]
|
||||||
|
|
||||||
|
if lang_status != lib_status and lib_status != "deprecated":
|
||||||
|
print "feature '" + name + "' has lang status " + lang_status + \
|
||||||
|
" but lib status " + lib_status
|
||||||
|
errors = True
|
||||||
|
|
||||||
|
partially_deprecated = lang_partially_deprecated or lib_partially_deprecated
|
||||||
|
if lib_status == "deprecated" and lang_status != "deprecated":
|
||||||
|
partially_deprecated = True
|
||||||
|
|
||||||
|
if lang_stable_since != lib_stable_since:
|
||||||
|
print "feature '" + name + "' has lang stable since " + lang_stable_since + \
|
||||||
|
" but lib stable since " + lib_stable_since
|
||||||
|
errors = True
|
||||||
|
|
||||||
|
merged_stats[name] = (name, True, True, lang_status, lang_stable_since, \
|
||||||
|
partially_deprecated)
|
||||||
|
|
||||||
|
del language_feature_stats[name]
|
||||||
|
del lib_feature_stats[name]
|
||||||
|
|
||||||
|
if errors:
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
# Finally, display the stats
|
||||||
|
stats = {}
|
||||||
|
stats.update(language_feature_stats)
|
||||||
|
stats.update(lib_feature_stats)
|
||||||
|
stats.update(merged_stats)
|
||||||
|
lines = []
|
||||||
|
for s in stats:
|
||||||
|
s = stats[s]
|
||||||
|
type_ = "lang"
|
||||||
|
if s[1] and s[2]:
|
||||||
|
type_ = "lang/lib"
|
||||||
|
elif s[2]:
|
||||||
|
type_ = "lib"
|
||||||
|
line = s[0] + ",\t\t\t" + type_ + ",\t" + s[3] + ",\t" + str(s[4])
|
||||||
|
line = "{: <32}".format(s[0]) + \
|
||||||
|
"{: <8}".format(type_) + \
|
||||||
|
"{: <12}".format(s[3]) + \
|
||||||
|
"{: <8}".format(str(s[4]))
|
||||||
|
if s[5]:
|
||||||
|
line += "(partially deprecated)"
|
||||||
|
lines += [line]
|
||||||
|
|
||||||
|
lines.sort()
|
||||||
|
|
||||||
|
print
|
||||||
|
print "Rust feature summary:"
|
||||||
|
print
|
||||||
|
for line in lines:
|
||||||
|
print line
|
||||||
|
print
|
||||||
|
|
|
@ -24,7 +24,7 @@ use syntax::ast::{TypeMethod, Method, Generics, StructField, TypeTraitItem};
|
||||||
use syntax::ast_util::is_local;
|
use syntax::ast_util::is_local;
|
||||||
use syntax::attr::{Stability, AttrMetaMethods};
|
use syntax::attr::{Stability, AttrMetaMethods};
|
||||||
use syntax::visit::{FnKind, FkMethod, Visitor};
|
use syntax::visit::{FnKind, FkMethod, Visitor};
|
||||||
use syntax::feature_gate::emit_feature_err;
|
use syntax::feature_gate::emit_feature_warn;
|
||||||
use util::nodemap::{NodeMap, DefIdMap, FnvHashSet};
|
use util::nodemap::{NodeMap, DefIdMap, FnvHashSet};
|
||||||
use util::ppaux::Repr;
|
use util::ppaux::Repr;
|
||||||
|
|
||||||
|
@ -221,8 +221,8 @@ impl<'a, 'tcx> Checker<'a, 'tcx> {
|
||||||
None => format!("use of unstable library feature '{}'", feature.get())
|
None => format!("use of unstable library feature '{}'", feature.get())
|
||||||
};
|
};
|
||||||
|
|
||||||
emit_feature_err(&self.tcx.sess.parse_sess.span_diagnostic,
|
emit_feature_warn(&self.tcx.sess.parse_sess.span_diagnostic,
|
||||||
feature.get(), span, &msg[]);
|
feature.get(), span, &msg[]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Some(..) => {
|
Some(..) => {
|
||||||
|
|
|
@ -17,6 +17,10 @@
|
||||||
//!
|
//!
|
||||||
//! Features are enabled in programs via the crate-level attributes of
|
//! Features are enabled in programs via the crate-level attributes of
|
||||||
//! `#![feature(...)]` with a comma-separated list of features.
|
//! `#![feature(...)]` with a comma-separated list of features.
|
||||||
|
//!
|
||||||
|
//! For the purpose of future feature-tracking, once code for detection of feature
|
||||||
|
//! gate usage is added, *do not remove it again* even once the feature
|
||||||
|
//! becomes stable.
|
||||||
use self::Status::*;
|
use self::Status::*;
|
||||||
|
|
||||||
use abi::RustIntrinsic;
|
use abi::RustIntrinsic;
|
||||||
|
@ -33,77 +37,82 @@ use parse::token::{self, InternedString};
|
||||||
use std::slice;
|
use std::slice;
|
||||||
use std::ascii::AsciiExt;
|
use std::ascii::AsciiExt;
|
||||||
|
|
||||||
|
// If you change this list without updating src/doc/reference.md, @cmr will be sad
|
||||||
|
// Don't ever remove anything from this list; set them to 'Removed'.
|
||||||
|
// The version numbers here correspond to the version in which the current status
|
||||||
|
// was set. This is most important for knowing when a particular feature became
|
||||||
|
// stable (active).
|
||||||
|
// NB: The featureck.py script parses this information directly out of the source
|
||||||
|
// so take care when modifying it.
|
||||||
|
static KNOWN_FEATURES: &'static [(&'static str, &'static str, Status)] = &[
|
||||||
|
("globs", "1.0.0", Accepted),
|
||||||
|
("macro_rules", "1.0.0", Accepted),
|
||||||
|
("struct_variant", "1.0.0", Accepted),
|
||||||
|
("asm", "1.0.0", Active),
|
||||||
|
("managed_boxes", "1.0.0", Removed),
|
||||||
|
("non_ascii_idents", "1.0.0", Active),
|
||||||
|
("thread_local", "1.0.0", Active),
|
||||||
|
("link_args", "1.0.0", Active),
|
||||||
|
("phase", "1.0.0", Removed),
|
||||||
|
("plugin_registrar", "1.0.0", Active),
|
||||||
|
("log_syntax", "1.0.0", Active),
|
||||||
|
("trace_macros", "1.0.0", Active),
|
||||||
|
("concat_idents", "1.0.0", Active),
|
||||||
|
("unsafe_destructor", "1.0.0", Active),
|
||||||
|
("intrinsics", "1.0.0", Active),
|
||||||
|
("lang_items", "1.0.0", Active),
|
||||||
|
|
||||||
// if you change this list without updating src/doc/reference.md, @cmr will be sad
|
("simd", "1.0.0", Active),
|
||||||
static KNOWN_FEATURES: &'static [(&'static str, Status)] = &[
|
("default_type_params", "1.0.0", Accepted),
|
||||||
("globs", Accepted),
|
("quote", "1.0.0", Active),
|
||||||
("macro_rules", Accepted),
|
("link_llvm_intrinsics", "1.0.0", Active),
|
||||||
("struct_variant", Accepted),
|
("linkage", "1.0.0", Active),
|
||||||
("asm", Active),
|
("struct_inherit", "1.0.0", Removed),
|
||||||
("managed_boxes", Removed),
|
|
||||||
("non_ascii_idents", Active),
|
|
||||||
("thread_local", Active),
|
|
||||||
("link_args", Active),
|
|
||||||
("phase", Removed),
|
|
||||||
("plugin_registrar", Active),
|
|
||||||
("log_syntax", Active),
|
|
||||||
("trace_macros", Active),
|
|
||||||
("concat_idents", Active),
|
|
||||||
("unsafe_destructor", Active),
|
|
||||||
("intrinsics", Active),
|
|
||||||
("lang_items", Active),
|
|
||||||
|
|
||||||
("simd", Active),
|
("quad_precision_float", "1.0.0", Removed),
|
||||||
("default_type_params", Accepted),
|
|
||||||
("quote", Active),
|
|
||||||
("link_llvm_intrinsics", Active),
|
|
||||||
("linkage", Active),
|
|
||||||
("struct_inherit", Removed),
|
|
||||||
|
|
||||||
("quad_precision_float", Removed),
|
("rustc_diagnostic_macros", "1.0.0", Active),
|
||||||
|
("unboxed_closures", "1.0.0", Active),
|
||||||
|
("import_shadowing", "1.0.0", Active),
|
||||||
|
("advanced_slice_patterns", "1.0.0", Active),
|
||||||
|
("tuple_indexing", "1.0.0", Accepted),
|
||||||
|
("associated_types", "1.0.0", Accepted),
|
||||||
|
("visible_private_types", "1.0.0", Active),
|
||||||
|
("slicing_syntax", "1.0.0", Active),
|
||||||
|
("box_syntax", "1.0.0", Active),
|
||||||
|
("on_unimplemented", "1.0.0", Active),
|
||||||
|
("simd_ffi", "1.0.0", Active),
|
||||||
|
|
||||||
("rustc_diagnostic_macros", Active),
|
("if_let", "1.0.0", Accepted),
|
||||||
("unboxed_closures", Active),
|
("while_let", "1.0.0", Accepted),
|
||||||
("import_shadowing", Active),
|
|
||||||
("advanced_slice_patterns", Active),
|
|
||||||
("tuple_indexing", Accepted),
|
|
||||||
("associated_types", Accepted),
|
|
||||||
("visible_private_types", Active),
|
|
||||||
("slicing_syntax", Active),
|
|
||||||
("box_syntax", Active),
|
|
||||||
("on_unimplemented", Active),
|
|
||||||
("simd_ffi", Active),
|
|
||||||
|
|
||||||
("if_let", Accepted),
|
("plugin", "1.0.0", Active),
|
||||||
("while_let", Accepted),
|
("start", "1.0.0", Active),
|
||||||
|
("main", "1.0.0", Active),
|
||||||
("plugin", Active),
|
|
||||||
("start", Active),
|
|
||||||
("main", Active),
|
|
||||||
|
|
||||||
// A temporary feature gate used to enable parser extensions needed
|
// A temporary feature gate used to enable parser extensions needed
|
||||||
// to bootstrap fix for #5723.
|
// to bootstrap fix for #5723.
|
||||||
("issue_5723_bootstrap", Accepted),
|
("issue_5723_bootstrap", "1.0.0", Accepted),
|
||||||
|
|
||||||
// A way to temporarily opt out of opt in copy. This will *never* be accepted.
|
// A way to temporarily opt out of opt in copy. This will *never* be accepted.
|
||||||
("opt_out_copy", Removed),
|
("opt_out_copy", "1.0.0", Removed),
|
||||||
|
|
||||||
// A way to temporarily opt out of the new orphan rules. This will *never* be accepted.
|
// A way to temporarily opt out of the new orphan rules. This will *never* be accepted.
|
||||||
("old_orphan_check", Deprecated),
|
("old_orphan_check", "1.0.0", Deprecated),
|
||||||
|
|
||||||
// A way to temporarily opt out of the new impl rules. This will *never* be accepted.
|
// A way to temporarily opt out of the new impl rules. This will *never* be accepted.
|
||||||
("old_impl_check", Deprecated),
|
("old_impl_check", "1.0.0", Deprecated),
|
||||||
|
|
||||||
// OIBIT specific features
|
// OIBIT specific features
|
||||||
("optin_builtin_traits", Active),
|
("optin_builtin_traits", "1.0.0", Active),
|
||||||
|
|
||||||
// int and uint are now deprecated
|
// int and uint are now deprecated
|
||||||
("int_uint", Active),
|
("int_uint", "1.0.0", Active),
|
||||||
|
|
||||||
// These are used to test this portion of the compiler, they don't actually
|
// These are used to test this portion of the compiler, they don't actually
|
||||||
// mean anything
|
// mean anything
|
||||||
("test_accepted_feature", Accepted),
|
("test_accepted_feature", "1.0.0", Accepted),
|
||||||
("test_removed_feature", Removed),
|
("test_removed_feature", "1.0.0", Removed),
|
||||||
];
|
];
|
||||||
|
|
||||||
enum Status {
|
enum Status {
|
||||||
|
@ -164,10 +173,7 @@ impl<'a> Context<'a> {
|
||||||
|
|
||||||
fn warn_feature(&self, feature: &str, span: Span, explain: &str) {
|
fn warn_feature(&self, feature: &str, span: Span, explain: &str) {
|
||||||
if !self.has_feature(feature) {
|
if !self.has_feature(feature) {
|
||||||
self.span_handler.span_warn(span, explain);
|
emit_feature_warn(self.span_handler, feature, span, explain);
|
||||||
self.span_handler.span_help(span, &format!("add #![feature({})] to the \
|
|
||||||
crate attributes to silence this warning",
|
|
||||||
feature)[]);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
fn has_feature(&self, feature: &str) -> bool {
|
fn has_feature(&self, feature: &str) -> bool {
|
||||||
|
@ -182,6 +188,13 @@ pub fn emit_feature_err(diag: &SpanHandler, feature: &str, span: Span, explain:
|
||||||
feature)[]);
|
feature)[]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn emit_feature_warn(diag: &SpanHandler, feature: &str, span: Span, explain: &str) {
|
||||||
|
diag.span_warn(span, explain);
|
||||||
|
diag.span_help(span, &format!("add #![feature({})] to the \
|
||||||
|
crate attributes to silence this warning",
|
||||||
|
feature)[]);
|
||||||
|
}
|
||||||
|
|
||||||
struct MacroVisitor<'a> {
|
struct MacroVisitor<'a> {
|
||||||
context: &'a Context<'a>
|
context: &'a Context<'a>
|
||||||
}
|
}
|
||||||
|
@ -510,21 +523,21 @@ fn check_crate_inner<F>(cm: &CodeMap, span_handler: &SpanHandler, krate: &ast::C
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
match KNOWN_FEATURES.iter()
|
match KNOWN_FEATURES.iter()
|
||||||
.find(|& &(n, _)| name == n) {
|
.find(|& &(n, _, _)| name == n) {
|
||||||
Some(&(name, Active)) => {
|
Some(&(name, _, Active)) => {
|
||||||
cx.features.push(name);
|
cx.features.push(name);
|
||||||
}
|
}
|
||||||
Some(&(name, Deprecated)) => {
|
Some(&(name, _, Deprecated)) => {
|
||||||
cx.features.push(name);
|
cx.features.push(name);
|
||||||
span_handler.span_warn(
|
span_handler.span_warn(
|
||||||
mi.span,
|
mi.span,
|
||||||
"feature is deprecated and will only be available \
|
"feature is deprecated and will only be available \
|
||||||
for a limited time, please rewrite code that relies on it");
|
for a limited time, please rewrite code that relies on it");
|
||||||
}
|
}
|
||||||
Some(&(_, Removed)) => {
|
Some(&(_, _, Removed)) => {
|
||||||
span_handler.span_err(mi.span, "feature has been removed");
|
span_handler.span_err(mi.span, "feature has been removed");
|
||||||
}
|
}
|
||||||
Some(&(_, Accepted)) => {
|
Some(&(_, _, Accepted)) => {
|
||||||
span_handler.span_warn(mi.span, "feature has been added to Rust, \
|
span_handler.span_warn(mi.span, "feature has been added to Rust, \
|
||||||
directive not necessary");
|
directive not necessary");
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue