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.
21 use abi::RustIntrinsic;
25 use attr::AttrMetaMethods;
27 use diagnostic::SpanHandler;
34 /// This is a list of all known features since the beginning of time. This list
35 /// can never shrink, it may only be expanded (in order to prevent old programs
36 /// from failing to compile). The status of each feature may change, however.
37 static KNOWN_FEATURES: &'static [(&'static str, Status)] = &[
39 ("macro_rules", Active),
40 ("struct_variant", Active),
43 ("managed_boxes", Active),
44 ("non_ascii_idents", Active),
45 ("thread_local", Active),
46 ("link_args", Active),
48 ("plugin_registrar", Active),
49 ("log_syntax", Active),
50 ("trace_macros", Active),
51 ("concat_idents", Active),
52 ("unsafe_destructor", Active),
53 ("intrinsics", Active),
54 ("lang_items", Active),
57 ("default_type_params", Active),
60 ("struct_inherit", Active),
61 ("overloaded_calls", Active),
62 ("unboxed_closure_sugar", Active),
64 ("quad_precision_float", Removed),
66 ("rustc_diagnostic_macros", Active),
67 ("unboxed_closures", Active),
68 ("import_shadowing", Active),
69 ("advanced_slice_patterns", Active),
70 ("tuple_indexing", Active),
71 ("associated_types", Active),
72 ("visible_private_types", Active),
74 // if you change this list without updating src/doc/rust.md, cmr will be sad
76 // A temporary feature gate used to enable parser extensions needed
77 // to bootstrap fix for #5723.
78 ("issue_5723_bootstrap", Accepted),
80 // These are used to test this portion of the compiler, they don't actually
82 ("test_accepted_feature", Accepted),
83 ("test_removed_feature", Removed),
87 /// Represents an active feature that is currently being implemented or
88 /// currently being considered for addition/removal.
91 /// Represents a feature which has since been removed (it was once Active)
94 /// This language feature has since been Accepted (it was once Active)
98 /// A set of features to be used by later passes.
100 pub default_type_params: bool,
101 pub overloaded_calls: bool,
102 pub rustc_diagnostic_macros: bool,
103 pub import_shadowing: bool,
104 pub visible_private_types: bool,
109 pub fn new() -> Features {
111 default_type_params: false,
112 overloaded_calls: false,
113 rustc_diagnostic_macros: false,
114 import_shadowing: false,
115 visible_private_types: false,
122 features: Vec<&'static str>,
123 span_handler: &'a SpanHandler,
126 impl<'a> Context<'a> {
127 fn gate_feature(&self, feature: &str, span: Span, explain: &str) {
128 if !self.has_feature(feature) {
129 self.span_handler.span_err(span, explain);
130 self.span_handler.span_note(span, format!("add #![feature({})] to the \
131 crate attributes to enable",
132 feature).as_slice());
136 fn gate_box(&self, span: Span) {
137 self.gate_feature("managed_boxes", span,
138 "The managed box syntax is being replaced by the \
139 `std::gc::Gc` and `std::rc::Rc` types. Equivalent \
140 functionality to managed trait objects will be \
141 implemented but is currently missing.");
144 fn has_feature(&self, feature: &str) -> bool {
145 self.features.iter().any(|n| n.as_slice() == feature)
149 impl<'a, 'v> Visitor<'v> for Context<'a> {
150 fn visit_ident(&mut self, sp: Span, id: ast::Ident) {
151 if !token::get_ident(id).get().is_ascii() {
152 self.gate_feature("non_ascii_idents", sp,
153 "non-ascii idents are not fully supported.");
157 fn visit_view_item(&mut self, i: &ast::ViewItem) {
159 ast::ViewItemUse(ref path) => {
161 ast::ViewPathGlob(..) => {
162 self.gate_feature("globs", path.span,
163 "glob import statements are \
164 experimental and possibly buggy");
169 ast::ViewItemExternCrate(..) => {
170 for attr in i.attrs.iter() {
171 if attr.name().get() == "phase"{
172 self.gate_feature("phase", attr.span,
173 "compile time crate loading is \
174 experimental and possibly buggy");
179 visit::walk_view_item(self, i)
182 fn visit_item(&mut self, i: &ast::Item) {
183 for attr in i.attrs.iter() {
184 if attr.name().equiv(&("thread_local")) {
185 self.gate_feature("thread_local", i.span,
186 "`#[thread_local]` is an experimental feature, and does not \
187 currently handle destructors. There is no corresponding \
188 `#[task_local]` mapping to the task model");
192 ast::ItemEnum(ref def, _) => {
193 for variant in def.variants.iter() {
194 match variant.node.kind {
195 ast::StructVariantKind(..) => {
196 self.gate_feature("struct_variant", variant.span,
197 "enum struct variants are \
198 experimental and possibly buggy");
205 ast::ItemForeignMod(ref foreign_module) => {
206 if attr::contains_name(i.attrs.as_slice(), "link_args") {
207 self.gate_feature("link_args", i.span,
208 "the `link_args` attribute is not portable \
209 across platforms, it is recommended to \
210 use `#[link(name = \"foo\")]` instead")
212 if foreign_module.abi == RustIntrinsic {
213 self.gate_feature("intrinsics",
215 "intrinsics are subject to change")
220 if attr::contains_name(i.attrs.as_slice(), "plugin_registrar") {
221 self.gate_feature("plugin_registrar", i.span,
222 "compiler plugins are experimental and possibly buggy");
226 ast::ItemStruct(ref struct_definition, _) => {
227 if attr::contains_name(i.attrs.as_slice(), "simd") {
228 self.gate_feature("simd", i.span,
229 "SIMD types are experimental and possibly buggy");
231 match struct_definition.super_struct {
232 Some(ref path) => self.gate_feature("struct_inherit", path.span,
233 "struct inheritance is experimental \
234 and possibly buggy"),
237 if struct_definition.is_virtual {
238 self.gate_feature("struct_inherit", i.span,
239 "struct inheritance (`virtual` keyword) is \
240 experimental and possibly buggy");
244 ast::ItemImpl(_, _, _, ref items) => {
245 if attr::contains_name(i.attrs.as_slice(),
246 "unsafe_destructor") {
247 self.gate_feature("unsafe_destructor",
249 "`#[unsafe_destructor]` allows too \
250 many unsafe patterns and may be \
251 removed in the future");
254 for item in items.iter() {
256 ast::MethodImplItem(_) => {}
257 ast::TypeImplItem(ref typedef) => {
258 self.gate_feature("associated_types",
260 "associated types are \
270 visit::walk_item(self, i);
273 fn visit_trait_item(&mut self, trait_item: &ast::TraitItem) {
275 ast::RequiredMethod(_) | ast::ProvidedMethod(_) => {}
276 ast::TypeTraitItem(ref ti) => {
277 self.gate_feature("associated_types",
279 "associated types are experimental")
284 fn visit_mac(&mut self, macro: &ast::Mac) {
285 let ast::MacInvocTT(ref path, _, _) = macro.node;
286 let id = path.segments.last().unwrap().identifier;
288 if id == token::str_to_ident("macro_rules") {
289 self.gate_feature("macro_rules", path.span, "macro definitions are \
290 not stable enough for use and are subject to change");
293 else if id == token::str_to_ident("asm") {
294 self.gate_feature("asm", path.span, "inline assembly is not \
295 stable enough for use and is subject to change");
298 else if id == token::str_to_ident("log_syntax") {
299 self.gate_feature("log_syntax", path.span, "`log_syntax!` is not \
300 stable enough for use and is subject to change");
303 else if id == token::str_to_ident("trace_macros") {
304 self.gate_feature("trace_macros", path.span, "`trace_macros` is not \
305 stable enough for use and is subject to change");
308 else if id == token::str_to_ident("concat_idents") {
309 self.gate_feature("concat_idents", path.span, "`concat_idents` is not \
310 stable enough for use and is subject to change");
314 fn visit_foreign_item(&mut self, i: &ast::ForeignItem) {
315 if attr::contains_name(i.attrs.as_slice(), "linkage") {
316 self.gate_feature("linkage", i.span,
317 "the `linkage` attribute is experimental \
318 and not portable across platforms")
320 visit::walk_foreign_item(self, i)
323 fn visit_ty(&mut self, t: &ast::Ty) {
325 ast::TyClosure(ref closure) if closure.onceness == ast::Once => {
326 self.gate_feature("once_fns", t.span,
327 "once functions are \
328 experimental and likely to be removed");
331 ast::TyBox(_) => { self.gate_box(t.span); }
332 ast::TyUnboxedFn(..) => {
333 self.gate_feature("unboxed_closure_sugar",
335 "unboxed closure trait sugar is experimental");
340 visit::walk_ty(self, t);
343 fn visit_expr(&mut self, e: &ast::Expr) {
345 ast::ExprUnary(ast::UnBox, _) => {
346 self.gate_box(e.span);
348 ast::ExprUnboxedFn(..) => {
349 self.gate_feature("unboxed_closures",
351 "unboxed closures are a work-in-progress \
352 feature with known bugs");
354 ast::ExprTupField(..) => {
355 self.gate_feature("tuple_indexing",
357 "tuple indexing is experimental");
361 visit::walk_expr(self, e);
364 fn visit_generics(&mut self, generics: &ast::Generics) {
365 for type_parameter in generics.ty_params.iter() {
366 match type_parameter.default {
368 self.gate_feature("default_type_params", ty.span,
369 "default type parameters are \
370 experimental and possibly buggy");
375 visit::walk_generics(self, generics);
378 fn visit_attribute(&mut self, attr: &ast::Attribute) {
379 if attr::contains_name(slice::ref_slice(attr), "lang") {
380 self.gate_feature("lang_items",
382 "language items are subject to change");
386 fn visit_pat(&mut self, pattern: &ast::Pat) {
388 ast::PatVec(_, Some(_), ref last) if !last.is_empty() => {
389 self.gate_feature("advanced_slice_patterns",
391 "multiple-element slice matches anywhere \
392 but at the end of a slice (e.g. \
393 `[0, ..xs, 0]` are experimental")
397 visit::walk_pat(self, pattern)
400 fn visit_fn(&mut self,
401 fn_kind: visit::FnKind<'v>,
402 fn_decl: &'v ast::FnDecl,
403 block: &'v ast::Block,
407 visit::FkItemFn(_, _, _, abi) if abi == RustIntrinsic => {
408 self.gate_feature("intrinsics",
410 "intrinsics are subject to change")
414 visit::walk_fn(self, fn_kind, fn_decl, block, span);
418 pub fn check_crate(span_handler: &SpanHandler, krate: &ast::Crate) -> (Features, Vec<Span>) {
419 let mut cx = Context {
420 features: Vec::new(),
421 span_handler: span_handler,
424 let mut unknown_features = Vec::new();
426 for attr in krate.attrs.iter() {
427 if !attr.check_name("feature") {
431 match attr.meta_item_list() {
433 span_handler.span_err(attr.span, "malformed feature attribute, \
434 expected #![feature(...)]");
437 for mi in list.iter() {
438 let name = match mi.node {
439 ast::MetaWord(ref word) => (*word).clone(),
441 span_handler.span_err(mi.span,
442 "malformed feature, expected just \
447 match KNOWN_FEATURES.iter()
448 .find(|& &(n, _)| name.equiv(&n)) {
449 Some(&(name, Active)) => { cx.features.push(name); }
450 Some(&(_, Removed)) => {
451 span_handler.span_err(mi.span, "feature has been removed");
453 Some(&(_, Accepted)) => {
454 span_handler.span_warn(mi.span, "feature has been added to Rust, \
455 directive not necessary");
458 unknown_features.push(mi.span);
466 visit::walk_crate(&mut cx, krate);
469 default_type_params: cx.has_feature("default_type_params"),
470 overloaded_calls: cx.has_feature("overloaded_calls"),
471 rustc_diagnostic_macros: cx.has_feature("rustc_diagnostic_macros"),
472 import_shadowing: cx.has_feature("import_shadowing"),
473 visible_private_types: cx.has_feature("visible_private_types"),
474 quote: cx.has_feature("quote"),