(index<- )        ./librustc/front/feature_gate.rs

    git branch:    * master           5200215 auto merge of #14035 : alexcrichton/rust/experimental, r=huonw
    modified:    Fri May  9 13:02:28 2014
   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 middle::lint;
  22  
  23  use syntax::ast;
  24  use syntax::attr;
  25  use syntax::attr::AttrMetaMethods;
  26  use syntax::codemap::Span;
  27  use syntax::visit;
  28  use syntax::visit::Visitor;
  29  use syntax::parse::token;
  30  
  31  use driver::session::Session;
  32  
  33  use std::cell::Cell;
  34  
  35  /// This is a list of all known features since the beginning of time. This list
  36  /// can never shrink, it may only be expanded (in order to prevent old programs
  37  /// from failing to compile). The status of each feature may change, however.
  38  static KNOWN_FEATURES: &'static [(&'static str, Status)] = &[
  39      ("globs", Active),
  40      ("macro_rules", Active),
  41      ("struct_variant", Active),
  42      ("once_fns", Active),
  43      ("asm", Active),
  44      ("managed_boxes", Active),
  45      ("non_ascii_idents", Active),
  46      ("thread_local", Active),
  47      ("link_args", Active),
  48      ("phase", Active),
  49      ("macro_registrar", Active),
  50      ("log_syntax", Active),
  51      ("trace_macros", Active),
  52      ("concat_idents", Active),
  53  
  54      ("simd", Active),
  55      ("default_type_params", Active),
  56      ("quote", Active),
  57      ("linkage", Active),
  58      ("struct_inherit", Active),
  59  
  60      ("quad_precision_float", Active),
  61  
  62      // A temporary feature gate used to enable parser extensions needed
  63      // to bootstrap fix for #5723.
  64      ("issue_5723_bootstrap", Active),
  65  
  66      // These are used to test this portion of the compiler, they don't actually
  67      // mean anything
  68      ("test_accepted_feature", Accepted),
  69      ("test_removed_feature", Removed),
  70  ];
  71  
  72  enum Status {
  73      /// Represents an active feature that is currently being implemented or
  74      /// currently being considered for addition/removal.
  75      Active,
  76  
  77      /// Represents a feature which has since been removed (it was once Active)
  78      Removed,
  79  
  80      /// This language feature has since been Accepted (it was once Active)
  81      Accepted,
  82  }
  83  
  84  /// A set of features to be used by later passes.
  85  pub struct Features {
  86      pub default_type_params: Cell<bool>,
  87      pub quad_precision_float: Cell<bool>,
  88      pub issue_5723_bootstrap: Cell<bool>,
  89  }
  90  
  91  impl Features {
  92      pub fn new() -> Features {
  93          Features {
  94              default_type_params: Cell::new(false),
  95              quad_precision_float: Cell::new(false),
  96              issue_5723_bootstrap: Cell::new(false),
  97          }
  98      }
  99  }
 100  
 101  struct Context<'a> {
 102      features: Vec<&'static str>,
 103      sess: &'a Session,
 104  }
 105  
 106  impl<'a> Context<'a> {
 107      fn gate_feature(&self, feature&str, spanSpan, explain&str) {
 108          if !self.has_feature(feature) {
 109              self.sess.span_err(span, explain);
 110              self.sess.span_note(span, format!("add \\#![feature({})] to the \
 111                                                    crate attributes to enable",
 112                                                   feature));
 113          }
 114      }
 115  
 116      fn gate_box(&self, spanSpan) {
 117          self.gate_feature("managed_boxes", span,
 118                            "The managed box syntax is being replaced by the \
 119                             `std::gc::Gc` and `std::rc::Rc` types. Equivalent \
 120                             functionality to managed trait objects will be \
 121                             implemented but is currently missing.");
 122      }
 123  
 124      fn has_feature(&self, feature&str) -> bool {
 125          self.features.iter().any(|n| n.as_slice() == feature)
 126      }
 127  }
 128  
 129  impl<'a> Visitor<()> for Context<'a> {
 130      fn visit_ident(&mut self, spSpan, idast::Ident, _()) {
 131          if !token::get_ident(id).get().is_ascii() {
 132              self.gate_feature("non_ascii_idents", sp,
 133                                "non-ascii idents are not fully supported.");
 134          }
 135      }
 136  
 137      fn visit_view_item(&mut self, i&ast::ViewItem, _()) {
 138          match i.node {
 139              ast::ViewItemUse(ref path) => {
 140                  match path.node {
 141                      ast::ViewPathGlob(..) => {
 142                          self.gate_feature("globs", path.span,
 143                                            "glob import statements are \
 144                                             experimental and possibly buggy");
 145                      }
 146                      _ => {}
 147                  }
 148              }
 149              ast::ViewItemExternCrate(..) => {
 150                  for attr in i.attrs.iter() {
 151                      if attr.name().get() == "phase"{
 152                          self.gate_feature("phase", attr.span,
 153                                            "compile time crate loading is \
 154                                             experimental and possibly buggy");
 155                      }
 156                  }
 157              }
 158          }
 159          visit::walk_view_item(self, i, ())
 160      }
 161  
 162      fn visit_item(&mut self, i&ast::Item, _:()) {
 163          for attr in i.attrs.iter() {
 164              if attr.name().equiv(&("thread_local")) {
 165                  self.gate_feature("thread_local", i.span,
 166                                    "`#[thread_local]` is an experimental feature, and does not \
 167                                    currently handle destructors. There is no corresponding \
 168                                    `#[task_local]` mapping to the task model");
 169              }
 170          }
 171          match i.node {
 172              ast::ItemEnum(ref def, _) => {
 173                  for variant in def.variants.iter() {
 174                      match variant.node.kind {
 175                          ast::StructVariantKind(..) => {
 176                              self.gate_feature("struct_variant", variant.span,
 177                                                "enum struct variants are \
 178                                                 experimental and possibly buggy");
 179                          }
 180                          _ => {}
 181                      }
 182                  }
 183              }
 184  
 185              ast::ItemForeignMod(..) => {
 186                  if attr::contains_name(i.attrs.as_slice(), "link_args") {
 187                      self.gate_feature("link_args", i.span,
 188                                        "the `link_args` attribute is not portable \
 189                                         across platforms, it is recommended to \
 190                                         use `#[link(name = \"foo\")]` instead")
 191                  }
 192              }
 193  
 194              ast::ItemFn(..) => {
 195                  if attr::contains_name(i.attrs.as_slice(), "macro_registrar") {
 196                      self.gate_feature("macro_registrar", i.span,
 197                                        "cross-crate macro exports are \
 198                                         experimental and possibly buggy");
 199                  }
 200              }
 201  
 202              ast::ItemStruct(struct_definition, _) => {
 203                  if attr::contains_name(i.attrs.as_slice(), "simd") {
 204                      self.gate_feature("simd", i.span,
 205                                        "SIMD types are experimental and possibly buggy");
 206                  }
 207                  match struct_definition.super_struct {
 208                      Some(ref path) => self.gate_feature("struct_inherit", path.span,
 209                                                          "struct inheritance is experimental \
 210                                                           and possibly buggy"),
 211                      None => {}
 212                  }
 213                  if struct_definition.is_virtual {
 214                      self.gate_feature("struct_inherit", i.span,
 215                                        "struct inheritance (`virtual` keyword) is \
 216                                         experimental and possibly buggy");
 217                  }
 218              }
 219  
 220              _ => {}
 221          }
 222  
 223          visit::walk_item(self, i, ());
 224      }
 225  
 226      fn visit_mac(&mut self, macro&ast::Mac, _()) {
 227          let ast::MacInvocTT(ref path, _, _) = macro.node;
 228          let id = path.segments.last().unwrap().identifier;
 229          let quotes = ["quote_tokens", "quote_expr", "quote_ty",
 230                        "quote_item", "quote_pat", "quote_stmt"];
 231          let msg = " is not stable enough for use and are subject to change";
 232  
 233  
 234          if id == token::str_to_ident("macro_rules") {
 235              self.gate_feature("macro_rules", path.span, "macro definitions are \
 236                  not stable enough for use and are subject to change");
 237          }
 238  
 239          else if id == token::str_to_ident("asm") {
 240              self.gate_feature("asm", path.span, "inline assembly is not \
 241                  stable enough for use and is subject to change");
 242          }
 243  
 244          else if id == token::str_to_ident("log_syntax") {
 245              self.gate_feature("log_syntax", path.span, "`log_syntax!` is not \
 246                  stable enough for use and is subject to change");
 247          }
 248  
 249          else if id == token::str_to_ident("trace_macros") {
 250              self.gate_feature("trace_macros", path.span, "`trace_macros` is not \
 251                  stable enough for use and is subject to change");
 252          }
 253  
 254          else if id == token::str_to_ident("concat_idents") {
 255              self.gate_feature("concat_idents", path.span, "`concat_idents` is not \
 256                  stable enough for use and is subject to change");
 257          }
 258  
 259          else {
 260              for &quote in quotes.iter() {
 261                  if id == token::str_to_ident(quote) {
 262                    self.gate_feature("quote", path.span, quote + msg);
 263                  }
 264              }
 265          }
 266      }
 267  
 268      fn visit_foreign_item(&mut self, i&ast::ForeignItem, _()) {
 269          match i.node {
 270              ast::ForeignItemFn(..) | ast::ForeignItemStatic(..) => {
 271                  if attr::contains_name(i.attrs.as_slice(), "linkage") {
 272                      self.gate_feature("linkage", i.span,
 273                                        "the `linkage` attribute is experimental \
 274                                         and not portable across platforms")
 275                  }
 276              }
 277          }
 278          visit::walk_foreign_item(self, i, ())
 279      }
 280  
 281      fn visit_ty(&mut self, t&ast::Ty, _()) {
 282          match t.node {
 283              ast::TyClosure(closure, _) if closure.onceness == ast::Once => {
 284                  self.gate_feature("once_fns", t.span,
 285                                    "once functions are \
 286                                     experimental and likely to be removed");
 287  
 288              },
 289              ast::TyBox(_) => { self.gate_box(t.span); }
 290              _ => {}
 291          }
 292  
 293          visit::walk_ty(self, t, ());
 294      }
 295  
 296      fn visit_expr(&mut self, e&ast::Expr, _()) {
 297          match e.node {
 298              ast::ExprUnary(ast::UnBox, _) => {
 299                  self.gate_box(e.span);
 300              }
 301              _ => {}
 302          }
 303          visit::walk_expr(self, e, ());
 304      }
 305  
 306      fn visit_generics(&mut self, generics&ast::Generics, _()) {
 307          for type_parameter in generics.ty_params.iter() {
 308              match type_parameter.default {
 309                  Some(ty) => {
 310                      self.gate_feature("default_type_params", ty.span,
 311                                        "default type parameters are \
 312                                         experimental and possibly buggy");
 313                  }
 314                  None => {}
 315              }
 316          }
 317          visit::walk_generics(self, generics, ());
 318      }
 319  }
 320  
 321  pub fn check_crate(sess: &Session, krate: &ast::Crate) {
 322      let mut cx = Context {
 323          features: Vec::new(),
 324          sess: sess,
 325      };
 326  
 327      for attr in krate.attrs.iter() {
 328          if !attr.name().equiv(&("feature")) {
 329              continue
 330          }
 331  
 332          match attr.meta_item_list() {
 333              None => {
 334                  sess.span_err(attr.span, "malformed feature attribute, \
 335                                            expected #![feature(...)]");
 336              }
 337              Some(list) => {
 338                  for &mi in list.iter() {
 339                      let name = match mi.node {
 340                          ast::MetaWord(ref word) => (*word).clone(),
 341                          _ => {
 342                              sess.span_err(mi.span,
 343                                            "malformed feature, expected just \
 344                                             one word");
 345                              continue
 346                          }
 347                      };
 348                      match KNOWN_FEATURES.iter()
 349                                          .find(|& &(n, _)| name.equiv(&n)) {
 350                          Some(&(name, Active)) => { cx.features.push(name); }
 351                          Some(&(_, Removed)) => {
 352                              sess.span_err(mi.span, "feature has been removed");
 353                          }
 354                          Some(&(_, Accepted)) => {
 355                              sess.span_warn(mi.span, "feature has added to rust, \
 356                                                       directive not necessary");
 357                          }
 358                          None => {
 359                              sess.add_lint(lint::UnknownFeatures,
 360                                            ast::CRATE_NODE_ID,
 361                                            mi.span,
 362                                            "unknown feature".to_owned());
 363                          }
 364                      }
 365                  }
 366              }
 367          }
 368      }
 369  
 370      visit::walk_crate(&mut cx, krate, ());
 371  
 372      sess.abort_if_errors();
 373  
 374      sess.features.default_type_params.set(cx.has_feature("default_type_params"));
 375      sess.features.quad_precision_float.set(cx.has_feature("quad_precision_float"));
 376      sess.features.issue_5723_bootstrap.set(cx.has_feature("issue_5723_bootstrap"));
 377  }