Skip to content

Commit 30a18c2

Browse files
committed
auto merge of #9703 : alexcrichton/rust/compiler-features, r=cmr
This implements the necessary logic for gating particular features off by default in the compiler. There are a number of issues which have been wanting this form of mechanism, and this initially gates features which we have open issues for. Additionally, this should unblock #9255
2 parents 3f32898 + 353f77b commit 30a18c2

File tree

107 files changed

+471
-43
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

107 files changed

+471
-43
lines changed

doc/rust.md

+52
Original file line numberDiff line numberDiff line change
@@ -1832,6 +1832,58 @@ fn main() {
18321832
> individual functions, structs, methods and enum variants, *not* to
18331833
> entire modules, traits, impls or enums themselves.
18341834
1835+
### Compiler Features
1836+
1837+
Certain aspects of Rust may be implemented in the compiler, but they're not
1838+
necessarily ready for every-day use. These features are often of "prototype
1839+
quality" or "almost production ready", but may not be stable enough to be
1840+
considered a full-fleged language feature.
1841+
1842+
For this reason, rust recognizes a special crate-level attribute of the form:
1843+
1844+
~~~ {.xfail-test}
1845+
#[feature(feature1, feature2, feature3)]
1846+
~~~
1847+
1848+
This directive informs the compiler that the feature list: `feature1`,
1849+
`feature2`, and `feature3` should all be enabled. This is only recognized at a
1850+
crate-level, not at a module-level. Without this directive, all features are
1851+
considered off, and using the features will result in a compiler error.
1852+
1853+
The currently implemented features of the compiler are:
1854+
1855+
* `macro_rules` - The definition of new macros. This does not encompass
1856+
macro-invocation, that is always enabled by default, this only
1857+
covers the definition of new macros. There are currently
1858+
various problems with invoking macros, how they interact with
1859+
their environment, and possibly how they are used outside of
1860+
location in which they are defined. Macro definitions are
1861+
likely to change slightly in the future, so they are currently
1862+
hidden behind this feature.
1863+
1864+
* `globs` - Importing everything in a module through `*`. This is currently a
1865+
large source of bugs in name resolution for Rust, and it's not clear
1866+
whether this will continue as a feature or not. For these reasons,
1867+
the glob import statement has been hidden behind this feature flag.
1868+
1869+
* `struct_variant` - Structural enum variants (those with named fields). It is
1870+
currently unknown whether this style of enum variant is as
1871+
fully supported as the tuple-forms, and it's not certain
1872+
that this style of variant should remain in the language.
1873+
For now this style of variant is hidden behind a feature
1874+
flag.
1875+
1876+
If a feature is promoted to a language feature, then all existing programs will
1877+
start to receive compilation warnings about #[feature] directives which enabled
1878+
the new feature (because the directive is no longer necessary). However, if
1879+
a feature is decided to be removed from the language, errors will be issued (if
1880+
there isn't a parser error first). The directive in this case is no longer
1881+
necessary, and it's likely that existing code will break if the feature isn't
1882+
removed.
1883+
1884+
If a unknown feature is found in a directive, it results in a compiler error. An
1885+
unknown feature is one which has never been recognized by the compiler.
1886+
18351887
# Statements and expressions
18361888

18371889
Rust is _primarily_ an expression language. This means that most forms of

doc/tutorial.md

+8
Original file line numberDiff line numberDiff line change
@@ -746,6 +746,10 @@ fn area(sh: Shape) -> f64 {
746746
}
747747
~~~~
748748

749+
> ***Note:*** This feature of the compiler is currently gated behind the
750+
> `#[feature(struct_variant)]` directive. More about these directives can be
751+
> found in the manual.
752+
749753
## Tuples
750754

751755
Tuples in Rust behave exactly like structs, except that their fields
@@ -2665,6 +2669,10 @@ use farm::*;
26652669
# fn main() { cow(); chicken() }
26662670
~~~
26672671

2672+
> ***Note:*** This feature of the compiler is currently gated behind the
2673+
> `#[feature(globs)]` directive. More about these directives can be found in
2674+
> the manual.
2675+
26682676
However, that's not all. You can also rename an item while you're bringing it into scope:
26692677

26702678
~~~

src/etc/extract-tests.py

+1
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,7 @@
6363
#[ allow(unused_variable) ];\n
6464
#[ allow(dead_assignment) ];\n
6565
#[ allow(unused_mut) ];\n
66+
#[ feature(macro_rules, globs, struct_variant) ];\n
6667
""" + block
6768
if xfail:
6869
block = "// xfail-test\n" + block

src/libextra/extra.rs

+2
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,8 @@ Rust extras are part of the standard Rust distribution.
3333
#[license = "MIT/ASL2"];
3434
#[crate_type = "lib"];
3535

36+
#[feature(macro_rules, globs)];
37+
3638
#[deny(non_camel_case_types)];
3739
#[deny(missing_doc)];
3840

src/librustc/driver/driver.rs

+2
Original file line numberDiff line numberDiff line change
@@ -159,6 +159,8 @@ pub fn phase_2_configure_and_expand(sess: Session,
159159
*sess.building_library = session::building_library(sess.opts.crate_type,
160160
&crate, sess.opts.test);
161161

162+
time(time_passes, ~"gated feature checking", (), |_|
163+
front::feature_gate::check_crate(sess, &crate));
162164

163165
// strip before expansion to allow macros to depend on
164166
// configuration variables e.g/ in

src/librustc/front/feature_gate.rs

+176
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,176 @@
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+
37+
// These are used to test this portion of the compiler, they don't actually
38+
// mean anything
39+
("test_accepted_feature", Accepted),
40+
("test_removed_feature", Removed),
41+
];
42+
43+
enum Status {
44+
/// Represents an active feature that is currently being implemented or
45+
/// currently being considered for addition/removal.
46+
Active,
47+
48+
/// Represents a feature which has since been removed (it was once Active)
49+
Removed,
50+
51+
/// This language feature has since been Accepted (it was once Active)
52+
Accepted,
53+
}
54+
55+
struct Context {
56+
features: ~[&'static str],
57+
sess: Session,
58+
}
59+
60+
impl Context {
61+
fn gate_feature(&self, feature: &str, span: Span, explain: &str) {
62+
if !self.has_feature(feature) {
63+
self.sess.span_err(span, explain);
64+
self.sess.span_note(span, format!("add \\#[feature({})] to the \
65+
crate attributes to enable",
66+
feature));
67+
}
68+
}
69+
70+
fn has_feature(&self, feature: &str) -> bool {
71+
self.features.iter().any(|n| n.as_slice() == feature)
72+
}
73+
}
74+
75+
impl Visitor<()> for Context {
76+
fn visit_view_item(&mut self, i: &ast::view_item, _: ()) {
77+
match i.node {
78+
ast::view_item_use(ref paths) => {
79+
for path in paths.iter() {
80+
match path.node {
81+
ast::view_path_glob(*) => {
82+
self.gate_feature("globs", path.span,
83+
"glob import statements are \
84+
experimental and possibly buggy");
85+
}
86+
_ => {}
87+
}
88+
}
89+
}
90+
_ => {}
91+
}
92+
visit::walk_view_item(self, i, ())
93+
}
94+
95+
fn visit_item(&mut self, i: @ast::item, _:()) {
96+
match i.node {
97+
ast::item_enum(ref def, _) => {
98+
for variant in def.variants.iter() {
99+
match variant.node.kind {
100+
ast::struct_variant_kind(*) => {
101+
self.gate_feature("struct_variant", variant.span,
102+
"enum struct variants are \
103+
experimental and possibly buggy");
104+
}
105+
_ => {}
106+
}
107+
}
108+
}
109+
110+
ast::item_mac(ref mac) => {
111+
match mac.node {
112+
ast::mac_invoc_tt(ref path, _, _) => {
113+
let rules = self.sess.ident_of("macro_rules");
114+
if path.segments.last().identifier == rules {
115+
self.gate_feature("macro_rules", i.span,
116+
"macro definitions are not \
117+
stable enough for use and are \
118+
subject to change");
119+
}
120+
}
121+
}
122+
}
123+
124+
_ => {}
125+
}
126+
127+
visit::walk_item(self, i, ());
128+
}
129+
}
130+
131+
pub fn check_crate(sess: Session, crate: &ast::Crate) {
132+
let mut cx = Context {
133+
features: ~[],
134+
sess: sess,
135+
};
136+
137+
for attr in crate.attrs.iter() {
138+
if "feature" != attr.name() { continue }
139+
140+
match attr.meta_item_list() {
141+
None => {
142+
sess.span_err(attr.span, "malformed feature attribute, \
143+
expected #[feature(...)]");
144+
}
145+
Some(list) => {
146+
for &mi in list.iter() {
147+
let name = match mi.node {
148+
ast::MetaWord(word) => word,
149+
_ => {
150+
sess.span_err(mi.span, "malformed feature, expected \
151+
just one word");
152+
continue
153+
}
154+
};
155+
match KNOWN_FEATURES.iter().find(|& &(n, _)| n == name) {
156+
Some(&(name, Active)) => { cx.features.push(name); }
157+
Some(&(_, Removed)) => {
158+
sess.span_err(mi.span, "feature has been removed");
159+
}
160+
Some(&(_, Accepted)) => {
161+
sess.span_warn(mi.span, "feature has added to rust, \
162+
directive not necessary");
163+
}
164+
None => {
165+
sess.span_err(mi.span, "unknown feature");
166+
}
167+
}
168+
}
169+
}
170+
}
171+
}
172+
173+
visit::walk_crate(&mut cx, crate, ());
174+
175+
sess.abort_if_errors();
176+
}

src/librustc/rustc.rs

+3
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,8 @@
1717
#[license = "MIT/ASL2"];
1818
#[crate_type = "lib"];
1919

20+
#[feature(macro_rules, globs, struct_variant)];
21+
2022
// Rustc tasks always run on a fixed_stack_segment, so code in this
2123
// module can call C functions (in particular, LLVM functions) with
2224
// impunity.
@@ -83,6 +85,7 @@ pub mod front {
8385
pub mod test;
8486
pub mod std_inject;
8587
pub mod assign_node_ids;
88+
pub mod feature_gate;
8689
}
8790

8891
pub mod back {

src/librustdoc/rustdoc.rs

+2
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,8 @@
1717
#[license = "MIT/ASL2"];
1818
#[crate_type = "lib"];
1919

20+
#[feature(globs, struct_variant)];
21+
2022
extern mod syntax;
2123
extern mod rustc;
2224
extern mod extra;

src/librusti/rusti.rs

+2
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,8 @@
6666
#[license = "MIT/ASL2"];
6767
#[crate_type = "lib"];
6868

69+
#[feature(globs)];
70+
6971
extern mod extra;
7072
extern mod rustc;
7173
extern mod syntax;

src/librustpkg/rustpkg.rs

+2
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,8 @@
1818
#[license = "MIT/ASL2"];
1919
#[crate_type = "lib"];
2020

21+
#[feature(globs)];
22+
2123
extern mod extra;
2224
extern mod rustc;
2325
extern mod syntax;

src/libstd/std.rs

+2
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,8 @@ they contained the following prologue:
6161
html_favicon_url = "http://www.rust-lang.org/favicon.ico",
6262
html_root_url = "http://static.rust-lang.org/doc/master")];
6363

64+
#[feature(macro_rules, globs)];
65+
6466
// Don't link to std. We are std.
6567
#[no_std];
6668

src/libsyntax/syntax.rs

+2
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,8 @@
2020
#[license = "MIT/ASL2"];
2121
#[crate_type = "lib"];
2222

23+
#[feature(macro_rules, globs)];
24+
2325
extern mod extra;
2426

2527
pub mod util {

src/test/auxiliary/issue_2316_b.rs

+1
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
// except according to those terms.
1010

1111
#[allow(unused_imports)];
12+
#[feature(globs)];
1213

1314
extern mod issue_2316_a;
1415

src/test/auxiliary/struct_variant_xc_aux.rs

+2
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,8 @@
1212
vers = "0.1")];
1313
#[crate_type = "lib"];
1414

15+
#[feature(struct_variant)];
16+
1517
pub enum Enum {
1618
Variant { arg: u8 }
1719
}

src/test/bench/core-std.rs

+2
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,8 @@
1010

1111
// Microbenchmarks for various functions in std and extra
1212

13+
#[feature(macro_rules)];
14+
1315
extern mod extra;
1416

1517
use extra::time::precise_time_s;

src/test/bench/rt-parfib.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ use std::os;
1414
use std::uint;
1515
use std::rt::test::spawntask_later;
1616
use std::cell::Cell;
17-
use std::comm::*;
17+
use std::comm::oneshot;
1818

1919
// A simple implementation of parfib. One subtree is found in a new
2020
// task and communicated over a oneshot pipe, the other is found

src/test/bench/shootout-chameneos-redux.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@
1313
extern mod extra;
1414

1515
use std::cell::Cell;
16-
use std::comm::*;
16+
use std::comm::{stream, SharedChan};
1717
use std::io;
1818
use std::option;
1919
use std::os;

src/test/bench/shootout-pfib.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@
2222
extern mod extra;
2323

2424
use extra::{time, getopts};
25-
use std::comm::*;
25+
use std::comm::{stream, SharedChan};
2626
use std::io::WriterUtil;
2727
use std::io;
2828
use std::os;

0 commit comments

Comments
 (0)