1 // Copyright 2013 The Rust Project Developers. See the COPYRIGHT
2 // file at the top-level directory of this distribution and at
3 // http://rust-lang.org/COPYRIGHT.
5 // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6 // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7 // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8 // option. This file may not be copied, modified, or distributed
9 // except according to those terms.
13 //! This modules implements the gating necessary for preventing certain compiler
14 //! features from being used by default. This module will crawl a pre-expanded
15 //! AST to ensure that there are no features which are used that are not
18 //! Features are enabled in programs via the crate-level attributes of
19 //! #[feature(...)] with a comma-separated list of features.
22 use syntax::attr::AttrMetaMethods;
23 use syntax::codemap::Span;
25 use syntax::visit::Visitor;
27 use driver::session::Session;
29 /// This is a list of all known features since the beginning of time. This list
30 /// can never shrink, it may only be expanded (in order to prevent old programs
31 /// from failing to compile). The status of each feature may change, however.
32 static KNOWN_FEATURES: &'static [(&'static str, Status)] = &[
34 ("macro_rules", Active),
35 ("struct_variant", Active),
38 ("managed_boxes", Active),
40 // These are used to test this portion of the compiler, they don't actually
42 ("test_accepted_feature", Accepted),
43 ("test_removed_feature", Removed),
47 /// Represents an active feature that is currently being implemented or
48 /// currently being considered for addition/removal.
51 /// Represents a feature which has since been removed (it was once Active)
54 /// This language feature has since been Accepted (it was once Active)
59 features: ~[&'static str],
64 fn gate_feature(&self, feature: &str, span: Span, explain: &str) {
65 if !self.has_feature(feature) {
66 self.sess.span_err(span, explain);
67 self.sess.span_note(span, format!("add \\#[feature({})] to the \
68 crate attributes to enable",
73 fn has_feature(&self, feature: &str) -> bool {
74 self.features.iter().any(|n| n.as_slice() == feature)
78 impl Visitor<()> for Context {
79 fn visit_view_item(&mut self, i: &ast::view_item, _: ()) {
81 ast::view_item_use(ref paths) => {
82 for path in paths.iter() {
84 ast::view_path_glob(*) => {
85 self.gate_feature("globs", path.span,
86 "glob import statements are \
87 experimental and possibly buggy");
95 visit::walk_view_item(self, i, ())
98 fn visit_item(&mut self, i: @ast::item, _:()) {
100 ast::item_enum(ref def, _) => {
101 for variant in def.variants.iter() {
102 match variant.node.kind {
103 ast::struct_variant_kind(*) => {
104 self.gate_feature("struct_variant", variant.span,
105 "enum struct variants are \
106 experimental and possibly buggy");
116 visit::walk_item(self, i, ());
119 fn visit_mac(&mut self, macro: &ast::mac, _: ()) {
120 let ast::mac_invoc_tt(ref path, _, _) = macro.node;
122 if path.segments.last().identifier == self.sess.ident_of("macro_rules") {
123 self.gate_feature("macro_rules", path.span, "macro definitions are \
124 not stable enough for use and are subject to change");
127 else if path.segments.last().identifier == self.sess.ident_of("asm") {
128 self.gate_feature("asm", path.span, "inline assembly is not \
129 stable enough for use and is subject to change");
133 fn visit_ty(&mut self, t: &ast::Ty, _: ()) {
135 ast::ty_closure(closure) if closure.onceness == ast::Once => {
136 self.gate_feature("once_fns", t.span,
137 "once functions are \
138 experimental and likely to be removed");
141 // NOTE: enable after snapshot
142 ast::ty_box(_) if false => {
143 self.gate_feature("managed_boxes", t.span, "The managed box syntax may be replaced \
144 by a library type, and a garbage \
145 collector is not yet implemented. \
146 Consider using the `std::rc` module \
147 as it performs much better as a \
148 reference counting implementation.");
153 visit::walk_ty(self, t, ());
157 pub fn check_crate(sess: Session, crate: &ast::Crate) {
158 let mut cx = Context {
163 for attr in crate.attrs.iter() {
164 if "feature" != attr.name() { continue }
166 match attr.meta_item_list() {
168 sess.span_err(attr.span, "malformed feature attribute, \
169 expected #[feature(...)]");
172 for &mi in list.iter() {
173 let name = match mi.node {
174 ast::MetaWord(word) => word,
176 sess.span_err(mi.span, "malformed feature, expected \
181 match KNOWN_FEATURES.iter().find(|& &(n, _)| n == name) {
182 Some(&(name, Active)) => { cx.features.push(name); }
183 Some(&(_, Removed)) => {
184 sess.span_err(mi.span, "feature has been removed");
186 Some(&(_, Accepted)) => {
187 sess.span_warn(mi.span, "feature has added to rust, \
188 directive not necessary");
191 sess.span_err(mi.span, "unknown feature");
199 visit::walk_crate(&mut cx, crate, ());
201 sess.abort_if_errors();