mirror of
https://github.com/rust-lang/rust.git
synced 2024-11-25 16:24:46 +00:00
Preliminary feature staging
This partially implements the feature staging described in the [release channel RFC][rc]. It does not yet fully conform to the RFC as written, but does accomplish its goals sufficiently for the 1.0 alpha release. It has three primary user-visible effects: * On the nightly channel, use of unstable APIs generates a warning. * On the beta channel, use of unstable APIs generates a warning. * On the beta channel, use of feature gates generates a warning. Code that does not trigger these warnings is considered 'stable', modulo pre-1.0 bugs. Disabling the warnings for unstable APIs continues to be done in the existing (i.e. old) style, via `#[allow(...)]`, not that specified in the RFC. I deem this marginally acceptable since any code that must do this is not using the stable dialect of Rust. Use of feature gates is itself gated with the new 'unstable_features' lint, on nightly set to 'allow', and on beta 'warn'. The attribute scheme used here corresponds to an older version of the RFC, with the `#[staged_api]` crate attribute toggling the staging behavior of the stability attributes, but the user impact is only in-tree so I'm not concerned about having to make design changes later (and I may ultimately prefer the scheme here after all, with the `#[staged_api]` crate attribute). Since the Rust codebase itself makes use of unstable features the compiler and build system to a midly elaborate dance to allow it to bootstrap while disobeying these lints (which would otherwise be errors because Rust builds with `-D warnings`). This patch includes one significant hack that causes a regression. Because the `format_args!` macro emits calls to unstable APIs it would trigger the lint. I added a hack to the lint to make it not trigger, but this in turn causes arguments to `println!` not to be checked for feature gates. I don't presently understand macro expansion well enough to fix. This is bug #20661. Closes #16678 [rc]: https://github.com/rust-lang/rfcs/blob/master/text/0507-release-channels.md
This commit is contained in:
parent
9f1ead8fad
commit
c27133e2ce
12
configure
vendored
12
configure
vendored
@ -599,6 +599,18 @@ then
|
||||
fi
|
||||
putvar CFG_RELEASE_CHANNEL
|
||||
|
||||
# A magic value that allows the compiler to use unstable features
|
||||
# during the bootstrap even when doing so would normally be an error
|
||||
# because of feature staging or because the build turns on
|
||||
# warnings-as-errors and unstable features default to warnings. The
|
||||
# build has to match this key in an env var. Meant to be a mild
|
||||
# deterrent from users just turning on unstable features on the stable
|
||||
# channel.
|
||||
# Basing CFG_BOOTSTRAP_KEY on CFG_BOOTSTRAP_KEY lets it get picked up
|
||||
# during a Makefile reconfig.
|
||||
CFG_BOOTSTRAP_KEY="${CFG_BOOTSTRAP_KEY-`date +%N`}"
|
||||
putvar CFG_BOOTSTRAP_KEY
|
||||
|
||||
step_msg "looking for build programs"
|
||||
|
||||
probe_need CFG_PERL perl
|
||||
|
11
mk/main.mk
11
mk/main.mk
@ -25,11 +25,13 @@ ifeq ($(CFG_RELEASE_CHANNEL),stable)
|
||||
CFG_RELEASE=$(CFG_RELEASE_NUM)
|
||||
# This is the string used in dist artifact file names, e.g. "0.12.0", "nightly"
|
||||
CFG_PACKAGE_VERS=$(CFG_RELEASE_NUM)
|
||||
CFG_DISABLE_UNSTABLE_FEATURES=1
|
||||
endif
|
||||
ifeq ($(CFG_RELEASE_CHANNEL),beta)
|
||||
# The beta channel is temporarily called 'alpha'
|
||||
CFG_RELEASE=$(CFG_RELEASE_NUM)-alpha$(CFG_BETA_CYCLE)
|
||||
CFG_PACKAGE_VERS=$(CFG_RELEASE_NUM)-alpha$(CFG_BETA_CYCLE)
|
||||
CFG_DISABLE_UNSTABLE_FEATURES=1
|
||||
endif
|
||||
ifeq ($(CFG_RELEASE_CHANNEL),nightly)
|
||||
CFG_RELEASE=$(CFG_RELEASE_NUM)-nightly
|
||||
@ -319,11 +321,20 @@ export CFG_VERSION_WIN
|
||||
export CFG_RELEASE
|
||||
export CFG_PACKAGE_NAME
|
||||
export CFG_BUILD
|
||||
export CFG_RELEASE_CHANNEL
|
||||
export CFG_LLVM_ROOT
|
||||
export CFG_PREFIX
|
||||
export CFG_LIBDIR
|
||||
export CFG_LIBDIR_RELATIVE
|
||||
export CFG_DISABLE_INJECT_STD_VERSION
|
||||
ifdef CFG_DISABLE_UNSTABLE_FEATURES
|
||||
CFG_INFO := $(info cfg: disabling unstable features (CFG_DISABLE_UNSTABLE_FEATURES))
|
||||
# Turn on feature-staging
|
||||
export CFG_DISABLE_UNSTABLE_FEATURES
|
||||
endif
|
||||
# Subvert unstable feature lints to do the self-build
|
||||
export CFG_BOOTSTRAP_KEY
|
||||
export RUSTC_BOOTSTRAP_KEY:=$(CFG_BOOTSTRAP_KEY)
|
||||
|
||||
######################################################################
|
||||
# Per-stage targets and runner
|
||||
|
@ -58,6 +58,7 @@
|
||||
|
||||
#![crate_name = "alloc"]
|
||||
#![experimental]
|
||||
#![staged_api]
|
||||
#![crate_type = "rlib"]
|
||||
#![doc(html_logo_url = "http://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png",
|
||||
html_favicon_url = "http://www.rust-lang.org/favicon.ico",
|
||||
|
@ -21,6 +21,7 @@
|
||||
|
||||
#![crate_name = "arena"]
|
||||
#![experimental]
|
||||
#![staged_api]
|
||||
#![crate_type = "rlib"]
|
||||
#![crate_type = "dylib"]
|
||||
#![doc(html_logo_url = "http://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png",
|
||||
|
@ -15,6 +15,7 @@
|
||||
|
||||
#![crate_name = "collections"]
|
||||
#![experimental]
|
||||
#![staged_api]
|
||||
#![crate_type = "rlib"]
|
||||
#![doc(html_logo_url = "http://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png",
|
||||
html_favicon_url = "http://www.rust-lang.org/favicon.ico",
|
||||
|
@ -49,6 +49,7 @@
|
||||
|
||||
#![crate_name = "core"]
|
||||
#![experimental]
|
||||
#![staged_api]
|
||||
#![crate_type = "rlib"]
|
||||
#![doc(html_logo_url = "http://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png",
|
||||
html_favicon_url = "http://www.rust-lang.org/favicon.ico",
|
||||
|
@ -16,6 +16,7 @@
|
||||
|
||||
#![crate_name = "flate"]
|
||||
#![experimental]
|
||||
#![staged_api]
|
||||
#![crate_type = "rlib"]
|
||||
#![crate_type = "dylib"]
|
||||
#![doc(html_logo_url = "http://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png",
|
||||
|
@ -16,6 +16,7 @@
|
||||
|
||||
#![crate_name = "fmt_macros"]
|
||||
#![experimental]
|
||||
#![staged_api]
|
||||
#![crate_type = "rlib"]
|
||||
#![crate_type = "dylib"]
|
||||
#![doc(html_logo_url = "http://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png",
|
||||
|
@ -79,6 +79,7 @@
|
||||
|
||||
#![crate_name = "getopts"]
|
||||
#![experimental = "use the crates.io `getopts` library instead"]
|
||||
#![staged_api]
|
||||
#![crate_type = "rlib"]
|
||||
#![crate_type = "dylib"]
|
||||
#![doc(html_logo_url = "http://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png",
|
||||
|
@ -266,6 +266,7 @@
|
||||
|
||||
#![crate_name = "graphviz"]
|
||||
#![experimental]
|
||||
#![staged_api]
|
||||
#![crate_type = "rlib"]
|
||||
#![crate_type = "dylib"]
|
||||
#![doc(html_logo_url = "http://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png",
|
||||
|
@ -11,6 +11,7 @@
|
||||
#![crate_name = "libc"]
|
||||
#![crate_type = "rlib"]
|
||||
#![cfg_attr(not(feature = "cargo-build"), experimental)]
|
||||
#![cfg_attr(not(feature = "cargo-build"), staged_api)]
|
||||
#![no_std]
|
||||
#![doc(html_logo_url = "http://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png",
|
||||
html_favicon_url = "http://www.rust-lang.org/favicon.ico",
|
||||
|
@ -157,6 +157,7 @@
|
||||
|
||||
#![crate_name = "log"]
|
||||
#![experimental = "use the crates.io `log` library instead"]
|
||||
#![staged_api]
|
||||
#![crate_type = "rlib"]
|
||||
#![crate_type = "dylib"]
|
||||
#![doc(html_logo_url = "http://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png",
|
||||
|
@ -25,6 +25,7 @@
|
||||
|
||||
#![no_std]
|
||||
#![experimental]
|
||||
#![staged_api]
|
||||
|
||||
#[macro_use]
|
||||
extern crate core;
|
||||
|
@ -17,6 +17,7 @@
|
||||
|
||||
#![crate_name = "rbml"]
|
||||
#![experimental]
|
||||
#![staged_api]
|
||||
#![crate_type = "rlib"]
|
||||
#![crate_type = "dylib"]
|
||||
#![doc(html_logo_url = "http://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png",
|
||||
|
@ -17,6 +17,7 @@
|
||||
#![crate_type = "rlib"]
|
||||
#![crate_type = "dylib"]
|
||||
#![experimental = "use the crates.io `regex` library instead"]
|
||||
#![staged_api]
|
||||
#![doc(html_logo_url = "http://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png",
|
||||
html_favicon_url = "http://www.rust-lang.org/favicon.ico",
|
||||
html_root_url = "http://doc.rust-lang.org/nightly/",
|
||||
|
@ -16,6 +16,7 @@
|
||||
|
||||
#![crate_name = "rustc"]
|
||||
#![experimental]
|
||||
#![staged_api]
|
||||
#![crate_type = "dylib"]
|
||||
#![crate_type = "rlib"]
|
||||
#![doc(html_logo_url = "http://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png",
|
||||
|
@ -34,7 +34,7 @@ use middle::{def, pat_util, stability};
|
||||
use middle::const_eval::{eval_const_expr_partial, const_int, const_uint};
|
||||
use util::ppaux::{ty_to_string};
|
||||
use util::nodemap::{FnvHashMap, NodeSet};
|
||||
use lint::{Context, LintPass, LintArray};
|
||||
use lint::{Context, LintPass, LintArray, Lint};
|
||||
|
||||
use std::collections::hash_map::Entry::{Occupied, Vacant};
|
||||
use std::num::SignedInt;
|
||||
@ -1643,6 +1643,13 @@ declare_lint! {
|
||||
"detects use of #[unstable] items (incl. items with no stability attribute)"
|
||||
}
|
||||
|
||||
declare_lint!(STAGED_EXPERIMENTAL, Warn,
|
||||
"detects use of #[experimental] items in staged builds");
|
||||
|
||||
declare_lint!(STAGED_UNSTABLE, Warn,
|
||||
"detects use of #[unstable] items (incl. items with no stability attribute) \
|
||||
in staged builds");
|
||||
|
||||
/// Checks for use of items with `#[deprecated]`, `#[experimental]` and
|
||||
/// `#[unstable]` attributes, or no stability attribute.
|
||||
#[derive(Copy)]
|
||||
@ -1650,12 +1657,13 @@ pub struct Stability;
|
||||
|
||||
impl Stability {
|
||||
fn lint(&self, cx: &Context, id: ast::DefId, span: Span) {
|
||||
let stability = stability::lookup(cx.tcx, id);
|
||||
|
||||
let ref stability = stability::lookup(cx.tcx, id);
|
||||
let cross_crate = !ast_util::is_local(id);
|
||||
|
||||
// stability attributes are promises made across crates; only
|
||||
// check DEPRECATED for crate-local usage.
|
||||
let (lint, label) = match stability {
|
||||
let (lint, label) = match *stability {
|
||||
// no stability attributes == Unstable
|
||||
None if cross_crate => (UNSTABLE, "unmarked"),
|
||||
Some(attr::Stability { level: attr::Unstable, .. }) if cross_crate =>
|
||||
@ -1667,24 +1675,53 @@ impl Stability {
|
||||
_ => return
|
||||
};
|
||||
|
||||
let msg = match stability {
|
||||
Some(attr::Stability { text: Some(ref s), .. }) => {
|
||||
format!("use of {} item: {}", label, *s)
|
||||
output(cx, span, stability, lint, label);
|
||||
if cross_crate && stability::is_staged_api(cx.tcx, id) {
|
||||
if lint.name == UNSTABLE.name {
|
||||
output(cx, span, stability, STAGED_UNSTABLE, label);
|
||||
} else if lint.name == EXPERIMENTAL.name {
|
||||
output(cx, span, stability, STAGED_EXPERIMENTAL, label);
|
||||
}
|
||||
_ => format!("use of {} item", label)
|
||||
};
|
||||
}
|
||||
|
||||
cx.span_lint(lint, span, msg.index(&FullRange));
|
||||
fn output(cx: &Context, span: Span, stability: &Option<attr::Stability>,
|
||||
lint: &'static Lint, label: &'static str) {
|
||||
let msg = match *stability {
|
||||
Some(attr::Stability { text: Some(ref s), .. }) => {
|
||||
format!("use of {} item: {}", label, *s)
|
||||
}
|
||||
_ => format!("use of {} item", label)
|
||||
};
|
||||
|
||||
cx.span_lint(lint, span, msg.index(&FullRange));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
fn is_internal(&self, cx: &Context, span: Span) -> bool {
|
||||
cx.tcx.sess.codemap().span_is_internal(span)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
impl LintPass for Stability {
|
||||
fn get_lints(&self) -> LintArray {
|
||||
lint_array!(DEPRECATED, EXPERIMENTAL, UNSTABLE)
|
||||
lint_array!(DEPRECATED, EXPERIMENTAL, UNSTABLE, STAGED_EXPERIMENTAL, STAGED_UNSTABLE)
|
||||
}
|
||||
|
||||
fn check_crate(&mut self, _: &Context, c: &ast::Crate) {
|
||||
// Just mark the #[staged_api] attribute used, though nothing else is done
|
||||
// with it during this pass over the source.
|
||||
for attr in c.attrs.iter() {
|
||||
if attr.name().get() == "staged_api" {
|
||||
match attr.node.value.node {
|
||||
ast::MetaWord(_) => {
|
||||
attr::mark_used(attr);
|
||||
}
|
||||
_ => (/*pass*/)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn check_view_item(&mut self, cx: &Context, item: &ast::ViewItem) {
|
||||
@ -1746,6 +1783,7 @@ impl LintPass for Stability {
|
||||
}
|
||||
_ => return
|
||||
};
|
||||
|
||||
self.lint(cx, id, span);
|
||||
}
|
||||
|
||||
@ -1878,3 +1916,22 @@ impl LintPass for HardwiredLints {
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/// Forbids using the `#[feature(...)]` attribute
|
||||
#[deriving(Copy)]
|
||||
pub struct UnstableFeatures;
|
||||
|
||||
declare_lint!(UNSTABLE_FEATURES, Allow,
|
||||
"enabling unstable features");
|
||||
|
||||
impl LintPass for UnstableFeatures {
|
||||
fn get_lints(&self) -> LintArray {
|
||||
lint_array!(UNSTABLE_FEATURES)
|
||||
}
|
||||
fn check_attribute(&mut self, ctx: &Context, attr: &ast::Attribute) {
|
||||
use syntax::attr;
|
||||
if attr::contains_name(&[attr.node.value.clone()], "feature") {
|
||||
ctx.span_lint(UNSTABLE_FEATURES, attr.span, "unstable feature");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -28,8 +28,9 @@ use self::TargetLint::*;
|
||||
use middle::privacy::ExportedItems;
|
||||
use middle::ty::{self, Ty};
|
||||
use session::{early_error, Session};
|
||||
use session::config::UnstableFeatures;
|
||||
use lint::{Level, LevelSource, Lint, LintId, LintArray, LintPass, LintPassObject};
|
||||
use lint::{Default, CommandLine, Node, Allow, Warn, Deny, Forbid};
|
||||
use lint::{Default, CommandLine, Node, Allow, Warn, Deny, Forbid, ReleaseChannel};
|
||||
use lint::builtin;
|
||||
use util::nodemap::FnvHashMap;
|
||||
|
||||
@ -210,6 +211,7 @@ impl LintStore {
|
||||
UnusedAllocation,
|
||||
Stability,
|
||||
MissingCopyImplementations,
|
||||
UnstableFeatures,
|
||||
);
|
||||
|
||||
add_builtin_with_new!(sess,
|
||||
@ -298,6 +300,29 @@ impl LintStore {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn maybe_stage_features(&mut self, sess: &Session) {
|
||||
let lvl = match sess.opts.unstable_features {
|
||||
UnstableFeatures::Default => return,
|
||||
UnstableFeatures::Disallow => Warn,
|
||||
UnstableFeatures::Cheat => Allow
|
||||
};
|
||||
match self.by_name.get("unstable_features") {
|
||||
Some(&Id(lint_id)) => self.set_level(lint_id, (lvl, ReleaseChannel)),
|
||||
Some(&Renamed(_, lint_id)) => self.set_level(lint_id, (lvl, ReleaseChannel)),
|
||||
None => unreachable!()
|
||||
}
|
||||
match self.by_name.get("staged_unstable") {
|
||||
Some(&Id(lint_id)) => self.set_level(lint_id, (lvl, ReleaseChannel)),
|
||||
Some(&Renamed(_, lint_id)) => self.set_level(lint_id, (lvl, ReleaseChannel)),
|
||||
None => unreachable!()
|
||||
}
|
||||
match self.by_name.get("staged_experimental") {
|
||||
Some(&Id(lint_id)) => self.set_level(lint_id, (lvl, ReleaseChannel)),
|
||||
Some(&Renamed(_, lint_id)) => self.set_level(lint_id, (lvl, ReleaseChannel)),
|
||||
None => unreachable!()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Context for lint checking.
|
||||
@ -380,6 +405,7 @@ pub fn raw_emit_lint(sess: &Session, lint: &'static Lint,
|
||||
if level == Allow { return }
|
||||
|
||||
let name = lint.name_lower();
|
||||
let mut def = None;
|
||||
let mut note = None;
|
||||
let msg = match source {
|
||||
Default => {
|
||||
@ -394,7 +420,13 @@ pub fn raw_emit_lint(sess: &Session, lint: &'static Lint,
|
||||
}, name.replace("_", "-"))
|
||||
},
|
||||
Node(src) => {
|
||||
note = Some(src);
|
||||
def = Some(src);
|
||||
msg.to_string()
|
||||
}
|
||||
ReleaseChannel => {
|
||||
let release_channel = option_env!("CFG_RELEASE_CHANNEL").unwrap_or("(unknown)");
|
||||
note = Some(format!("this feature may not be used in the {} release channel",
|
||||
release_channel));
|
||||
msg.to_string()
|
||||
}
|
||||
};
|
||||
@ -410,7 +442,11 @@ pub fn raw_emit_lint(sess: &Session, lint: &'static Lint,
|
||||
_ => sess.bug("impossible level in raw_emit_lint"),
|
||||
}
|
||||
|
||||
for span in note.into_iter() {
|
||||
for note in note.into_iter() {
|
||||
sess.note(note.index(&FullRange));
|
||||
}
|
||||
|
||||
for span in def.into_iter() {
|
||||
sess.span_note(span, "lint level defined here");
|
||||
}
|
||||
}
|
||||
@ -767,6 +803,10 @@ impl LintPass for GatherNodeLevels {
|
||||
/// Consumes the `lint_store` field of the `Session`.
|
||||
pub fn check_crate(tcx: &ty::ctxt,
|
||||
exported_items: &ExportedItems) {
|
||||
|
||||
// If this is a feature-staged build of rustc then flip several lints to 'forbid'
|
||||
tcx.sess.lint_store.borrow_mut().maybe_stage_features(&tcx.sess);
|
||||
|
||||
let krate = tcx.map.krate();
|
||||
let mut cx = Context::new(tcx, krate, exported_items);
|
||||
|
||||
|
@ -248,6 +248,9 @@ pub enum LintSource {
|
||||
|
||||
/// Lint level was set by a command-line flag.
|
||||
CommandLine,
|
||||
|
||||
/// Lint level was set by the release channel.
|
||||
ReleaseChannel
|
||||
}
|
||||
|
||||
pub type LevelSource = (Level, LintSource);
|
||||
|
@ -27,6 +27,7 @@ use std::rc::Rc;
|
||||
use syntax::ast;
|
||||
use syntax::ast_map;
|
||||
use syntax::attr;
|
||||
use syntax::attr::AttrMetaMethods;
|
||||
use syntax::diagnostic::expect;
|
||||
use syntax::parse::token;
|
||||
|
||||
@ -375,6 +376,18 @@ pub fn get_stability(cstore: &cstore::CStore,
|
||||
decoder::get_stability(&*cdata, def.node)
|
||||
}
|
||||
|
||||
pub fn is_staged_api(cstore: &cstore::CStore, def: ast::DefId) -> bool {
|
||||
let cdata = cstore.get_crate_data(def.krate);
|
||||
let attrs = decoder::get_crate_attributes(cdata.data());
|
||||
for attr in attrs.iter() {
|
||||
if attr.name().get() == "staged_api" {
|
||||
match attr.node.value.node { ast::MetaWord(_) => return true, _ => (/*pass*/) }
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
pub fn get_repr_attrs(cstore: &cstore::CStore, def: ast::DefId)
|
||||
-> Vec<attr::ReprAttr> {
|
||||
let cdata = cstore.get_crate_data(def.krate);
|
||||
|
@ -189,3 +189,19 @@ pub fn lookup(tcx: &ty::ctxt, id: DefId) -> Option<Stability> {
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
pub fn is_staged_api(tcx: &ty::ctxt, id: DefId) -> bool {
|
||||
match ty::trait_item_of_item(tcx, id) {
|
||||
Some(ty::MethodTraitItemId(trait_method_id))
|
||||
if trait_method_id != id => {
|
||||
is_staged_api(tcx, trait_method_id)
|
||||
}
|
||||
_ if is_local(id) => {
|
||||
// Unused case
|
||||
unreachable!()
|
||||
}
|
||||
_ => {
|
||||
csearch::is_staged_api(&tcx.sess.cstore, id)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -111,7 +111,24 @@ pub struct Options {
|
||||
/// An optional name to use as the crate for std during std injection,
|
||||
/// written `extern crate std = "name"`. Default to "std". Used by
|
||||
/// out-of-tree drivers.
|
||||
pub alt_std_name: Option<String>
|
||||
pub alt_std_name: Option<String>,
|
||||
/// Indicates how the compiler should treat unstable features
|
||||
pub unstable_features: UnstableFeatures
|
||||
}
|
||||
|
||||
#[deriving(Clone, Copy)]
|
||||
pub enum UnstableFeatures {
|
||||
/// Hard errors for unstable features are active, as on
|
||||
/// beta/stable channels.
|
||||
Disallow,
|
||||
/// Use the default lint levels
|
||||
Default,
|
||||
/// Errors are bypassed for bootstrapping. This is required any time
|
||||
/// during the build that feature-related lints are set to warn or above
|
||||
/// because the build turns on warnings-as-errors and uses lots of unstable
|
||||
/// features. As a result, this this is always required for building Rust
|
||||
/// itself.
|
||||
Cheat
|
||||
}
|
||||
|
||||
#[derive(Clone, PartialEq, Eq)]
|
||||
@ -217,6 +234,7 @@ pub fn basic_options() -> Options {
|
||||
crate_name: None,
|
||||
alt_std_name: None,
|
||||
libs: Vec::new(),
|
||||
unstable_features: UnstableFeatures::Disallow
|
||||
}
|
||||
}
|
||||
|
||||
@ -1149,6 +1167,7 @@ pub fn build_session_options(matches: &getopts::Matches) -> Options {
|
||||
crate_name: crate_name,
|
||||
alt_std_name: None,
|
||||
libs: libs,
|
||||
unstable_features: UnstableFeatures::Disallow
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -23,6 +23,7 @@
|
||||
|
||||
#![crate_name = "rustc_back"]
|
||||
#![experimental]
|
||||
#![staged_api]
|
||||
#![crate_type = "dylib"]
|
||||
#![crate_type = "rlib"]
|
||||
#![doc(html_logo_url = "http://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png",
|
||||
|
@ -10,6 +10,7 @@
|
||||
|
||||
#![crate_name = "rustc_borrowck"]
|
||||
#![experimental]
|
||||
#![staged_api]
|
||||
#![crate_type = "dylib"]
|
||||
#![crate_type = "rlib"]
|
||||
#![doc(html_logo_url = "http://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png",
|
||||
|
@ -16,6 +16,7 @@
|
||||
|
||||
#![crate_name = "rustc_driver"]
|
||||
#![experimental]
|
||||
#![staged_api]
|
||||
#![crate_type = "dylib"]
|
||||
#![crate_type = "rlib"]
|
||||
#![doc(html_logo_url = "http://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png",
|
||||
@ -46,7 +47,7 @@ pub use syntax::diagnostic;
|
||||
|
||||
use rustc_trans::back::link;
|
||||
use rustc::session::{config, Session, build_session};
|
||||
use rustc::session::config::{Input, PrintRequest};
|
||||
use rustc::session::config::{Input, PrintRequest, UnstableFeatures};
|
||||
use rustc::lint::Lint;
|
||||
use rustc::lint;
|
||||
use rustc::metadata;
|
||||
@ -132,7 +133,11 @@ fn run_compiler(args: &[String]) {
|
||||
_ => early_error("multiple input filenames provided")
|
||||
};
|
||||
|
||||
let mut sopts = sopts;
|
||||
sopts.unstable_features = get_unstable_features_setting();
|
||||
|
||||
let mut sess = build_session(sopts, input_file_path, descriptions);
|
||||
|
||||
let cfg = config::build_configuration(&sess);
|
||||
if print_crate_info(&sess, Some(&input), &odir, &ofile) {
|
||||
return
|
||||
@ -181,6 +186,21 @@ fn run_compiler(args: &[String]) {
|
||||
driver::compile_input(sess, cfg, &input, &odir, &ofile, None);
|
||||
}
|
||||
|
||||
pub fn get_unstable_features_setting() -> UnstableFeatures {
|
||||
// Whether this is a feature-staged build, i.e. on the beta or stable channel
|
||||
let disable_unstable_features = option_env!("CFG_DISABLE_UNSTABLE_FEATURES").is_some();
|
||||
// The secret key needed to get through the rustc build itself by
|
||||
// subverting the unstable features lints
|
||||
let bootstrap_secret_key = option_env!("CFG_BOOTSTRAP_KEY");
|
||||
// The matching key to the above, only known by the build system
|
||||
let bootstrap_provided_key = os::getenv("RUSTC_BOOTSTRAP_KEY");
|
||||
match (disable_unstable_features, bootstrap_secret_key, bootstrap_provided_key) {
|
||||
(_, Some(ref s), Some(ref p)) if s == p => UnstableFeatures::Cheat,
|
||||
(true, _, _) => UnstableFeatures::Disallow,
|
||||
(false, _, _) => UnstableFeatures::Default
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns a version string such as "0.12.0-dev".
|
||||
pub fn release_str() -> Option<&'static str> {
|
||||
option_env!("CFG_RELEASE")
|
||||
|
@ -15,6 +15,7 @@
|
||||
|
||||
#![crate_name = "rustc_llvm"]
|
||||
#![experimental]
|
||||
#![staged_api]
|
||||
#![crate_type = "dylib"]
|
||||
#![crate_type = "rlib"]
|
||||
#![doc(html_logo_url = "http://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png",
|
||||
|
@ -10,6 +10,7 @@
|
||||
|
||||
#![crate_name = "rustc_resolve"]
|
||||
#![experimental]
|
||||
#![staged_api]
|
||||
#![crate_type = "dylib"]
|
||||
#![crate_type = "rlib"]
|
||||
#![doc(html_logo_url = "http://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png",
|
||||
|
@ -16,6 +16,7 @@
|
||||
|
||||
#![crate_name = "rustc_trans"]
|
||||
#![experimental]
|
||||
#![staged_api]
|
||||
#![crate_type = "dylib"]
|
||||
#![crate_type = "rlib"]
|
||||
#![doc(html_logo_url = "http://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png",
|
||||
|
@ -65,6 +65,7 @@ This API is completely unstable and subject to change.
|
||||
|
||||
#![crate_name = "rustc_typeck"]
|
||||
#![experimental]
|
||||
#![staged_api]
|
||||
#![crate_type = "dylib"]
|
||||
#![crate_type = "rlib"]
|
||||
#![doc(html_logo_url = "http://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png",
|
||||
|
@ -11,6 +11,7 @@ pub use self::MaybeTyped::*;
|
||||
|
||||
use rustc_driver::driver;
|
||||
use rustc::session::{self, config};
|
||||
use rustc::session::config::UnstableFeatures;
|
||||
use rustc::session::search_paths::SearchPaths;
|
||||
use rustc::middle::{privacy, ty};
|
||||
use rustc::lint;
|
||||
@ -95,10 +96,11 @@ pub fn run_core(search_paths: SearchPaths, cfgs: Vec<String>, externs: Externs,
|
||||
externs: externs,
|
||||
target_triple: triple.unwrap_or(config::host_triple().to_string()),
|
||||
cfg: config::parse_cfgspecs(cfgs),
|
||||
// Ensure that rustdoc works even if rustc is feature-staged
|
||||
unstable_features: UnstableFeatures::Default,
|
||||
..config::basic_options().clone()
|
||||
};
|
||||
|
||||
|
||||
let codemap = codemap::CodeMap::new();
|
||||
let diagnostic_handler = diagnostic::default_handler(diagnostic::Auto, None);
|
||||
let span_diagnostic_handler =
|
||||
|
@ -10,6 +10,7 @@
|
||||
|
||||
#![crate_name = "rustdoc"]
|
||||
#![experimental]
|
||||
#![staged_api]
|
||||
#![crate_type = "dylib"]
|
||||
#![crate_type = "rlib"]
|
||||
#![doc(html_logo_url = "http://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png",
|
||||
|
@ -22,6 +22,7 @@ use std::collections::{HashSet, HashMap};
|
||||
use testing;
|
||||
use rustc::session::{self, config};
|
||||
use rustc::session::search_paths::{SearchPaths, PathKind};
|
||||
use rustc_driver::get_unstable_features_setting;
|
||||
use rustc_driver::driver;
|
||||
use syntax::ast;
|
||||
use syntax::codemap::{CodeMap, dummy_spanned};
|
||||
@ -52,6 +53,7 @@ pub fn run(input: &str,
|
||||
search_paths: libs.clone(),
|
||||
crate_types: vec!(config::CrateTypeDylib),
|
||||
externs: externs.clone(),
|
||||
unstable_features: get_unstable_features_setting(),
|
||||
..config::basic_options().clone()
|
||||
};
|
||||
|
||||
@ -128,6 +130,7 @@ fn runtest(test: &str, cratename: &str, libs: SearchPaths,
|
||||
.. config::basic_codegen_options()
|
||||
},
|
||||
test: as_test_harness,
|
||||
unstable_features: get_unstable_features_setting(),
|
||||
..config::basic_options().clone()
|
||||
};
|
||||
|
||||
|
@ -16,6 +16,7 @@ Core encoding and decoding interfaces.
|
||||
|
||||
#![crate_name = "serialize"]
|
||||
#![unstable = "deprecated in favor of rustc-serialize on crates.io"]
|
||||
#![staged_api]
|
||||
#![crate_type = "rlib"]
|
||||
#![crate_type = "dylib"]
|
||||
#![doc(html_logo_url = "http://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png",
|
||||
|
@ -96,6 +96,7 @@
|
||||
|
||||
#![crate_name = "std"]
|
||||
#![stable]
|
||||
#![staged_api]
|
||||
#![crate_type = "rlib"]
|
||||
#![crate_type = "dylib"]
|
||||
#![doc(html_logo_url = "http://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png",
|
||||
|
@ -590,7 +590,12 @@ impl CodeMap {
|
||||
Some(ref info) => {
|
||||
// save the parent expn_id for next loop iteration
|
||||
expnid = info.call_site.expn_id;
|
||||
if info.callee.span.is_none() {
|
||||
if info.callee.name == "format_args" {
|
||||
// This is a hack because the format_args builtin calls unstable APIs.
|
||||
// I spent like 6 hours trying to solve this more generally but am stupid.
|
||||
is_internal = true;
|
||||
false
|
||||
} else if info.callee.span.is_none() {
|
||||
// it's a compiler built-in, we *really* don't want to mess with it
|
||||
// so we skip it, unless it was called by a regular macro, in which case
|
||||
// we will handle the caller macro next turn
|
||||
|
@ -16,6 +16,7 @@
|
||||
|
||||
#![crate_name = "syntax"]
|
||||
#![experimental]
|
||||
#![staged_api]
|
||||
#![crate_type = "dylib"]
|
||||
#![crate_type = "rlib"]
|
||||
#![doc(html_logo_url = "http://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png",
|
||||
|
@ -48,7 +48,7 @@ fn no_prelude(attrs: &[ast::Attribute]) -> bool {
|
||||
}
|
||||
|
||||
struct StandardLibraryInjector<'a> {
|
||||
alt_std_name: Option<String>,
|
||||
alt_std_name: Option<String>
|
||||
}
|
||||
|
||||
impl<'a> fold::Folder for StandardLibraryInjector<'a> {
|
||||
@ -84,14 +84,13 @@ impl<'a> fold::Folder for StandardLibraryInjector<'a> {
|
||||
|
||||
fn inject_crates_ref(krate: ast::Crate, alt_std_name: Option<String>) -> ast::Crate {
|
||||
let mut fold = StandardLibraryInjector {
|
||||
alt_std_name: alt_std_name,
|
||||
alt_std_name: alt_std_name
|
||||
};
|
||||
fold.fold_crate(krate)
|
||||
}
|
||||
|
||||
struct PreludeInjector<'a>;
|
||||
|
||||
|
||||
impl<'a> fold::Folder for PreludeInjector<'a> {
|
||||
fn fold_crate(&mut self, mut krate: ast::Crate) -> ast::Crate {
|
||||
// Add #![no_std] here, so we don't re-inject when compiling pretty-printed source.
|
||||
@ -104,20 +103,10 @@ impl<'a> fold::Folder for PreludeInjector<'a> {
|
||||
attr::mark_used(&no_std_attr);
|
||||
krate.attrs.push(no_std_attr);
|
||||
|
||||
// only add `use std::prelude::*;` if there wasn't a
|
||||
// `#![no_implicit_prelude]` at the crate level.
|
||||
// fold_mod() will insert glob path.
|
||||
if !no_prelude(krate.attrs.index(&FullRange)) {
|
||||
// only add `use std::prelude::*;` if there wasn't a
|
||||
// `#![no_implicit_prelude]` at the crate level.
|
||||
// fold_mod() will insert glob path.
|
||||
let globs_attr = attr::mk_attr_inner(attr::mk_attr_id(),
|
||||
attr::mk_list_item(
|
||||
InternedString::new("feature"),
|
||||
vec!(
|
||||
attr::mk_word_item(InternedString::new("globs")),
|
||||
)));
|
||||
// std_inject runs after feature checking so manually mark this attr
|
||||
attr::mark_used(&globs_attr);
|
||||
krate.attrs.push(globs_attr);
|
||||
|
||||
krate.module = self.fold_mod(krate.module);
|
||||
}
|
||||
krate
|
||||
|
@ -40,6 +40,7 @@
|
||||
|
||||
#![crate_name = "term"]
|
||||
#![experimental = "use the crates.io `term` library instead"]
|
||||
#![staged_api]
|
||||
#![crate_type = "rlib"]
|
||||
#![crate_type = "dylib"]
|
||||
#![doc(html_logo_url = "http://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png",
|
||||
|
@ -25,6 +25,7 @@
|
||||
|
||||
#![crate_name = "test"]
|
||||
#![experimental]
|
||||
#![staged_api]
|
||||
#![crate_type = "rlib"]
|
||||
#![crate_type = "dylib"]
|
||||
#![doc(html_logo_url = "http://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png",
|
||||
|
@ -22,6 +22,7 @@
|
||||
|
||||
#![crate_name = "unicode"]
|
||||
#![experimental]
|
||||
#![staged_api]
|
||||
#![crate_type = "rlib"]
|
||||
#![doc(html_logo_url = "http://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png",
|
||||
html_favicon_url = "http://www.rust-lang.org/favicon.ico",
|
||||
|
14
src/test/compile-fail/feature-gate-feature-gate.rs
Normal file
14
src/test/compile-fail/feature-gate-feature-gate.rs
Normal file
@ -0,0 +1,14 @@
|
||||
// Copyright 2014 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.
|
||||
|
||||
#![forbid(unstable_features)]
|
||||
#![feature(intrinsics)] //~ ERROR unstable feature
|
||||
|
||||
fn main() { }
|
@ -8,6 +8,14 @@
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
// FIXME #20661: format_args! emits calls to the unstable std::fmt::rt
|
||||
// module, so the compiler has some hacks to make that possible
|
||||
// (in span_is_internal). Unnfortunately those hacks defeat this
|
||||
// particular scenario of checking feature gates in arguments to
|
||||
// println!().
|
||||
|
||||
// ignore-test
|
||||
|
||||
// tests that input to a macro is checked for use of gated features. If this
|
||||
// test succeeds due to the acceptance of a feature, pick a new feature to
|
||||
// test. Not ideal, but oh well :(
|
||||
|
@ -1,5 +1,4 @@
|
||||
#![no_std]
|
||||
#![feature(globs)]
|
||||
#[macro_use]
|
||||
extern crate "std" as std;
|
||||
#[prelude_import]
|
||||
|
Loading…
Reference in New Issue
Block a user