[input] CrateName(CrateNum),
[] ItemChildren(DefId),
[] ExternModStmtCnum(DefId),
+ [input] GetLibFeatures,
+ [] DefinedLibFeatures(CrateNum),
[input] GetLangItems,
[] DefinedLangItems(CrateNum),
[] MissingLangItems(CrateNum),
E0708, // `async` non-`move` closures with arguments are not currently supported
E0709, // multiple different lifetimes used in arguments of `async fn`
E0710, // an unknown tool name found in scoped lint
+ E0711, // a feature has been declared with conflicting stability attributes
}
span
});
+impl_stable_hash_for!(struct ::middle::lib_features::LibFeatures {
+ stable,
+ unstable
+});
+
impl<'a> HashStable<StableHashingContext<'a>> for ::middle::lang_items::LangItem {
fn hash_stable<W: StableHasherResult>(&self,
_: &mut StableHashingContext<'a>,
pub mod exported_symbols;
pub mod free_region;
pub mod intrinsicck;
+ pub mod lib_features;
pub mod lang_items;
pub mod liveness;
pub mod mem_categorization;
declare_lint! {
pub UNUSED_FEATURES,
Warn,
- "unused or unknown features found in crate-level #[feature] directives"
+ "unused features found in crate-level #[feature] directives"
+}
+
+declare_lint! {
+ pub UNKNOWN_FEATURES,
+ Deny,
+ "unknown features found in crate-level #[feature] directives"
}
declare_lint! {
UNUSED_MACROS,
WARNINGS,
UNUSED_FEATURES,
+ UNKNOWN_FEATURES,
STABLE_FEATURES,
UNKNOWN_CRATE_TYPES,
TRIVIAL_CASTS,
--- /dev/null
+// Copyright 2018 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.
+
+// Detecting lib features (i.e. features that are not lang features).
+//
+// These are declared using stability attributes (e.g. `#[stable(..)]`
+// and `#[unstable(..)]`), but are not declared in one single location
+// (unlike lang features), which means we need to collect them instead.
+
+use ty::TyCtxt;
+use syntax::symbol::Symbol;
+use syntax::ast::{Attribute, MetaItem, MetaItemKind};
+use syntax_pos::{Span, DUMMY_SP};
+use hir;
+use hir::itemlikevisit::ItemLikeVisitor;
+use rustc_data_structures::fx::{FxHashSet, FxHashMap};
+use errors::DiagnosticId;
+
+pub struct LibFeatures {
+ // A map from feature to stabilisation version.
+ pub stable: FxHashMap<Symbol, Symbol>,
+ pub unstable: FxHashSet<Symbol>,
+}
+
+impl LibFeatures {
+ fn new() -> LibFeatures {
+ LibFeatures {
+ stable: FxHashMap(),
+ unstable: FxHashSet(),
+ }
+ }
+
+ pub fn iter(&self) -> Vec<(Symbol, Option<Symbol>)> {
+ self.stable.iter().map(|(f, s)| (*f, Some(*s)))
+ .chain(self.unstable.iter().map(|f| (*f, None)))
+ .collect()
+ }
+}
+
+pub struct LibFeatureCollector<'a, 'tcx: 'a> {
+ tcx: TyCtxt<'a, 'tcx, 'tcx>,
+ lib_features: LibFeatures,
+}
+
+impl<'a, 'tcx> LibFeatureCollector<'a, 'tcx> {
+ fn new(tcx: TyCtxt<'a, 'tcx, 'tcx>) -> LibFeatureCollector<'a, 'tcx> {
+ LibFeatureCollector {
+ tcx,
+ lib_features: LibFeatures::new(),
+ }
+ }
+
+ fn extract(&self, attrs: &[Attribute]) -> Vec<(Symbol, Option<Symbol>, Span)> {
+ let stab_attrs = vec!["stable", "unstable", "rustc_const_unstable"];
+ let mut features = vec![];
+
+ for attr in attrs {
+ // FIXME(varkor): the stability attribute might be behind a `#[cfg]` attribute.
+
+ // Find a stability attribute (i.e. `#[stable(..)]`, `#[unstable(..)]`,
+ // `#[rustc_const_unstable(..)]`).
+ if stab_attrs.iter().any(|stab_attr| attr.check_name(stab_attr)) {
+ let meta_item = attr.meta();
+ if let Some(MetaItem { node: MetaItemKind::List(ref metas), .. }) = meta_item {
+ let mut feature = None;
+ let mut since = None;
+ for meta in metas {
+ if let Some(mi) = meta.meta_item() {
+ // Find the `feature = ".."` meta-item.
+ match (&*mi.name().as_str(), mi.value_str()) {
+ ("feature", val) => feature = val,
+ ("since", val) => since = val,
+ _ => {}
+ }
+ }
+ }
+ if let Some(feature) = feature {
+ features.push((feature, since, attr.span));
+ }
+ // We need to iterate over the other attributes, because
+ // `rustc_const_unstable` is not mutually exclusive with
+ // the other stability attributes, so we can't just `break`
+ // here.
+ }
+ }
+ }
+
+ features
+ }
+
+ fn collect_feature(&mut self, feature: Symbol, since: Option<Symbol>, span: Span) {
+ let already_in_stable = self.lib_features.stable.contains_key(&feature);
+ let already_in_unstable = self.lib_features.unstable.contains(&feature);
+
+ match (since, already_in_stable, already_in_unstable) {
+ (Some(since), _, false) => {
+ self.lib_features.stable.insert(feature, since);
+ }
+ (None, false, _) => {
+ self.lib_features.unstable.insert(feature);
+ }
+ (Some(_), _, true) | (None, true, _) => {
+ let msg = format!(
+ "feature `{}` is declared {}, but was previously declared {}",
+ feature,
+ if since.is_some() { "stable"} else { "unstable" },
+ if since.is_none() { "stable"} else { "unstable" },
+ );
+ self.tcx.sess.struct_span_err_with_code(span, &msg,
+ DiagnosticId::Error("E0711".into())).emit();
+ }
+ }
+ }
+
+ fn collect_from_attrs(&mut self, attrs: &[Attribute]) {
+ for (feature, stable, span) in self.extract(attrs) {
+ self.collect_feature(feature, stable, span);
+ }
+ }
+}
+
+impl<'a, 'v, 'tcx> ItemLikeVisitor<'v> for LibFeatureCollector<'a, 'tcx> {
+ fn visit_item(&mut self, item: &hir::Item) {
+ self.collect_from_attrs(&item.attrs);
+ }
+
+ fn visit_trait_item(&mut self, trait_item: &hir::TraitItem) {
+ self.collect_from_attrs(&trait_item.attrs);
+ }
+
+ fn visit_impl_item(&mut self, impl_item: &hir::ImplItem) {
+ self.collect_from_attrs(&impl_item.attrs);
+ }
+}
+
+pub fn collect<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) -> LibFeatures {
+ let mut collector = LibFeatureCollector::new(tcx);
+ for &cnum in tcx.crates().iter() {
+ for &(feature, since) in tcx.defined_lib_features(cnum).iter() {
+ collector.collect_feature(feature, since, DUMMY_SP);
+ }
+ }
+ collector.collect_from_attrs(&tcx.hir.krate().attrs);
+ tcx.hir.krate().visit_all_item_likes(&mut collector);
+ collector.lib_features
+}
krate.visit_all_item_likes(&mut missing.as_deep_visitor());
}
- let ref declared_lib_features = tcx.features().declared_lib_features;
- let mut remaining_lib_features: FxHashMap<Symbol, Span>
- = declared_lib_features.clone().into_iter().collect();
- remaining_lib_features.remove(&Symbol::intern("proc_macro"));
-
for &(ref stable_lang_feature, span) in &tcx.features().declared_stable_lang_features {
- let version = find_lang_feature_accepted_version(&stable_lang_feature.as_str())
+ let since = find_lang_feature_accepted_version(&stable_lang_feature.as_str())
.expect("unexpectedly couldn't find version feature was stabilized");
tcx.lint_node(lint::builtin::STABLE_FEATURES,
ast::CRATE_NODE_ID,
span,
- &format_stable_since_msg(version));
- }
-
- // FIXME(#44232) the `used_features` table no longer exists, so we don't
- // lint about unknown or unused features. We should reenable
- // this one day!
- //
- // let index = tcx.stability();
- // for (used_lib_feature, level) in &index.used_features {
- // remaining_lib_features.remove(used_lib_feature);
- // }
- //
- // for &span in remaining_lib_features.values() {
- // tcx.lint_node(lint::builtin::UNUSED_FEATURES,
- // ast::CRATE_NODE_ID,
- // span,
- // "unused or unknown feature");
- // }
+ &format_stable_since_msg(*stable_lang_feature, since));
+ }
+
+ let ref declared_lib_features = tcx.features().declared_lib_features;
+
+ let mut remaining_lib_features = FxHashMap();
+ for (feature, span) in declared_lib_features.clone().into_iter() {
+ remaining_lib_features.insert(feature, span);
+ }
+ // FIXME(varkor): we don't properly handle lib features behind `cfg` attributes yet,
+ // but it happens just to affect `libc`, so we're just going to hard-code it for now.
+ remaining_lib_features.remove(&Symbol::intern("libc"));
+
+ for (feature, stable) in tcx.lib_features().iter() {
+ remaining_lib_features.remove(&feature);
+ }
+
+ for (feature, span) in remaining_lib_features {
+ tcx.lint_node(lint::builtin::UNKNOWN_FEATURES,
+ ast::CRATE_NODE_ID,
+ span,
+ &format!("unknown feature `{}`", feature));
+ }
+
+ // FIXME(#44232): the `used_features` table no longer exists, so we
+ // don't lint about unused features. We should reenable this one day!
}
-fn format_stable_since_msg(version: &str) -> String {
- format!("this feature has been stable since {}. Attribute no longer needed", version)
+fn format_stable_since_msg(feature: Symbol, since: &str) -> String {
+ // "this feature has been stable since {}. Attribute no longer needed"
+ format!("the feature `{}` has been stable since {} and no longer requires \
+ an attribute to enable", feature, since)
}
self.sess.consider_optimizing(&cname, msg)
}
+ pub fn lib_features(self) -> Lrc<middle::lib_features::LibFeatures> {
+ self.get_lib_features(LOCAL_CRATE)
+ }
+
pub fn lang_items(self) -> Lrc<middle::lang_items::LanguageItems> {
self.get_lang_items(LOCAL_CRATE)
}
assert_eq!(id, LOCAL_CRATE);
tcx.crate_name
};
+ providers.get_lib_features = |tcx, id| {
+ assert_eq!(id, LOCAL_CRATE);
+ // FIXME(#42293): see comment below.
+ tcx.dep_graph.with_ignore(|| Lrc::new(middle::lib_features::collect(tcx)))
+ };
providers.get_lang_items = |tcx, id| {
assert_eq!(id, LOCAL_CRATE);
// FIXME(#42293) Right now we insert a `with_ignore` node in the dep
}
}
+impl<'tcx> QueryDescription<'tcx> for queries::get_lib_features<'tcx> {
+ fn describe(_tcx: TyCtxt, _: CrateNum) -> String {
+ format!("calculating the lib features map")
+ }
+}
+
+impl<'tcx> QueryDescription<'tcx> for queries::defined_lib_features<'tcx> {
+ fn describe(_tcx: TyCtxt, _: CrateNum) -> String {
+ format!("calculating the lib features defined in a crate")
+ }
+}
+
impl<'tcx> QueryDescription<'tcx> for queries::get_lang_items<'tcx> {
fn describe(_tcx: TyCtxt, _: CrateNum) -> String {
"calculating the lang items map".to_string()
use middle::region;
use middle::resolve_lifetime::{ResolveLifetimes, Region, ObjectLifetimeDefault};
use middle::stability::{self, DeprecationEntry};
+use middle::lib_features::LibFeatures;
use middle::lang_items::{LanguageItems, LangItem};
use middle::exported_symbols::{SymbolExportLevel, ExportedSymbol};
use mir::interpret::ConstEvalResult;
[] fn item_children: ItemChildren(DefId) -> Lrc<Vec<Export>>,
[] fn extern_mod_stmt_cnum: ExternModStmtCnum(DefId) -> Option<CrateNum>,
+ [] fn get_lib_features: get_lib_features_node(CrateNum) -> Lrc<LibFeatures>,
+ [] fn defined_lib_features: DefinedLibFeatures(CrateNum)
+ -> Lrc<Vec<(Symbol, Option<Symbol>)>>,
[] fn get_lang_items: get_lang_items_node(CrateNum) -> Lrc<LanguageItems>,
[] fn defined_lang_items: DefinedLangItems(CrateNum) -> Lrc<Vec<(DefId, usize)>>,
[] fn missing_lang_items: MissingLangItems(CrateNum) -> Lrc<Vec<LangItem>>,
DepConstructor::LinkArgs
}
+fn get_lib_features_node<'tcx>(_: CrateNum) -> DepConstructor<'tcx> {
+ DepConstructor::GetLibFeatures
+}
+
fn get_lang_items_node<'tcx>(_: CrateNum) -> DepConstructor<'tcx> {
DepConstructor::GetLangItems
}
DepKind::CrateName => { force!(crate_name, krate!()); }
DepKind::ItemChildren => { force!(item_children, def_id!()); }
DepKind::ExternModStmtCnum => { force!(extern_mod_stmt_cnum, def_id!()); }
+ DepKind::GetLibFeatures => { force!(get_lib_features, LOCAL_CRATE); }
+ DepKind::DefinedLibFeatures => { force!(defined_lib_features, krate!()); }
DepKind::GetLangItems => { force!(get_lang_items, LOCAL_CRATE); }
DepKind::DefinedLangItems => { force!(defined_lang_items, krate!()); }
DepKind::MissingLangItems => { force!(missing_lang_items, krate!()); }
UNUSED_DOC_COMMENTS,
UNUSED_EXTERN_CRATES,
UNUSED_FEATURES,
+ UNKNOWN_FEATURES,
UNUSED_LABELS,
UNUSED_PARENS);
store.register_renamed("bare_trait_object", "bare_trait_objects");
store.register_renamed("unstable_name_collision", "unstable_name_collisions");
store.register_renamed("unused_doc_comment", "unused_doc_comments");
- store.register_renamed("unknown_features", "unused_features");
store.register_removed("unsigned_negation", "replaced by negate_unsigned feature gate");
store.register_removed("negate_unsigned", "cast a signed value instead");
store.register_removed("raw_pointer_derive", "using derive with raw pointers is ok");
cdata.each_child_of_item(def_id.index, |child| result.push(child), tcx.sess);
Lrc::new(result)
}
+ defined_lib_features => { Lrc::new(cdata.get_lib_features()) }
defined_lang_items => { Lrc::new(cdata.get_lang_items()) }
missing_lang_items => { Lrc::new(cdata.get_missing_lang_items()) }
self.get_impl_data(id).trait_ref.map(|tr| tr.decode((self, tcx)))
}
+ /// Iterates over all the stability attributes in the given crate.
+ pub fn get_lib_features(&self) -> Vec<(ast::Name, Option<ast::Name>)> {
+ self.root
+ .lib_features
+ .decode(self)
+ .collect()
+ }
+
/// Iterates over the language items in the given crate.
pub fn get_lang_items(&self) -> Vec<(DefId, usize)> {
self.root
());
let dep_bytes = self.position() - i;
+ // Encode the lib features.
+ i = self.position();
+ let lib_features = self.tracked(IsolatedEncoder::encode_lib_features, ());
+ let lib_feature_bytes = self.position() - i;
+
// Encode the language items.
i = self.position();
let lang_items = self.tracked(IsolatedEncoder::encode_lang_items, ());
crate_deps,
dylib_dependency_formats,
+ lib_features,
lang_items,
lang_items_missing,
native_libraries,
println!("metadata stats:");
println!(" dep bytes: {}", dep_bytes);
+ println!(" lib feature bytes: {}", lib_feature_bytes);
println!(" lang item bytes: {}", lang_item_bytes);
println!(" native bytes: {}", native_lib_bytes);
println!(" codemap bytes: {}", codemap_bytes);
self.lazy_seq_ref(deps.iter().map(|&(_, ref dep)| dep))
}
+ fn encode_lib_features(&mut self, _: ()) -> LazySeq<(ast::Name, Option<ast::Name>)> {
+ let tcx = self.tcx;
+ let lib_features = tcx.lib_features();
+ self.lazy_seq(lib_features.iter())
+ }
+
fn encode_lang_items(&mut self, _: ()) -> LazySeq<(DefIndex, usize)> {
let tcx = self.tcx;
let lang_items = tcx.lang_items();
pub crate_deps: LazySeq<CrateDep>,
pub dylib_dependency_formats: LazySeq<Option<LinkagePreference>>,
+ pub lib_features: LazySeq<(Symbol, Option<Symbol>)>,
pub lang_items: LazySeq<(DefIndex, usize)>,
pub lang_items_missing: LazySeq<lang_items::LangItem>,
pub native_libraries: LazySeq<NativeLibrary>,
"##,
+E0635: r##"
+The `#![feature]` attribute specified an unknown feature.
+
+Erroneous code example:
+
+```compile_fail,E0635
+#![feature(nonexistent_rust_feature)] // error: unknown feature
+```
+
+"##,
+
+
}
register_diagnostics! {