diff options
| author | Alex Crichton <alex@alexcrichton.com> | 2013-10-02 18:10:16 -0700 |
|---|---|---|
| committer | Alex Crichton <alex@alexcrichton.com> | 2013-10-05 20:19:33 -0700 |
| commit | dd98f7089fec5ee8bc908089bcb89c6e352d8726 (patch) | |
| tree | 2cf633494514e1976e7e1131b994e2b7e6038a11 /src | |
| parent | acf9783879dca0db0721c10ac79c9078f2dec425 (diff) | |
| download | rust-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.rs | 2 | ||||
| -rw-r--r-- | src/librustc/driver/driver.rs | 2 | ||||
| -rw-r--r-- | src/librustc/front/feature_gate.rs | 176 | ||||
| -rw-r--r-- | src/librustc/rustc.rs | 3 | ||||
| -rw-r--r-- | src/librustdoc/rustdoc.rs | 2 | ||||
| -rw-r--r-- | src/librusti/rusti.rs | 2 | ||||
| -rw-r--r-- | src/librustpkg/rustpkg.rs | 2 | ||||
| -rw-r--r-- | src/libstd/std.rs | 2 | ||||
| -rw-r--r-- | src/libsyntax/syntax.rs | 2 | ||||
| -rw-r--r-- | src/test/compile-fail/gated-bad-feature.rs | 24 | ||||
| -rw-r--r-- | src/test/compile-fail/gated-glob-imports.rs | 14 | ||||
| -rw-r--r-- | src/test/compile-fail/gated-macro-rules.rs | 14 | ||||
| -rw-r--r-- | src/test/compile-fail/gated-struct-enums.rs | 15 |
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() {} + |
