]> git.lizzy.rs Git - rust.git/commitdiff
move feature_gate to libsyntax
authorNick Cameron <ncameron@mozilla.com>
Thu, 11 Sep 2014 00:55:42 +0000 (12:55 +1200)
committerNick Cameron <ncameron@mozilla.com>
Wed, 17 Sep 2014 04:53:20 +0000 (16:53 +1200)
src/librustc/driver/driver.rs
src/librustc/driver/session.rs
src/librustc/front/feature_gate.rs [deleted file]
src/librustc/lib.rs
src/librustc/middle/resolve.rs
src/librustc/middle/typeck/astconv.rs
src/librustc/middle/typeck/check/mod.rs
src/libsyntax/feature_gate.rs [new file with mode: 0644]
src/libsyntax/lib.rs

index 4c6bb2de180608f0dbd7fb6ebea875590e1eff3f..20371f63a3427d7fe9e45dc35b1bbf86a7bccfee 100644 (file)
@@ -13,7 +13,6 @@
 use back::write;
 use driver::session::Session;
 use driver::config;
-use front;
 use lint;
 use llvm::{ContextRef, ModuleRef};
 use metadata::common::LinkMeta;
@@ -194,8 +193,20 @@ pub fn phase_2_configure_and_expand(sess: &Session,
     *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
@@ -225,7 +236,7 @@ pub fn phase_2_configure_and_expand(sess: &Session,
     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",
@@ -277,7 +288,7 @@ pub fn phase_2_configure_and_expand(sess: &Session,
                 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,
index 2d28a9294e4fd93d8930f451de3d46029af875c6..d7ed5d3e1ffa446f005d46bf201a5083640b0061 100644 (file)
@@ -11,7 +11,6 @@
 
 use driver::config;
 use driver::driver;
-use front;
 use metadata::cstore::CStore;
 use metadata::filesearch;
 use lint;
@@ -21,6 +20,7 @@
 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;
@@ -49,7 +49,7 @@ pub struct Session {
     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.
@@ -245,7 +245,7 @@ pub fn build_session_(sopts: config::Options,
         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),
     };
 
diff --git a/src/librustc/front/feature_gate.rs b/src/librustc/front/feature_gate.rs
deleted file mode 100644 (file)
index 13a40ab..0000000
+++ /dev/null
@@ -1,465 +0,0 @@
-// 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 &quote 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"));
-}
-
index e1a82d1db7c529bbf225ec55a4edf8451a079612..81234f36ade50b32b375fa0d3e1694322e7c7ea6 100644 (file)
@@ -116,10 +116,6 @@ pub mod middle {
     pub mod weak_lang_items;
 }
 
-pub mod front {
-    pub mod feature_gate;
-}
-
 pub mod metadata;
 
 pub mod driver;
index ded4883350ff2c6cc1ec1e7debd7646209b31475..d4fe3c265f518dd92a69b3f7acbfbba3566d2386 100644 (file)
@@ -2811,7 +2811,7 @@ fn check_for_conflicting_import(&mut self,
                                     import_span: Span,
                                     name: Name,
                                     namespace: Namespace) {
-        if self.session.features.import_shadowing.get() {
+        if self.session.features.borrow().import_shadowing {
             return
         }
 
@@ -2837,7 +2837,7 @@ fn check_for_conflicts_between_imports_and_items(&mut self,
                                                      &mut ImportResolution,
                                                      import_span: Span,
                                                      name: Name) {
-        if self.session.features.import_shadowing.get() {
+        if self.session.features.borrow().import_shadowing {
             return
         }
 
@@ -2919,7 +2919,7 @@ fn check_for_conflicts_between_external_crates(&self,
                                                    module: &Module,
                                                    name: Name,
                                                    span: Span) {
-        if self.session.features.import_shadowing.get() {
+        if self.session.features.borrow().import_shadowing {
             return
         }
 
@@ -2937,7 +2937,7 @@ fn check_for_conflicts_between_external_crates_and_items(&self,
                                                              module: &Module,
                                                              name: Name,
                                                              span: Span) {
-        if self.session.features.import_shadowing.get() {
+        if self.session.features.borrow().import_shadowing {
             return
         }
 
index cb449f80ed4a49f7905523ec9134e9f37625117c..c46e95cf045f5eab247e77a88bc27b2e5431e6b0 100644 (file)
@@ -235,7 +235,7 @@ fn ast_path_substs<'tcx, AC: AstConv<'tcx>, RS: RegionScope>(
     }
 
     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,
index 20fe8186adf40fe50100022eb2ae24fae60d0cf8..12905763f522b442c0bee6350cbf62d43f15c725 100644 (file)
@@ -2131,7 +2131,7 @@ fn try_overloaded_call(fcx: &FnCtxt,
         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,
diff --git a/src/libsyntax/feature_gate.rs b/src/libsyntax/feature_gate.rs
new file mode 100644 (file)
index 0000000..e22e551
--- /dev/null
@@ -0,0 +1,461 @@
+// 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 &quote 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)
+}
+
index 8122aa1dcc21c671d9ec827a680aeed5cbe7dfef..457d77efb708e2846d2ac5c8af602046650aee79 100644 (file)
@@ -62,6 +62,7 @@ pub mod syntax {
 pub mod config;
 pub mod crateid;
 pub mod diagnostic;
+pub mod feature_gate;
 pub mod fold;
 pub mod owned_slice;
 pub mod parse;