]> git.lizzy.rs Git - rust.git/blob - src/librustc/front/feature_gate.rs
add feature gate for managed boxes
[rust.git] / src / librustc / front / feature_gate.rs
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.
4 //
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.
10
11 //! Feature gating
12 //!
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
16 //! enabled.
17 //!
18 //! Features are enabled in programs via the crate-level attributes of
19 //! #[feature(...)] with a comma-separated list of features.
20
21 use syntax::ast;
22 use syntax::attr::AttrMetaMethods;
23 use syntax::codemap::Span;
24 use syntax::visit;
25 use syntax::visit::Visitor;
26
27 use driver::session::Session;
28
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)] = &[
33     ("globs", Active),
34     ("macro_rules", Active),
35     ("struct_variant", Active),
36     ("once_fns", Active),
37     ("asm", Active),
38     ("managed_boxes", Active),
39
40     // These are used to test this portion of the compiler, they don't actually
41     // mean anything
42     ("test_accepted_feature", Accepted),
43     ("test_removed_feature", Removed),
44 ];
45
46 enum Status {
47     /// Represents an active feature that is currently being implemented or
48     /// currently being considered for addition/removal.
49     Active,
50
51     /// Represents a feature which has since been removed (it was once Active)
52     Removed,
53
54     /// This language feature has since been Accepted (it was once Active)
55     Accepted,
56 }
57
58 struct Context {
59     features: ~[&'static str],
60     sess: Session,
61 }
62
63 impl Context {
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",
69                                                  feature));
70         }
71     }
72
73     fn has_feature(&self, feature: &str) -> bool {
74         self.features.iter().any(|n| n.as_slice() == feature)
75     }
76 }
77
78 impl Visitor<()> for Context {
79     fn visit_view_item(&mut self, i: &ast::view_item, _: ()) {
80         match i.node {
81             ast::view_item_use(ref paths) => {
82                 for path in paths.iter() {
83                     match path.node {
84                         ast::view_path_glob(*) => {
85                             self.gate_feature("globs", path.span,
86                                               "glob import statements are \
87                                                experimental and possibly buggy");
88                         }
89                         _ => {}
90                     }
91                 }
92             }
93             _ => {}
94         }
95         visit::walk_view_item(self, i, ())
96     }
97
98     fn visit_item(&mut self, i: @ast::item, _:()) {
99         match i.node {
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");
107                         }
108                         _ => {}
109                     }
110                 }
111             }
112
113             _ => {}
114         }
115
116         visit::walk_item(self, i, ());
117     }
118
119     fn visit_mac(&mut self, macro: &ast::mac, _: ()) {
120         let ast::mac_invoc_tt(ref path, _, _) = macro.node;
121
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");
125         }
126
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");
130         }
131     }
132
133     fn visit_ty(&mut self, t: &ast::Ty, _: ()) {
134         match t.node {
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");
139
140             },
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.");
149             }
150             _ => {}
151         }
152
153         visit::walk_ty(self, t, ());
154     }
155 }
156
157 pub fn check_crate(sess: Session, crate: &ast::Crate) {
158     let mut cx = Context {
159         features: ~[],
160         sess: sess,
161     };
162
163     for attr in crate.attrs.iter() {
164         if "feature" != attr.name() { continue }
165
166         match attr.meta_item_list() {
167             None => {
168                 sess.span_err(attr.span, "malformed feature attribute, \
169                                           expected #[feature(...)]");
170             }
171             Some(list) => {
172                 for &mi in list.iter() {
173                     let name = match mi.node {
174                         ast::MetaWord(word) => word,
175                         _ => {
176                             sess.span_err(mi.span, "malformed feature, expected \
177                                                     just one word");
178                             continue
179                         }
180                     };
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");
185                         }
186                         Some(&(_, Accepted)) => {
187                             sess.span_warn(mi.span, "feature has added to rust, \
188                                                      directive not necessary");
189                         }
190                         None => {
191                             sess.span_err(mi.span, "unknown feature");
192                         }
193                     }
194                 }
195             }
196         }
197     }
198
199     visit::walk_crate(&mut cx, crate, ());
200
201     sess.abort_if_errors();
202 }