use back::write;
use driver::session::Session;
use driver::config;
-use front;
use lint;
use llvm::{ContextRef, ModuleRef};
use metadata::common::LinkMeta;
*sess.crate_metadata.borrow_mut() =
collect_crate_metadata(sess, krate.attrs.as_slice());
- time(time_passes, "gated feature checking", (), |_|
- front::feature_gate::check_crate(sess, &krate));
+ time(time_passes, "gated feature checking", (), |_| {
+ let (features, unknown_features) =
+ syntax::feature_gate::check_crate(&sess.parse_sess.span_diagnostic, &krate);
+
+ for uf in unknown_features.iter() {
+ sess.add_lint(lint::builtin::UNKNOWN_FEATURES,
+ ast::CRATE_NODE_ID,
+ *uf,
+ "unknown feature".to_string());
+ }
+
+ sess.abort_if_errors();
+ *sess.features.borrow_mut() = features;
+ });
let any_exe = sess.crate_types.borrow().iter().any(|ty| {
*ty == config::CrateTypeExecutable
let mut registry = Registry::new(&krate);
time(time_passes, "plugin registration", (), |_| {
- if sess.features.rustc_diagnostic_macros.get() {
+ if sess.features.borrow().rustc_diagnostic_macros {
registry.register_macro("__diagnostic_used",
diagnostics::plugin::expand_diagnostic_used);
registry.register_macro("__register_diagnostic",
os::setenv("PATH", os::join_paths(new_path.as_slice()).unwrap());
}
let cfg = syntax::ext::expand::ExpansionConfig {
- deriving_hash_type_parameter: sess.features.default_type_params.get(),
+ deriving_hash_type_parameter: sess.features.borrow().default_type_params,
crate_name: crate_name.to_string(),
};
let ret = syntax::ext::expand::expand_crate(&sess.parse_sess,
use driver::config;
use driver::driver;
-use front;
use metadata::cstore::CStore;
use metadata::filesearch;
use lint;
use syntax::codemap::Span;
use syntax::diagnostic;
use syntax::diagnostics;
+use syntax::feature_gate;
use syntax::parse;
use syntax::parse::token;
use syntax::parse::ParseSess;
pub lints: RefCell<NodeMap<Vec<(lint::LintId, codemap::Span, String)>>>,
pub crate_types: RefCell<Vec<config::CrateType>>,
pub crate_metadata: RefCell<Vec<String>>,
- pub features: front::feature_gate::Features,
+ pub features: RefCell<feature_gate::Features>,
/// The maximum recursion limit for potentially infinitely recursive
/// operations such as auto-dereference and monomorphization.
lints: RefCell::new(NodeMap::new()),
crate_types: RefCell::new(Vec::new()),
crate_metadata: RefCell::new(Vec::new()),
- features: front::feature_gate::Features::new(),
+ features: RefCell::new(feature_gate::Features::new()),
recursion_limit: Cell::new(64),
};
+++ /dev/null
-// Copyright 2013 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.
-
-//! Feature gating
-//!
-//! This modules implements the gating necessary for preventing certain compiler
-//! features from being used by default. This module will crawl a pre-expanded
-//! AST to ensure that there are no features which are used that are not
-//! enabled.
-//!
-//! Features are enabled in programs via the crate-level attributes of
-//! `#![feature(...)]` with a comma-separated list of features.
-
-use lint;
-
-use syntax::abi::RustIntrinsic;
-use syntax::ast::NodeId;
-use syntax::ast;
-use syntax::attr;
-use syntax::attr::AttrMetaMethods;
-use syntax::codemap::Span;
-use syntax::visit;
-use syntax::visit::Visitor;
-use syntax::parse::token;
-
-use driver::session::Session;
-
-use std::cell::Cell;
-use std::slice;
-
-/// This is a list of all known features since the beginning of time. This list
-/// can never shrink, it may only be expanded (in order to prevent old programs
-/// from failing to compile). The status of each feature may change, however.
-static KNOWN_FEATURES: &'static [(&'static str, Status)] = &[
- ("globs", Active),
- ("macro_rules", Active),
- ("struct_variant", Active),
- ("once_fns", Active),
- ("asm", Active),
- ("managed_boxes", Active),
- ("non_ascii_idents", Active),
- ("thread_local", Active),
- ("link_args", Active),
- ("phase", Active),
- ("plugin_registrar", Active),
- ("log_syntax", Active),
- ("trace_macros", Active),
- ("concat_idents", Active),
- ("unsafe_destructor", Active),
- ("intrinsics", Active),
- ("lang_items", Active),
-
- ("simd", Active),
- ("default_type_params", Active),
- ("quote", Active),
- ("linkage", Active),
- ("struct_inherit", Active),
- ("overloaded_calls", Active),
- ("unboxed_closure_sugar", Active),
-
- ("quad_precision_float", Removed),
-
- ("rustc_diagnostic_macros", Active),
- ("unboxed_closures", Active),
- ("import_shadowing", Active),
- ("advanced_slice_patterns", Active),
- ("tuple_indexing", Active),
-
- // if you change this list without updating src/doc/rust.md, cmr will be sad
-
- // A temporary feature gate used to enable parser extensions needed
- // to bootstrap fix for #5723.
- ("issue_5723_bootstrap", Accepted),
-
- // These are used to test this portion of the compiler, they don't actually
- // mean anything
- ("test_accepted_feature", Accepted),
- ("test_removed_feature", Removed),
-];
-
-enum Status {
- /// Represents an active feature that is currently being implemented or
- /// currently being considered for addition/removal.
- Active,
-
- /// Represents a feature which has since been removed (it was once Active)
- Removed,
-
- /// This language feature has since been Accepted (it was once Active)
- Accepted,
-}
-
-/// A set of features to be used by later passes.
-pub struct Features {
- pub default_type_params: Cell<bool>,
- pub overloaded_calls: Cell<bool>,
- pub rustc_diagnostic_macros: Cell<bool>,
- pub import_shadowing: Cell<bool>,
-}
-
-impl Features {
- pub fn new() -> Features {
- Features {
- default_type_params: Cell::new(false),
- overloaded_calls: Cell::new(false),
- rustc_diagnostic_macros: Cell::new(false),
- import_shadowing: Cell::new(false),
- }
- }
-}
-
-struct Context<'a> {
- features: Vec<&'static str>,
- sess: &'a Session,
-}
-
-impl<'a> Context<'a> {
- fn gate_feature(&self, feature: &str, span: Span, explain: &str) {
- if !self.has_feature(feature) {
- self.sess.span_err(span, explain);
- self.sess.span_note(span, format!("add #![feature({})] to the \
- crate attributes to enable",
- feature).as_slice());
- }
- }
-
- fn gate_box(&self, span: Span) {
- self.gate_feature("managed_boxes", span,
- "The managed box syntax is being replaced by the \
- `std::gc::Gc` and `std::rc::Rc` types. Equivalent \
- functionality to managed trait objects will be \
- implemented but is currently missing.");
- }
-
- fn has_feature(&self, feature: &str) -> bool {
- self.features.iter().any(|n| n.as_slice() == feature)
- }
-}
-
-impl<'a, 'v> Visitor<'v> for Context<'a> {
- fn visit_ident(&mut self, sp: Span, id: ast::Ident) {
- if !token::get_ident(id).get().is_ascii() {
- self.gate_feature("non_ascii_idents", sp,
- "non-ascii idents are not fully supported.");
- }
- }
-
- fn visit_view_item(&mut self, i: &ast::ViewItem) {
- match i.node {
- ast::ViewItemUse(ref path) => {
- match path.node {
- ast::ViewPathGlob(..) => {
- self.gate_feature("globs", path.span,
- "glob import statements are \
- experimental and possibly buggy");
- }
- _ => {}
- }
- }
- ast::ViewItemExternCrate(..) => {
- for attr in i.attrs.iter() {
- if attr.name().get() == "phase"{
- self.gate_feature("phase", attr.span,
- "compile time crate loading is \
- experimental and possibly buggy");
- }
- }
- }
- }
- visit::walk_view_item(self, i)
- }
-
- fn visit_item(&mut self, i: &ast::Item) {
- for attr in i.attrs.iter() {
- if attr.name().equiv(&("thread_local")) {
- self.gate_feature("thread_local", i.span,
- "`#[thread_local]` is an experimental feature, and does not \
- currently handle destructors. There is no corresponding \
- `#[task_local]` mapping to the task model");
- }
- }
- match i.node {
- ast::ItemEnum(ref def, _) => {
- for variant in def.variants.iter() {
- match variant.node.kind {
- ast::StructVariantKind(..) => {
- self.gate_feature("struct_variant", variant.span,
- "enum struct variants are \
- experimental and possibly buggy");
- }
- _ => {}
- }
- }
- }
-
- ast::ItemForeignMod(ref foreign_module) => {
- if attr::contains_name(i.attrs.as_slice(), "link_args") {
- self.gate_feature("link_args", i.span,
- "the `link_args` attribute is not portable \
- across platforms, it is recommended to \
- use `#[link(name = \"foo\")]` instead")
- }
- if foreign_module.abi == RustIntrinsic {
- self.gate_feature("intrinsics",
- i.span,
- "intrinsics are subject to change")
- }
- }
-
- ast::ItemFn(..) => {
- if attr::contains_name(i.attrs.as_slice(), "plugin_registrar") {
- self.gate_feature("plugin_registrar", i.span,
- "compiler plugins are experimental and possibly buggy");
- }
- }
-
- ast::ItemStruct(ref struct_definition, _) => {
- if attr::contains_name(i.attrs.as_slice(), "simd") {
- self.gate_feature("simd", i.span,
- "SIMD types are experimental and possibly buggy");
- }
- match struct_definition.super_struct {
- Some(ref path) => self.gate_feature("struct_inherit", path.span,
- "struct inheritance is experimental \
- and possibly buggy"),
- None => {}
- }
- if struct_definition.is_virtual {
- self.gate_feature("struct_inherit", i.span,
- "struct inheritance (`virtual` keyword) is \
- experimental and possibly buggy");
- }
- }
-
- ast::ItemImpl(..) => {
- if attr::contains_name(i.attrs.as_slice(),
- "unsafe_destructor") {
- self.gate_feature("unsafe_destructor",
- i.span,
- "`#[unsafe_destructor]` allows too \
- many unsafe patterns and may be \
- removed in the future");
- }
- }
-
- _ => {}
- }
-
- visit::walk_item(self, i);
- }
-
- fn visit_mac(&mut self, macro: &ast::Mac) {
- let ast::MacInvocTT(ref path, _, _) = macro.node;
- let id = path.segments.last().unwrap().identifier;
- let quotes = ["quote_tokens", "quote_expr", "quote_ty",
- "quote_item", "quote_pat", "quote_stmt"];
- let msg = " is not stable enough for use and are subject to change";
-
-
- if id == token::str_to_ident("macro_rules") {
- self.gate_feature("macro_rules", path.span, "macro definitions are \
- not stable enough for use and are subject to change");
- }
-
- else if id == token::str_to_ident("asm") {
- self.gate_feature("asm", path.span, "inline assembly is not \
- stable enough for use and is subject to change");
- }
-
- else if id == token::str_to_ident("log_syntax") {
- self.gate_feature("log_syntax", path.span, "`log_syntax!` is not \
- stable enough for use and is subject to change");
- }
-
- else if id == token::str_to_ident("trace_macros") {
- self.gate_feature("trace_macros", path.span, "`trace_macros` is not \
- stable enough for use and is subject to change");
- }
-
- else if id == token::str_to_ident("concat_idents") {
- self.gate_feature("concat_idents", path.span, "`concat_idents` is not \
- stable enough for use and is subject to change");
- }
-
- else {
- for "e in quotes.iter() {
- if id == token::str_to_ident(quote) {
- self.gate_feature("quote",
- path.span,
- format!("{}{}", quote, msg).as_slice());
- }
- }
- }
- }
-
- fn visit_foreign_item(&mut self, i: &ast::ForeignItem) {
- if attr::contains_name(i.attrs.as_slice(), "linkage") {
- self.gate_feature("linkage", i.span,
- "the `linkage` attribute is experimental \
- and not portable across platforms")
- }
- visit::walk_foreign_item(self, i)
- }
-
- fn visit_ty(&mut self, t: &ast::Ty) {
- match t.node {
- ast::TyClosure(ref closure) if closure.onceness == ast::Once => {
- self.gate_feature("once_fns", t.span,
- "once functions are \
- experimental and likely to be removed");
-
- },
- ast::TyBox(_) => { self.gate_box(t.span); }
- ast::TyUnboxedFn(..) => {
- self.gate_feature("unboxed_closure_sugar",
- t.span,
- "unboxed closure trait sugar is experimental");
- }
- _ => {}
- }
-
- visit::walk_ty(self, t);
- }
-
- fn visit_expr(&mut self, e: &ast::Expr) {
- match e.node {
- ast::ExprUnary(ast::UnBox, _) => {
- self.gate_box(e.span);
- }
- ast::ExprUnboxedFn(..) => {
- self.gate_feature("unboxed_closures",
- e.span,
- "unboxed closures are a work-in-progress \
- feature with known bugs");
- }
- ast::ExprTupField(..) => {
- self.gate_feature("tuple_indexing",
- e.span,
- "tuple indexing is experimental");
- }
- _ => {}
- }
- visit::walk_expr(self, e);
- }
-
- fn visit_generics(&mut self, generics: &ast::Generics) {
- for type_parameter in generics.ty_params.iter() {
- match type_parameter.default {
- Some(ref ty) => {
- self.gate_feature("default_type_params", ty.span,
- "default type parameters are \
- experimental and possibly buggy");
- }
- None => {}
- }
- }
- visit::walk_generics(self, generics);
- }
-
- fn visit_attribute(&mut self, attr: &ast::Attribute) {
- if attr::contains_name(slice::ref_slice(attr), "lang") {
- self.gate_feature("lang_items",
- attr.span,
- "language items are subject to change");
- }
- }
-
- fn visit_pat(&mut self, pattern: &ast::Pat) {
- match pattern.node {
- ast::PatVec(_, Some(_), ref last) if !last.is_empty() => {
- self.gate_feature("advanced_slice_patterns",
- pattern.span,
- "multiple-element slice matches anywhere \
- but at the end of a slice (e.g. \
- `[0, ..xs, 0]` are experimental")
- }
- _ => {}
- }
- visit::walk_pat(self, pattern)
- }
-
- fn visit_fn(&mut self,
- fn_kind: visit::FnKind<'v>,
- fn_decl: &'v ast::FnDecl,
- block: &'v ast::Block,
- span: Span,
- _: NodeId) {
- match fn_kind {
- visit::FkItemFn(_, _, _, abi) if abi == RustIntrinsic => {
- self.gate_feature("intrinsics",
- span,
- "intrinsics are subject to change")
- }
- _ => {}
- }
- visit::walk_fn(self, fn_kind, fn_decl, block, span);
- }
-}
-
-pub fn check_crate(sess: &Session, krate: &ast::Crate) {
- let mut cx = Context {
- features: Vec::new(),
- sess: sess,
- };
-
- for attr in krate.attrs.iter() {
- if !attr.check_name("feature") {
- continue
- }
-
- match attr.meta_item_list() {
- None => {
- sess.span_err(attr.span, "malformed feature attribute, \
- expected #![feature(...)]");
- }
- Some(list) => {
- for mi in list.iter() {
- let name = match mi.node {
- ast::MetaWord(ref word) => (*word).clone(),
- _ => {
- sess.span_err(mi.span,
- "malformed feature, expected just \
- one word");
- continue
- }
- };
- match KNOWN_FEATURES.iter()
- .find(|& &(n, _)| name.equiv(&n)) {
- Some(&(name, Active)) => { cx.features.push(name); }
- Some(&(_, Removed)) => {
- sess.span_err(mi.span, "feature has been removed");
- }
- Some(&(_, Accepted)) => {
- sess.span_warn(mi.span, "feature has been added to Rust, \
- directive not necessary");
- }
- None => {
- sess.add_lint(lint::builtin::UNKNOWN_FEATURES,
- ast::CRATE_NODE_ID,
- mi.span,
- "unknown feature".to_string());
- }
- }
- }
- }
- }
- }
-
- visit::walk_crate(&mut cx, krate);
-
- sess.abort_if_errors();
-
- sess.features.default_type_params.set(cx.has_feature("default_type_params"));
- sess.features.overloaded_calls.set(cx.has_feature("overloaded_calls"));
- sess.features.rustc_diagnostic_macros.set(cx.has_feature("rustc_diagnostic_macros"));
- sess.features.import_shadowing.set(cx.has_feature("import_shadowing"));
-}
-
pub mod weak_lang_items;
}
-pub mod front {
- pub mod feature_gate;
-}
-
pub mod metadata;
pub mod driver;
import_span: Span,
name: Name,
namespace: Namespace) {
- if self.session.features.import_shadowing.get() {
+ if self.session.features.borrow().import_shadowing {
return
}
&mut ImportResolution,
import_span: Span,
name: Name) {
- if self.session.features.import_shadowing.get() {
+ if self.session.features.borrow().import_shadowing {
return
}
module: &Module,
name: Name,
span: Span) {
- if self.session.features.import_shadowing.get() {
+ if self.session.features.borrow().import_shadowing {
return
}
module: &Module,
name: Name,
span: Span) {
- if self.session.features.import_shadowing.get() {
+ if self.session.features.borrow().import_shadowing {
return
}
}
if supplied_ty_param_count > required_ty_param_count
- && !this.tcx().sess.features.default_type_params.get() {
+ && !this.tcx().sess.features.borrow().default_type_params {
span_err!(this.tcx().sess, path.span, E0108,
"default type parameters are experimental and possibly buggy");
span_note!(this.tcx().sess, path.span,
fcx.inh.method_map.borrow_mut().insert(method_call, method_callee);
write_call(fcx, call_expression, output_type);
- if !fcx.tcx().sess.features.overloaded_calls.get() {
+ if !fcx.tcx().sess.features.borrow().overloaded_calls {
span_err!(fcx.tcx().sess, call_expression.span, E0056,
"overloaded calls are experimental");
span_note!(fcx.tcx().sess, call_expression.span,
--- /dev/null
+// Copyright 2013 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.
+
+//! Feature gating
+//!
+//! This modules implements the gating necessary for preventing certain compiler
+//! features from being used by default. This module will crawl a pre-expanded
+//! AST to ensure that there are no features which are used that are not
+//! enabled.
+//!
+//! Features are enabled in programs via the crate-level attributes of
+//! `#![feature(...)]` with a comma-separated list of features.
+
+use abi::RustIntrinsic;
+use ast::NodeId;
+use ast;
+use attr;
+use attr::AttrMetaMethods;
+use codemap::Span;
+use diagnostic::SpanHandler;
+use visit;
+use visit::Visitor;
+use parse::token;
+
+use std::slice;
+
+/// This is a list of all known features since the beginning of time. This list
+/// can never shrink, it may only be expanded (in order to prevent old programs
+/// from failing to compile). The status of each feature may change, however.
+static KNOWN_FEATURES: &'static [(&'static str, Status)] = &[
+ ("globs", Active),
+ ("macro_rules", Active),
+ ("struct_variant", Active),
+ ("once_fns", Active),
+ ("asm", Active),
+ ("managed_boxes", Active),
+ ("non_ascii_idents", Active),
+ ("thread_local", Active),
+ ("link_args", Active),
+ ("phase", Active),
+ ("plugin_registrar", Active),
+ ("log_syntax", Active),
+ ("trace_macros", Active),
+ ("concat_idents", Active),
+ ("unsafe_destructor", Active),
+ ("intrinsics", Active),
+ ("lang_items", Active),
+
+ ("simd", Active),
+ ("default_type_params", Active),
+ ("quote", Active),
+ ("linkage", Active),
+ ("struct_inherit", Active),
+ ("overloaded_calls", Active),
+ ("unboxed_closure_sugar", Active),
+
+ ("quad_precision_float", Removed),
+
+ ("rustc_diagnostic_macros", Active),
+ ("unboxed_closures", Active),
+ ("import_shadowing", Active),
+ ("advanced_slice_patterns", Active),
+ ("tuple_indexing", Active),
+
+ // if you change this list without updating src/doc/rust.md, cmr will be sad
+
+ // A temporary feature gate used to enable parser extensions needed
+ // to bootstrap fix for #5723.
+ ("issue_5723_bootstrap", Accepted),
+
+ // These are used to test this portion of the compiler, they don't actually
+ // mean anything
+ ("test_accepted_feature", Accepted),
+ ("test_removed_feature", Removed),
+];
+
+enum Status {
+ /// Represents an active feature that is currently being implemented or
+ /// currently being considered for addition/removal.
+ Active,
+
+ /// Represents a feature which has since been removed (it was once Active)
+ Removed,
+
+ /// This language feature has since been Accepted (it was once Active)
+ Accepted,
+}
+
+/// A set of features to be used by later passes.
+pub struct Features {
+ pub default_type_params: bool,
+ pub overloaded_calls: bool,
+ pub rustc_diagnostic_macros: bool,
+ pub import_shadowing: bool,
+}
+
+impl Features {
+ pub fn new() -> Features {
+ Features {
+ default_type_params: false,
+ overloaded_calls: false,
+ rustc_diagnostic_macros: false,
+ import_shadowing: false,
+ }
+ }
+}
+
+struct Context<'a> {
+ features: Vec<&'static str>,
+ span_handler: &'a SpanHandler,
+}
+
+impl<'a> Context<'a> {
+ fn gate_feature(&self, feature: &str, span: Span, explain: &str) {
+ if !self.has_feature(feature) {
+ self.span_handler.span_err(span, explain);
+ self.span_handler.span_note(span, format!("add #![feature({})] to the \
+ crate attributes to enable",
+ feature).as_slice());
+ }
+ }
+
+ fn gate_box(&self, span: Span) {
+ self.gate_feature("managed_boxes", span,
+ "The managed box syntax is being replaced by the \
+ `std::gc::Gc` and `std::rc::Rc` types. Equivalent \
+ functionality to managed trait objects will be \
+ implemented but is currently missing.");
+ }
+
+ fn has_feature(&self, feature: &str) -> bool {
+ self.features.iter().any(|n| n.as_slice() == feature)
+ }
+}
+
+impl<'a, 'v> Visitor<'v> for Context<'a> {
+ fn visit_ident(&mut self, sp: Span, id: ast::Ident) {
+ if !token::get_ident(id).get().is_ascii() {
+ self.gate_feature("non_ascii_idents", sp,
+ "non-ascii idents are not fully supported.");
+ }
+ }
+
+ fn visit_view_item(&mut self, i: &ast::ViewItem) {
+ match i.node {
+ ast::ViewItemUse(ref path) => {
+ match path.node {
+ ast::ViewPathGlob(..) => {
+ self.gate_feature("globs", path.span,
+ "glob import statements are \
+ experimental and possibly buggy");
+ }
+ _ => {}
+ }
+ }
+ ast::ViewItemExternCrate(..) => {
+ for attr in i.attrs.iter() {
+ if attr.name().get() == "phase"{
+ self.gate_feature("phase", attr.span,
+ "compile time crate loading is \
+ experimental and possibly buggy");
+ }
+ }
+ }
+ }
+ visit::walk_view_item(self, i)
+ }
+
+ fn visit_item(&mut self, i: &ast::Item) {
+ for attr in i.attrs.iter() {
+ if attr.name().equiv(&("thread_local")) {
+ self.gate_feature("thread_local", i.span,
+ "`#[thread_local]` is an experimental feature, and does not \
+ currently handle destructors. There is no corresponding \
+ `#[task_local]` mapping to the task model");
+ }
+ }
+ match i.node {
+ ast::ItemEnum(ref def, _) => {
+ for variant in def.variants.iter() {
+ match variant.node.kind {
+ ast::StructVariantKind(..) => {
+ self.gate_feature("struct_variant", variant.span,
+ "enum struct variants are \
+ experimental and possibly buggy");
+ }
+ _ => {}
+ }
+ }
+ }
+
+ ast::ItemForeignMod(ref foreign_module) => {
+ if attr::contains_name(i.attrs.as_slice(), "link_args") {
+ self.gate_feature("link_args", i.span,
+ "the `link_args` attribute is not portable \
+ across platforms, it is recommended to \
+ use `#[link(name = \"foo\")]` instead")
+ }
+ if foreign_module.abi == RustIntrinsic {
+ self.gate_feature("intrinsics",
+ i.span,
+ "intrinsics are subject to change")
+ }
+ }
+
+ ast::ItemFn(..) => {
+ if attr::contains_name(i.attrs.as_slice(), "plugin_registrar") {
+ self.gate_feature("plugin_registrar", i.span,
+ "compiler plugins are experimental and possibly buggy");
+ }
+ }
+
+ ast::ItemStruct(ref struct_definition, _) => {
+ if attr::contains_name(i.attrs.as_slice(), "simd") {
+ self.gate_feature("simd", i.span,
+ "SIMD types are experimental and possibly buggy");
+ }
+ match struct_definition.super_struct {
+ Some(ref path) => self.gate_feature("struct_inherit", path.span,
+ "struct inheritance is experimental \
+ and possibly buggy"),
+ None => {}
+ }
+ if struct_definition.is_virtual {
+ self.gate_feature("struct_inherit", i.span,
+ "struct inheritance (`virtual` keyword) is \
+ experimental and possibly buggy");
+ }
+ }
+
+ ast::ItemImpl(..) => {
+ if attr::contains_name(i.attrs.as_slice(),
+ "unsafe_destructor") {
+ self.gate_feature("unsafe_destructor",
+ i.span,
+ "`#[unsafe_destructor]` allows too \
+ many unsafe patterns and may be \
+ removed in the future");
+ }
+ }
+
+ _ => {}
+ }
+
+ visit::walk_item(self, i);
+ }
+
+ fn visit_mac(&mut self, macro: &ast::Mac) {
+ let ast::MacInvocTT(ref path, _, _) = macro.node;
+ let id = path.segments.last().unwrap().identifier;
+ let quotes = ["quote_tokens", "quote_expr", "quote_ty",
+ "quote_item", "quote_pat", "quote_stmt"];
+ let msg = " is not stable enough for use and are subject to change";
+
+
+ if id == token::str_to_ident("macro_rules") {
+ self.gate_feature("macro_rules", path.span, "macro definitions are \
+ not stable enough for use and are subject to change");
+ }
+
+ else if id == token::str_to_ident("asm") {
+ self.gate_feature("asm", path.span, "inline assembly is not \
+ stable enough for use and is subject to change");
+ }
+
+ else if id == token::str_to_ident("log_syntax") {
+ self.gate_feature("log_syntax", path.span, "`log_syntax!` is not \
+ stable enough for use and is subject to change");
+ }
+
+ else if id == token::str_to_ident("trace_macros") {
+ self.gate_feature("trace_macros", path.span, "`trace_macros` is not \
+ stable enough for use and is subject to change");
+ }
+
+ else if id == token::str_to_ident("concat_idents") {
+ self.gate_feature("concat_idents", path.span, "`concat_idents` is not \
+ stable enough for use and is subject to change");
+ }
+
+ else {
+ for "e in quotes.iter() {
+ if id == token::str_to_ident(quote) {
+ self.gate_feature("quote",
+ path.span,
+ format!("{}{}", quote, msg).as_slice());
+ }
+ }
+ }
+ }
+
+ fn visit_foreign_item(&mut self, i: &ast::ForeignItem) {
+ if attr::contains_name(i.attrs.as_slice(), "linkage") {
+ self.gate_feature("linkage", i.span,
+ "the `linkage` attribute is experimental \
+ and not portable across platforms")
+ }
+ visit::walk_foreign_item(self, i)
+ }
+
+ fn visit_ty(&mut self, t: &ast::Ty) {
+ match t.node {
+ ast::TyClosure(ref closure) if closure.onceness == ast::Once => {
+ self.gate_feature("once_fns", t.span,
+ "once functions are \
+ experimental and likely to be removed");
+
+ },
+ ast::TyBox(_) => { self.gate_box(t.span); }
+ ast::TyUnboxedFn(..) => {
+ self.gate_feature("unboxed_closure_sugar",
+ t.span,
+ "unboxed closure trait sugar is experimental");
+ }
+ _ => {}
+ }
+
+ visit::walk_ty(self, t);
+ }
+
+ fn visit_expr(&mut self, e: &ast::Expr) {
+ match e.node {
+ ast::ExprUnary(ast::UnBox, _) => {
+ self.gate_box(e.span);
+ }
+ ast::ExprUnboxedFn(..) => {
+ self.gate_feature("unboxed_closures",
+ e.span,
+ "unboxed closures are a work-in-progress \
+ feature with known bugs");
+ }
+ ast::ExprTupField(..) => {
+ self.gate_feature("tuple_indexing",
+ e.span,
+ "tuple indexing is experimental");
+ }
+ _ => {}
+ }
+ visit::walk_expr(self, e);
+ }
+
+ fn visit_generics(&mut self, generics: &ast::Generics) {
+ for type_parameter in generics.ty_params.iter() {
+ match type_parameter.default {
+ Some(ref ty) => {
+ self.gate_feature("default_type_params", ty.span,
+ "default type parameters are \
+ experimental and possibly buggy");
+ }
+ None => {}
+ }
+ }
+ visit::walk_generics(self, generics);
+ }
+
+ fn visit_attribute(&mut self, attr: &ast::Attribute) {
+ if attr::contains_name(slice::ref_slice(attr), "lang") {
+ self.gate_feature("lang_items",
+ attr.span,
+ "language items are subject to change");
+ }
+ }
+
+ fn visit_pat(&mut self, pattern: &ast::Pat) {
+ match pattern.node {
+ ast::PatVec(_, Some(_), ref last) if !last.is_empty() => {
+ self.gate_feature("advanced_slice_patterns",
+ pattern.span,
+ "multiple-element slice matches anywhere \
+ but at the end of a slice (e.g. \
+ `[0, ..xs, 0]` are experimental")
+ }
+ _ => {}
+ }
+ visit::walk_pat(self, pattern)
+ }
+
+ fn visit_fn(&mut self,
+ fn_kind: visit::FnKind<'v>,
+ fn_decl: &'v ast::FnDecl,
+ block: &'v ast::Block,
+ span: Span,
+ _: NodeId) {
+ match fn_kind {
+ visit::FkItemFn(_, _, _, abi) if abi == RustIntrinsic => {
+ self.gate_feature("intrinsics",
+ span,
+ "intrinsics are subject to change")
+ }
+ _ => {}
+ }
+ visit::walk_fn(self, fn_kind, fn_decl, block, span);
+ }
+}
+
+pub fn check_crate(span_handler: &SpanHandler, krate: &ast::Crate) -> (Features, Vec<Span>) {
+ let mut cx = Context {
+ features: Vec::new(),
+ span_handler: span_handler,
+ };
+
+ let mut unknown_features = Vec::new();
+
+ for attr in krate.attrs.iter() {
+ if !attr.check_name("feature") {
+ continue
+ }
+
+ match attr.meta_item_list() {
+ None => {
+ span_handler.span_err(attr.span, "malformed feature attribute, \
+ expected #![feature(...)]");
+ }
+ Some(list) => {
+ for mi in list.iter() {
+ let name = match mi.node {
+ ast::MetaWord(ref word) => (*word).clone(),
+ _ => {
+ span_handler.span_err(mi.span,
+ "malformed feature, expected just \
+ one word");
+ continue
+ }
+ };
+ match KNOWN_FEATURES.iter()
+ .find(|& &(n, _)| name.equiv(&n)) {
+ Some(&(name, Active)) => { cx.features.push(name); }
+ Some(&(_, Removed)) => {
+ span_handler.span_err(mi.span, "feature has been removed");
+ }
+ Some(&(_, Accepted)) => {
+ span_handler.span_warn(mi.span, "feature has been added to Rust, \
+ directive not necessary");
+ }
+ None => {
+ unknown_features.push(mi.span);
+ }
+ }
+ }
+ }
+ }
+ }
+
+ visit::walk_crate(&mut cx, krate);
+
+ (Features {
+ default_type_params: cx.has_feature("default_type_params"),
+ overloaded_calls: cx.has_feature("overloaded_calls"),
+ rustc_diagnostic_macros: cx.has_feature("rustc_diagnostic_macros"),
+ import_shadowing: cx.has_feature("import_shadowing"),
+ },
+ unknown_features)
+}
+
pub mod config;
pub mod crateid;
pub mod diagnostic;
+pub mod feature_gate;
pub mod fold;
pub mod owned_slice;
pub mod parse;