2013-10-02 18:10:16 -07:00
|
|
|
// 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.
|
|
|
|
|
2013-11-26 14:55:06 -08:00
|
|
|
use middle::lint;
|
|
|
|
|
2013-10-02 18:10:16 -07:00
|
|
|
use syntax::ast;
|
Add generation of static libraries to rustc
This commit implements the support necessary for generating both intermediate
and result static rust libraries. This is an implementation of my thoughts in
https://mail.mozilla.org/pipermail/rust-dev/2013-November/006686.html.
When compiling a library, we still retain the "lib" option, although now there
are "rlib", "staticlib", and "dylib" as options for crate_type (and these are
stackable). The idea of "lib" is to generate the "compiler default" instead of
having too choose (although all are interchangeable). For now I have left the
"complier default" to be a dynamic library for size reasons.
Of the rust libraries, lib{std,extra,rustuv} will bootstrap with an
rlib/dylib pair, but lib{rustc,syntax,rustdoc,rustpkg} will only be built as a
dynamic object. I chose this for size reasons, but also because you're probably
not going to be embedding the rustc compiler anywhere any time soon.
Other than the options outlined above, there are a few defaults/preferences that
are now opinionated in the compiler:
* If both a .dylib and .rlib are found for a rust library, the compiler will
prefer the .rlib variant. This is overridable via the -Z prefer-dynamic option
* If generating a "lib", the compiler will generate a dynamic library. This is
overridable by explicitly saying what flavor you'd like (rlib, staticlib,
dylib).
* If no options are passed to the command line, and no crate_type is found in
the destination crate, then an executable is generated
With this change, you can successfully build a rust program with 0 dynamic
dependencies on rust libraries. There is still a dynamic dependency on
librustrt, but I plan on removing that in a subsequent commit.
This change includes no tests just yet. Our current testing
infrastructure/harnesses aren't very amenable to doing flavorful things with
linking, so I'm planning on adding a new mode of testing which I believe belongs
as a separate commit.
Closes #552
2013-11-15 14:03:29 -08:00
|
|
|
use syntax::attr;
|
2013-10-02 18:10:16 -07:00
|
|
|
use syntax::attr::AttrMetaMethods;
|
|
|
|
use syntax::codemap::Span;
|
|
|
|
use syntax::visit;
|
|
|
|
use syntax::visit::Visitor;
|
2013-11-22 23:25:14 +11:00
|
|
|
use syntax::parse::token;
|
2013-10-02 18:10:16 -07:00
|
|
|
|
|
|
|
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),
|
2013-10-15 07:21:54 +02:00
|
|
|
("once_fns", Active),
|
2013-10-21 11:16:58 +02:00
|
|
|
("asm", Active),
|
2013-10-18 01:14:47 -04:00
|
|
|
("managed_boxes", Active),
|
2013-11-22 23:25:14 +11:00
|
|
|
("non_ascii_idents", Active),
|
2013-11-26 14:21:22 -05:00
|
|
|
("thread_local", Active),
|
Add generation of static libraries to rustc
This commit implements the support necessary for generating both intermediate
and result static rust libraries. This is an implementation of my thoughts in
https://mail.mozilla.org/pipermail/rust-dev/2013-November/006686.html.
When compiling a library, we still retain the "lib" option, although now there
are "rlib", "staticlib", and "dylib" as options for crate_type (and these are
stackable). The idea of "lib" is to generate the "compiler default" instead of
having too choose (although all are interchangeable). For now I have left the
"complier default" to be a dynamic library for size reasons.
Of the rust libraries, lib{std,extra,rustuv} will bootstrap with an
rlib/dylib pair, but lib{rustc,syntax,rustdoc,rustpkg} will only be built as a
dynamic object. I chose this for size reasons, but also because you're probably
not going to be embedding the rustc compiler anywhere any time soon.
Other than the options outlined above, there are a few defaults/preferences that
are now opinionated in the compiler:
* If both a .dylib and .rlib are found for a rust library, the compiler will
prefer the .rlib variant. This is overridable via the -Z prefer-dynamic option
* If generating a "lib", the compiler will generate a dynamic library. This is
overridable by explicitly saying what flavor you'd like (rlib, staticlib,
dylib).
* If no options are passed to the command line, and no crate_type is found in
the destination crate, then an executable is generated
With this change, you can successfully build a rust program with 0 dynamic
dependencies on rust libraries. There is still a dynamic dependency on
librustrt, but I plan on removing that in a subsequent commit.
This change includes no tests just yet. Our current testing
infrastructure/harnesses aren't very amenable to doing flavorful things with
linking, so I'm planning on adding a new mode of testing which I believe belongs
as a separate commit.
Closes #552
2013-11-15 14:03:29 -08:00
|
|
|
("link_args", Active),
|
2013-10-02 18:10:16 -07:00
|
|
|
|
|
|
|
// 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 {
|
2013-11-22 23:25:14 +11:00
|
|
|
fn visit_ident(&mut self, sp: Span, id: ast::Ident, _: ()) {
|
|
|
|
let s = token::ident_to_str(&id);
|
|
|
|
|
|
|
|
if !s.is_ascii() {
|
|
|
|
self.gate_feature("non_ascii_idents", sp,
|
|
|
|
"non-ascii idents are not fully supported.");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-10-02 18:10:16 -07:00
|
|
|
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 {
|
2013-11-28 12:22:53 -08:00
|
|
|
ast::view_path_glob(..) => {
|
2013-10-02 18:10:16 -07:00
|
|
|
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, _:()) {
|
2013-11-26 14:21:22 -05:00
|
|
|
for attr in i.attrs.iter() {
|
Add generation of static libraries to rustc
This commit implements the support necessary for generating both intermediate
and result static rust libraries. This is an implementation of my thoughts in
https://mail.mozilla.org/pipermail/rust-dev/2013-November/006686.html.
When compiling a library, we still retain the "lib" option, although now there
are "rlib", "staticlib", and "dylib" as options for crate_type (and these are
stackable). The idea of "lib" is to generate the "compiler default" instead of
having too choose (although all are interchangeable). For now I have left the
"complier default" to be a dynamic library for size reasons.
Of the rust libraries, lib{std,extra,rustuv} will bootstrap with an
rlib/dylib pair, but lib{rustc,syntax,rustdoc,rustpkg} will only be built as a
dynamic object. I chose this for size reasons, but also because you're probably
not going to be embedding the rustc compiler anywhere any time soon.
Other than the options outlined above, there are a few defaults/preferences that
are now opinionated in the compiler:
* If both a .dylib and .rlib are found for a rust library, the compiler will
prefer the .rlib variant. This is overridable via the -Z prefer-dynamic option
* If generating a "lib", the compiler will generate a dynamic library. This is
overridable by explicitly saying what flavor you'd like (rlib, staticlib,
dylib).
* If no options are passed to the command line, and no crate_type is found in
the destination crate, then an executable is generated
With this change, you can successfully build a rust program with 0 dynamic
dependencies on rust libraries. There is still a dynamic dependency on
librustrt, but I plan on removing that in a subsequent commit.
This change includes no tests just yet. Our current testing
infrastructure/harnesses aren't very amenable to doing flavorful things with
linking, so I'm planning on adding a new mode of testing which I believe belongs
as a separate commit.
Closes #552
2013-11-15 14:03:29 -08:00
|
|
|
if "thread_local" == attr.name() &&
|
|
|
|
cfg!(stage0, remove_this_on_next_snapshot) { // NOTE: snap rem
|
2013-11-26 14:21:22 -05:00
|
|
|
self.gate_feature("thread_local", i.span,
|
|
|
|
"`#[thread_local]` is an experimental feature, and does not \
|
|
|
|
currently handle destructors. There is no corresponding \
|
|
|
|
`#[task_local]` mapping to the task model");
|
|
|
|
}
|
|
|
|
}
|
2013-10-02 18:10:16 -07:00
|
|
|
match i.node {
|
|
|
|
ast::item_enum(ref def, _) => {
|
|
|
|
for variant in def.variants.iter() {
|
|
|
|
match variant.node.kind {
|
2013-11-28 12:22:53 -08:00
|
|
|
ast::struct_variant_kind(..) => {
|
2013-10-02 18:10:16 -07:00
|
|
|
self.gate_feature("struct_variant", variant.span,
|
|
|
|
"enum struct variants are \
|
|
|
|
experimental and possibly buggy");
|
|
|
|
}
|
|
|
|
_ => {}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-11-28 18:03:38 -08:00
|
|
|
ast::item_foreign_mod(..) => {
|
Add generation of static libraries to rustc
This commit implements the support necessary for generating both intermediate
and result static rust libraries. This is an implementation of my thoughts in
https://mail.mozilla.org/pipermail/rust-dev/2013-November/006686.html.
When compiling a library, we still retain the "lib" option, although now there
are "rlib", "staticlib", and "dylib" as options for crate_type (and these are
stackable). The idea of "lib" is to generate the "compiler default" instead of
having too choose (although all are interchangeable). For now I have left the
"complier default" to be a dynamic library for size reasons.
Of the rust libraries, lib{std,extra,rustuv} will bootstrap with an
rlib/dylib pair, but lib{rustc,syntax,rustdoc,rustpkg} will only be built as a
dynamic object. I chose this for size reasons, but also because you're probably
not going to be embedding the rustc compiler anywhere any time soon.
Other than the options outlined above, there are a few defaults/preferences that
are now opinionated in the compiler:
* If both a .dylib and .rlib are found for a rust library, the compiler will
prefer the .rlib variant. This is overridable via the -Z prefer-dynamic option
* If generating a "lib", the compiler will generate a dynamic library. This is
overridable by explicitly saying what flavor you'd like (rlib, staticlib,
dylib).
* If no options are passed to the command line, and no crate_type is found in
the destination crate, then an executable is generated
With this change, you can successfully build a rust program with 0 dynamic
dependencies on rust libraries. There is still a dynamic dependency on
librustrt, but I plan on removing that in a subsequent commit.
This change includes no tests just yet. Our current testing
infrastructure/harnesses aren't very amenable to doing flavorful things with
linking, so I'm planning on adding a new mode of testing which I believe belongs
as a separate commit.
Closes #552
2013-11-15 14:03:29 -08:00
|
|
|
if attr::contains_name(i.attrs, "link_args") &&
|
|
|
|
cfg!(stage0, remove_this_on_next_snapshot) { // NOTE: snap
|
|
|
|
self.gate_feature("link_args", i.span,
|
|
|
|
"the `link_args` attribute is not portable \
|
|
|
|
across platforms, it is recommended to \
|
|
|
|
use `#[link(name = \"foo\")]` instead")
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-10-02 18:10:16 -07:00
|
|
|
_ => {}
|
|
|
|
}
|
|
|
|
|
|
|
|
visit::walk_item(self, i, ());
|
|
|
|
}
|
2013-10-15 07:21:54 +02:00
|
|
|
|
2013-10-21 11:16:58 +02:00
|
|
|
fn visit_mac(&mut self, macro: &ast::mac, _: ()) {
|
|
|
|
let ast::mac_invoc_tt(ref path, _, _) = macro.node;
|
|
|
|
|
|
|
|
if path.segments.last().identifier == self.sess.ident_of("macro_rules") {
|
|
|
|
self.gate_feature("macro_rules", path.span, "macro definitions are \
|
|
|
|
not stable enough for use and are subject to change");
|
|
|
|
}
|
|
|
|
|
|
|
|
else if path.segments.last().identifier == self.sess.ident_of("asm") {
|
2013-10-22 01:18:57 +02:00
|
|
|
self.gate_feature("asm", path.span, "inline assembly is not \
|
|
|
|
stable enough for use and is subject to change");
|
2013-10-21 11:16:58 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-10-15 07:21:54 +02:00
|
|
|
fn visit_ty(&mut self, t: &ast::Ty, _: ()) {
|
|
|
|
match t.node {
|
2013-10-28 15:22:49 -07:00
|
|
|
ast::ty_closure(closure) if closure.onceness == ast::Once &&
|
|
|
|
closure.sigil != ast::OwnedSigil => {
|
2013-10-15 07:21:54 +02:00
|
|
|
self.gate_feature("once_fns", t.span,
|
|
|
|
"once functions are \
|
|
|
|
experimental and likely to be removed");
|
|
|
|
|
|
|
|
},
|
2013-10-23 04:49:18 -04:00
|
|
|
ast::ty_box(_) => {
|
2013-10-30 16:27:31 -07:00
|
|
|
self.gate_feature("managed_boxes", t.span,
|
2013-11-26 14:21:22 -05:00
|
|
|
"The managed box syntax is being replaced by the `std::gc::Gc` \
|
|
|
|
and `std::rc::Rc` types. Equivalent functionality to managed \
|
2013-11-22 06:54:33 -05:00
|
|
|
trait objects will be implemented but is currently missing.");
|
2013-10-18 01:14:47 -04:00
|
|
|
}
|
2013-10-15 07:21:54 +02:00
|
|
|
_ => {}
|
|
|
|
}
|
|
|
|
|
|
|
|
visit::walk_ty(self, t, ());
|
|
|
|
}
|
2013-10-02 18:10:16 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
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 => {
|
2013-11-26 14:55:06 -08:00
|
|
|
sess.add_lint(lint::unknown_features,
|
|
|
|
ast::CRATE_NODE_ID,
|
|
|
|
mi.span,
|
|
|
|
~"unknown feature");
|
2013-10-02 18:10:16 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
visit::walk_crate(&mut cx, crate, ());
|
|
|
|
|
|
|
|
sess.abort_if_errors();
|
|
|
|
}
|