about summary refs log tree commit diff
path: root/src
diff options
context:
space:
mode:
authorAlex Crichton <alex@alexcrichton.com>2013-10-02 18:10:16 -0700
committerAlex Crichton <alex@alexcrichton.com>2013-10-05 20:19:33 -0700
commitdd98f7089fec5ee8bc908089bcb89c6e352d8726 (patch)
tree2cf633494514e1976e7e1131b994e2b7e6038a11 /src
parentacf9783879dca0db0721c10ac79c9078f2dec425 (diff)
downloadrust-dd98f7089fec5ee8bc908089bcb89c6e352d8726.tar.gz
rust-dd98f7089fec5ee8bc908089bcb89c6e352d8726.zip
Implement feature-gating for the compiler
A few features are now hidden behind various #[feature(...)] directives. These
include struct-like enum variants, glob imports, and macro_rules! invocations.

Closes #9304
Closes #9305
Closes #9306
Closes #9331
Diffstat (limited to 'src')
-rw-r--r--src/libextra/extra.rs2
-rw-r--r--src/librustc/driver/driver.rs2
-rw-r--r--src/librustc/front/feature_gate.rs176
-rw-r--r--src/librustc/rustc.rs3
-rw-r--r--src/librustdoc/rustdoc.rs2
-rw-r--r--src/librusti/rusti.rs2
-rw-r--r--src/librustpkg/rustpkg.rs2
-rw-r--r--src/libstd/std.rs2
-rw-r--r--src/libsyntax/syntax.rs2
-rw-r--r--src/test/compile-fail/gated-bad-feature.rs24
-rw-r--r--src/test/compile-fail/gated-glob-imports.rs14
-rw-r--r--src/test/compile-fail/gated-macro-rules.rs14
-rw-r--r--src/test/compile-fail/gated-struct-enums.rs15
13 files changed, 260 insertions, 0 deletions
diff --git a/src/libextra/extra.rs b/src/libextra/extra.rs
index 74787e66fec..45e4fe50f25 100644
--- a/src/libextra/extra.rs
+++ b/src/libextra/extra.rs
@@ -33,6 +33,8 @@ Rust extras are part of the standard Rust distribution.
 #[license = "MIT/ASL2"];
 #[crate_type = "lib"];
 
+#[feature(macro_rules, globs)];
+
 #[deny(non_camel_case_types)];
 #[deny(missing_doc)];
 
diff --git a/src/librustc/driver/driver.rs b/src/librustc/driver/driver.rs
index 00f722e7890..4dff3abda30 100644
--- a/src/librustc/driver/driver.rs
+++ b/src/librustc/driver/driver.rs
@@ -159,6 +159,8 @@ pub fn phase_2_configure_and_expand(sess: Session,
     *sess.building_library = session::building_library(sess.opts.crate_type,
                                                        &crate, sess.opts.test);
 
+    time(time_passes, ~"gated feature checking", (), |_|
+         front::feature_gate::check_crate(sess, &crate));
 
     // strip before expansion to allow macros to depend on
     // configuration variables e.g/ in
diff --git a/src/librustc/front/feature_gate.rs b/src/librustc/front/feature_gate.rs
new file mode 100644
index 00000000000..5986409c843
--- /dev/null
+++ b/src/librustc/front/feature_gate.rs
@@ -0,0 +1,176 @@
+// 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 syntax::ast;
+use syntax::attr::AttrMetaMethods;
+use syntax::codemap::Span;
+use syntax::visit;
+use syntax::visit::Visitor;
+
+use driver::session::Session;
+
+/// 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),
+
+    // 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,
+}
+
+struct Context {
+    features: ~[&'static str],
+    sess: Session,
+}
+
+impl Context {
+    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));
+        }
+    }
+
+    fn has_feature(&self, feature: &str) -> bool {
+        self.features.iter().any(|n| n.as_slice() == feature)
+    }
+}
+
+impl Visitor<()> for Context {
+    fn visit_view_item(&mut self, i: &ast::view_item, _: ()) {
+        match i.node {
+            ast::view_item_use(ref paths) => {
+                for path in paths.iter() {
+                    match path.node {
+                        ast::view_path_glob(*) => {
+                            self.gate_feature("globs", path.span,
+                                              "glob import statements are \
+                                               experimental and possibly buggy");
+                        }
+                        _ => {}
+                    }
+                }
+            }
+            _ => {}
+        }
+        visit::walk_view_item(self, i, ())
+    }
+
+    fn visit_item(&mut self, i: @ast::item, _:()) {
+        match i.node {
+            ast::item_enum(ref def, _) => {
+                for variant in def.variants.iter() {
+                    match variant.node.kind {
+                        ast::struct_variant_kind(*) => {
+                            self.gate_feature("struct_variant", variant.span,
+                                              "enum struct variants are \
+                                               experimental and possibly buggy");
+                        }
+                        _ => {}
+                    }
+                }
+            }
+
+            ast::item_mac(ref mac) => {
+                match mac.node {
+                    ast::mac_invoc_tt(ref path, _, _) => {
+                        let rules = self.sess.ident_of("macro_rules");
+                        if path.segments.last().identifier == rules {
+                            self.gate_feature("macro_rules", i.span,
+                                              "macro definitions are not \
+                                               stable enough for use and are \
+                                               subject to change");
+                        }
+                    }
+                }
+            }
+
+            _ => {}
+        }
+
+        visit::walk_item(self, i, ());
+    }
+}
+
+pub fn check_crate(sess: Session, crate: &ast::Crate) {
+    let mut cx = Context {
+        features: ~[],
+        sess: sess,
+    };
+
+    for attr in crate.attrs.iter() {
+        if "feature" != attr.name() { 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(word) => word,
+                        _ => {
+                            sess.span_err(mi.span, "malformed feature, expected \
+                                                    just one word");
+                            continue
+                        }
+                    };
+                    match KNOWN_FEATURES.iter().find(|& &(n, _)| n == name) {
+                        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 added to rust, \
+                                                     directive not necessary");
+                        }
+                        None => {
+                            sess.span_err(mi.span, "unknown feature");
+                        }
+                    }
+                }
+            }
+        }
+    }
+
+    visit::walk_crate(&mut cx, crate, ());
+
+    sess.abort_if_errors();
+}
diff --git a/src/librustc/rustc.rs b/src/librustc/rustc.rs
index 2cf04e8d3e1..a8a255669ca 100644
--- a/src/librustc/rustc.rs
+++ b/src/librustc/rustc.rs
@@ -17,6 +17,8 @@
 #[license = "MIT/ASL2"];
 #[crate_type = "lib"];
 
+#[feature(macro_rules, globs, struct_variant)];
+
 // Rustc tasks always run on a fixed_stack_segment, so code in this
 // module can call C functions (in particular, LLVM functions) with
 // impunity.
@@ -83,6 +85,7 @@ pub mod front {
     pub mod test;
     pub mod std_inject;
     pub mod assign_node_ids;
+    pub mod feature_gate;
 }
 
 pub mod back {
diff --git a/src/librustdoc/rustdoc.rs b/src/librustdoc/rustdoc.rs
index b953fe1ed5d..d72612256a7 100644
--- a/src/librustdoc/rustdoc.rs
+++ b/src/librustdoc/rustdoc.rs
@@ -17,6 +17,8 @@
 #[license = "MIT/ASL2"];
 #[crate_type = "lib"];
 
+#[feature(globs, struct_variant)];
+
 extern mod syntax;
 extern mod rustc;
 extern mod extra;
diff --git a/src/librusti/rusti.rs b/src/librusti/rusti.rs
index 9da8c58fd05..3775d175166 100644
--- a/src/librusti/rusti.rs
+++ b/src/librusti/rusti.rs
@@ -66,6 +66,8 @@
 #[license = "MIT/ASL2"];
 #[crate_type = "lib"];
 
+#[feature(globs)];
+
 extern mod extra;
 extern mod rustc;
 extern mod syntax;
diff --git a/src/librustpkg/rustpkg.rs b/src/librustpkg/rustpkg.rs
index 1ece56df60a..cd4badfab31 100644
--- a/src/librustpkg/rustpkg.rs
+++ b/src/librustpkg/rustpkg.rs
@@ -18,6 +18,8 @@
 #[license = "MIT/ASL2"];
 #[crate_type = "lib"];
 
+#[feature(globs)];
+
 extern mod extra;
 extern mod rustc;
 extern mod syntax;
diff --git a/src/libstd/std.rs b/src/libstd/std.rs
index 5501cdfdcd5..53837f96593 100644
--- a/src/libstd/std.rs
+++ b/src/libstd/std.rs
@@ -61,6 +61,8 @@ they contained the following prologue:
       html_favicon_url = "http://www.rust-lang.org/favicon.ico",
       html_root_url = "http://static.rust-lang.org/doc/master")];
 
+#[feature(macro_rules, globs)];
+
 // Don't link to std. We are std.
 #[no_std];
 
diff --git a/src/libsyntax/syntax.rs b/src/libsyntax/syntax.rs
index 74f695d301b..1f385a00fa6 100644
--- a/src/libsyntax/syntax.rs
+++ b/src/libsyntax/syntax.rs
@@ -20,6 +20,8 @@
 #[license = "MIT/ASL2"];
 #[crate_type = "lib"];
 
+#[feature(macro_rules, globs)];
+
 extern mod extra;
 
 pub mod util {
diff --git a/src/test/compile-fail/gated-bad-feature.rs b/src/test/compile-fail/gated-bad-feature.rs
new file mode 100644
index 00000000000..0bf2d5ad78b
--- /dev/null
+++ b/src/test/compile-fail/gated-bad-feature.rs
@@ -0,0 +1,24 @@
+// 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(
+    foo_bar_baz,
+    foo(bar),
+    foo = "baz"
+)];
+//~^^^^ ERROR: unknown feature
+//~^^^^ ERROR: malformed feature
+//~^^^^ ERROR: malformed feature
+
+#[feature]; //~ ERROR: malformed feature
+#[feature = "foo"]; //~ ERROR: malformed feature
+
+#[feature(test_removed_feature)]; //~ ERROR: feature has been removed
+#[feature(test_accepted_feature)]; //~ WARNING: feature has added
diff --git a/src/test/compile-fail/gated-glob-imports.rs b/src/test/compile-fail/gated-glob-imports.rs
new file mode 100644
index 00000000000..cc7ba785e7e
--- /dev/null
+++ b/src/test/compile-fail/gated-glob-imports.rs
@@ -0,0 +1,14 @@
+// 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.
+
+use std::*;
+//~^ ERROR: glob import statements are experimental
+
+fn main() {}
diff --git a/src/test/compile-fail/gated-macro-rules.rs b/src/test/compile-fail/gated-macro-rules.rs
new file mode 100644
index 00000000000..7f771c72416
--- /dev/null
+++ b/src/test/compile-fail/gated-macro-rules.rs
@@ -0,0 +1,14 @@
+// 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.
+
+macro_rules! foo(() => ())
+//~^ ERROR: macro definitions are not stable enough for use
+
+fn main() {}
diff --git a/src/test/compile-fail/gated-struct-enums.rs b/src/test/compile-fail/gated-struct-enums.rs
new file mode 100644
index 00000000000..f1bd9362bb7
--- /dev/null
+++ b/src/test/compile-fail/gated-struct-enums.rs
@@ -0,0 +1,15 @@
+// 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.
+
+enum A { B { foo: int } }
+//~^ ERROR: enum struct variants are experimental
+
+fn main() {}
+