about summary refs log tree commit diff
diff options
context:
space:
mode:
authorBrian Anderson <banderson@mozilla.com>2015-01-14 15:20:14 -0800
committerBrian Anderson <banderson@mozilla.com>2015-01-21 16:16:21 -0800
commit7b73ec469878e428c789b77320b3f8dc8d974d22 (patch)
tree297c1f66334f03df5b0da3f2ea37bfb00a63453e
parent94ca8a361026d1a622a961e8dc8cacc331ed1ac3 (diff)
downloadrust-7b73ec469878e428c789b77320b3f8dc8d974d22.tar.gz
rust-7b73ec469878e428c789b77320b3f8dc8d974d22.zip
Tie stability attributes to feature gates
-rw-r--r--src/compiletest/compiletest.rs2
-rw-r--r--src/driver/driver.rs3
-rw-r--r--src/liballoc/arc.rs1
-rw-r--r--src/liballoc/lib.rs2
-rw-r--r--src/liballoc/rc.rs1
-rw-r--r--src/libarena/lib.rs2
-rw-r--r--src/libcollections/lib.rs2
-rw-r--r--src/libcore/simd.rs1
-rw-r--r--src/libcore/slice.rs1
-rw-r--r--src/libcoretest/lib.rs2
-rw-r--r--src/libflate/lib.rs2
-rw-r--r--src/libfmt_macros/lib.rs2
-rw-r--r--src/libgetopts/lib.rs2
-rw-r--r--src/libgraphviz/lib.rs2
-rw-r--r--src/liblibc/lib.rs4
-rw-r--r--src/liblog/lib.rs2
-rw-r--r--src/librand/lib.rs2
-rw-r--r--src/librbml/lib.rs2
-rw-r--r--src/libregex/lib.rs2
-rw-r--r--src/libregex/re.rs1
-rw-r--r--src/librustc/lib.rs2
-rw-r--r--src/librustc/lint/builtin.rs117
-rw-r--r--src/librustc/lint/context.rs9
-rw-r--r--src/librustc/middle/stability.rs232
-rw-r--r--src/librustc_back/lib.rs2
-rw-r--r--src/librustc_borrowck/lib.rs2
-rw-r--r--src/librustc_driver/driver.rs23
-rw-r--r--src/librustc_driver/lib.rs2
-rw-r--r--src/librustc_llvm/lib.rs2
-rw-r--r--src/librustc_privacy/lib.rs2
-rw-r--r--src/librustc_resolve/lib.rs2
-rw-r--r--src/librustc_trans/lib.rs2
-rw-r--r--src/librustc_typeck/lib.rs2
-rw-r--r--src/librustdoc/lib.rs2
-rw-r--r--src/libserialize/lib.rs2
-rw-r--r--src/libstd/collections/hash/table.rs1
-rw-r--r--src/libstd/io/mod.rs1
-rw-r--r--src/libstd/io/net/tcp.rs3
-rw-r--r--src/libstd/io/net/udp.rs1
-rw-r--r--src/libstd/io/process.rs2
-rw-r--r--src/libstd/lib.rs2
-rw-r--r--src/libstd/thunk.rs1
-rw-r--r--src/libsyntax/feature_gate.rs32
-rw-r--r--src/libsyntax/lib.rs2
-rw-r--r--src/libterm/lib.rs2
-rw-r--r--src/libtest/lib.rs2
-rw-r--r--src/libunicode/lib.rs2
-rw-r--r--src/rustbook/main.rs2
-rw-r--r--src/test/bench/shootout-mandelbrot.rs1
-rw-r--r--src/test/compile-fail/lint-dead-code-1.rs1
-rw-r--r--src/test/compile-fail/lint-dead-code-3.rs1
-rw-r--r--src/test/compile-fail/lint-dead-code-4.rs1
-rw-r--r--src/test/compile-fail/lint-exceeding-bitshifts.rs1
-rw-r--r--src/test/compile-fail/lint-uppercase-variables.rs1
-rw-r--r--src/test/compile-fail/liveness-unused.rs1
-rw-r--r--src/test/compile-fail/simd-binop.rs1
-rw-r--r--src/test/debuginfo/simd.rs1
-rw-r--r--src/test/run-pass/associated-types-normalize-unifield-struct.rs1
-rw-r--r--src/test/run-pass/ifmt.rs1
-rw-r--r--src/test/run-pass/issue-11958.rs1
-rw-r--r--src/test/run-pass/issue-16671.rs1
-rw-r--r--src/test/run-pass/issue-21058.rs1
-rw-r--r--src/test/run-pass/simd-binop.rs1
-rw-r--r--src/test/run-pass/simd-issue-10604.rs1
-rw-r--r--src/test/run-pass/tcp-connect-timeouts.rs1
65 files changed, 299 insertions, 212 deletions
diff --git a/src/compiletest/compiletest.rs b/src/compiletest/compiletest.rs
index f3514c6e7bc..b23c867d5c9 100644
--- a/src/compiletest/compiletest.rs
+++ b/src/compiletest/compiletest.rs
@@ -13,7 +13,7 @@
 #![feature(slicing_syntax, unboxed_closures)]
 #![feature(box_syntax)]
 #![feature(int_uint)]
-#![allow(unstable)]
+#![feature(unnamed_feature)]
 
 #![deny(warnings)]
 
diff --git a/src/driver/driver.rs b/src/driver/driver.rs
index 5f086280a65..6e436ec41d5 100644
--- a/src/driver/driver.rs
+++ b/src/driver/driver.rs
@@ -8,7 +8,8 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-#![allow(unstable)]
+#![allow(unknown_features)]
+#![feature(unnamed_feature)]
 
 #[cfg(rustdoc)]
 extern crate "rustdoc" as this;
diff --git a/src/liballoc/arc.rs b/src/liballoc/arc.rs
index 34322f7950c..9245d33047c 100644
--- a/src/liballoc/arc.rs
+++ b/src/liballoc/arc.rs
@@ -608,7 +608,6 @@ impl<H: Hasher, T: Hash<H>> Hash<H> for Arc<T> {
 }
 
 #[cfg(test)]
-#[allow(unstable)]
 mod tests {
     use std::clone::Clone;
     use std::sync::mpsc::channel;
diff --git a/src/liballoc/lib.rs b/src/liballoc/lib.rs
index 84527893374..b8c9c8403c3 100644
--- a/src/liballoc/lib.rs
+++ b/src/liballoc/lib.rs
@@ -66,10 +66,10 @@
 
 #![no_std]
 #![allow(unknown_features)]
-#![allow(unstable)]
 #![feature(lang_items, unsafe_destructor)]
 #![feature(box_syntax)]
 #![feature(optin_builtin_traits)]
+#![feature(unnamed_feature)]
 #![allow(unknown_features)] #![feature(int_uint)]
 
 #[macro_use]
diff --git a/src/liballoc/rc.rs b/src/liballoc/rc.rs
index 0b8c518a3a5..5e828106739 100644
--- a/src/liballoc/rc.rs
+++ b/src/liballoc/rc.rs
@@ -937,7 +937,6 @@ impl<T> RcBoxPtr<T> for Weak<T> {
 }
 
 #[cfg(test)]
-#[allow(unstable)]
 mod tests {
     use super::{Rc, Weak, weak_count, strong_count};
     use std::cell::RefCell;
diff --git a/src/libarena/lib.rs b/src/libarena/lib.rs
index 633e2bf57b6..feb70e48562 100644
--- a/src/libarena/lib.rs
+++ b/src/libarena/lib.rs
@@ -32,9 +32,9 @@
 #![feature(unsafe_destructor)]
 #![feature(unboxed_closures)]
 #![feature(box_syntax)]
+#![feature(unnamed_feature)]
 #![allow(unknown_features)] #![feature(int_uint)]
 #![allow(missing_docs)]
-#![allow(unstable)]
 
 extern crate alloc;
 
diff --git a/src/libcollections/lib.rs b/src/libcollections/lib.rs
index 9663adfb39d..b99019f921e 100644
--- a/src/libcollections/lib.rs
+++ b/src/libcollections/lib.rs
@@ -26,8 +26,8 @@
 #![feature(unsafe_destructor, slicing_syntax)]
 #![feature(box_syntax)]
 #![feature(unboxed_closures)]
+#![feature(unnamed_feature)]
 #![allow(unknown_features)] #![feature(int_uint)]
-#![allow(unstable)]
 #![no_std]
 
 #[macro_use]
diff --git a/src/libcore/simd.rs b/src/libcore/simd.rs
index 01082516793..8a229ac08ec 100644
--- a/src/libcore/simd.rs
+++ b/src/libcore/simd.rs
@@ -19,7 +19,6 @@
 //! provided beyond this module.
 //!
 //! ```rust
-//! #[allow(unstable)];
 //!
 //! fn main() {
 //!     use std::simd::f32x4;
diff --git a/src/libcore/slice.rs b/src/libcore/slice.rs
index 99949ff1384..1c7478ddb76 100644
--- a/src/libcore/slice.rs
+++ b/src/libcore/slice.rs
@@ -1433,7 +1433,6 @@ pub mod bytes {
 
     impl MutableByteVector for [u8] {
         #[inline]
-        #[allow(unstable)]
         fn set_memory(&mut self, value: u8) {
             unsafe { ptr::set_memory(self.as_mut_ptr(), value, self.len()) };
         }
diff --git a/src/libcoretest/lib.rs b/src/libcoretest/lib.rs
index 0c7b72612fa..1aa302aa8ed 100644
--- a/src/libcoretest/lib.rs
+++ b/src/libcoretest/lib.rs
@@ -11,8 +11,8 @@
 #![feature(unsafe_destructor, slicing_syntax)]
 #![feature(unboxed_closures)]
 #![feature(box_syntax)]
+#![feature(unnamed_feature)]
 #![allow(unknown_features)] #![feature(int_uint)]
-#![allow(unstable)]
 
 extern crate core;
 extern crate test;
diff --git a/src/libflate/lib.rs b/src/libflate/lib.rs
index 4a23eb65268..a5033a701bf 100644
--- a/src/libflate/lib.rs
+++ b/src/libflate/lib.rs
@@ -18,7 +18,7 @@
 #![unstable(feature = "unnamed_feature", since = "1.0.0")]
 #![staged_api]
 #![allow(unknown_features)] #![feature(int_uint)]
-#![allow(unstable)]
+#![feature(unnamed_feature)]
 #![crate_type = "rlib"]
 #![crate_type = "dylib"]
 #![doc(html_logo_url = "http://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png",
diff --git a/src/libfmt_macros/lib.rs b/src/libfmt_macros/lib.rs
index 3a52ead26b5..282ff7c29ac 100644
--- a/src/libfmt_macros/lib.rs
+++ b/src/libfmt_macros/lib.rs
@@ -26,7 +26,7 @@
 
 #![feature(slicing_syntax)]
 #![allow(unknown_features)] #![feature(int_uint)]
-#![allow(unstable)]
+#![feature(unnamed_feature)]
 
 pub use self::Piece::*;
 pub use self::Position::*;
diff --git a/src/libgetopts/lib.rs b/src/libgetopts/lib.rs
index 1f069b5c94c..829c89a6c66 100644
--- a/src/libgetopts/lib.rs
+++ b/src/libgetopts/lib.rs
@@ -88,8 +88,8 @@
        html_root_url = "http://doc.rust-lang.org/nightly/",
        html_playground_url = "http://play.rust-lang.org/")]
 #![feature(slicing_syntax)]
+#![feature(unnamed_feature)]
 #![allow(unknown_features)] #![feature(int_uint)]
-#![allow(unstable)]
 #![deny(missing_docs)]
 
 #[cfg(test)] #[macro_use] extern crate log;
diff --git a/src/libgraphviz/lib.rs b/src/libgraphviz/lib.rs
index cff042271b1..300500df478 100644
--- a/src/libgraphviz/lib.rs
+++ b/src/libgraphviz/lib.rs
@@ -273,8 +273,8 @@
        html_favicon_url = "http://www.rust-lang.org/favicon.ico",
        html_root_url = "http://doc.rust-lang.org/nightly/")]
 #![feature(slicing_syntax)]
+#![feature(unnamed_feature)]
 #![allow(unknown_features)] #![feature(int_uint)]
-#![allow(unstable)]
 
 use self::LabelText::*;
 
diff --git a/src/liblibc/lib.rs b/src/liblibc/lib.rs
index fc90a1905a8..ebdf9c95705 100644
--- a/src/liblibc/lib.rs
+++ b/src/liblibc/lib.rs
@@ -13,8 +13,8 @@
 #![cfg_attr(not(feature = "cargo-build"),
             unstable(feature = "unnamed_feature", since = "1.0.0"))]
 #![cfg_attr(not(feature = "cargo-build"), staged_api)]
+#![cfg_attr(not(feature = "cargo-build"), feature(unnamed_feature))]
 #![allow(unknown_features)] #![feature(int_uint)]
-#![allow(unstable)]
 #![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",
@@ -74,7 +74,7 @@
 //! one from Berkeley after the lawsuits died down and the CSRG dissolved.
 
 #![allow(bad_style, raw_pointer_derive)]
-
+#![cfg_attr(not(feature = "cargo-build"), feature(unnamed_feature))]
 #[cfg(feature = "cargo-build")] extern crate "std" as core;
 #[cfg(not(feature = "cargo-build"))] extern crate core;
 
diff --git a/src/liblog/lib.rs b/src/liblog/lib.rs
index 872d46c4324..f1f106c73f6 100644
--- a/src/liblog/lib.rs
+++ b/src/liblog/lib.rs
@@ -169,8 +169,8 @@
 #![allow(unknown_features)]
 #![feature(slicing_syntax)]
 #![feature(box_syntax)]
+#![feature(unnamed_feature)]
 #![allow(unknown_features)] #![feature(int_uint)]
-#![allow(unstable)]
 #![deny(missing_docs)]
 
 extern crate regex;
diff --git a/src/librand/lib.rs b/src/librand/lib.rs
index e8a1cb2a18d..b39fb3e9fb8 100644
--- a/src/librand/lib.rs
+++ b/src/librand/lib.rs
@@ -22,8 +22,8 @@
        html_favicon_url = "http://www.rust-lang.org/favicon.ico",
        html_root_url = "http://doc.rust-lang.org/nightly/",
        html_playground_url = "http://play.rust-lang.org/")]
+#![feature(unnamed_feature)]
 #![allow(unknown_features)] #![feature(int_uint)]
-#![allow(unstable)]
 #![no_std]
 #![unstable(feature = "unnamed_feature", since = "1.0.0")]
 #![staged_api]
diff --git a/src/librbml/lib.rs b/src/librbml/lib.rs
index 2eedc0d8f8f..60ad6a04d4b 100644
--- a/src/librbml/lib.rs
+++ b/src/librbml/lib.rs
@@ -26,8 +26,8 @@
        html_playground_url = "http://play.rust-lang.org/")]
 #![allow(unknown_features)]
 #![feature(slicing_syntax)]
+#![feature(unnamed_feature)]
 #![allow(unknown_features)] #![feature(int_uint)]
-#![allow(unstable)]
 
 extern crate serialize;
 #[macro_use] extern crate log;
diff --git a/src/libregex/lib.rs b/src/libregex/lib.rs
index 0b7ebc90bec..c575f9a849e 100644
--- a/src/libregex/lib.rs
+++ b/src/libregex/lib.rs
@@ -25,9 +25,9 @@
        html_playground_url = "http://play.rust-lang.org/")]
 
 #![allow(unknown_features)]
-#![allow(unstable)]
 #![feature(slicing_syntax)]
 #![feature(box_syntax)]
+#![feature(unnamed_feature)]
 #![allow(unknown_features)] #![feature(int_uint)]
 #![deny(missing_docs)]
 
diff --git a/src/libregex/re.rs b/src/libregex/re.rs
index 86329e365f5..98d072bb954 100644
--- a/src/libregex/re.rs
+++ b/src/libregex/re.rs
@@ -410,7 +410,6 @@ pub struct Captures<'t> {
 }
 
 impl<'t> Captures<'t> {
-    #[allow(unstable)]
     fn new(re: &Regex, search: &'t str, locs: CaptureLocs)
           -> Option<Captures<'t>> {
         if !has_match(&locs) {
diff --git a/src/librustc/lib.rs b/src/librustc/lib.rs
index ffde6495717..e37a2c91bca 100644
--- a/src/librustc/lib.rs
+++ b/src/librustc/lib.rs
@@ -27,9 +27,9 @@
 #![feature(quote)]
 #![feature(slicing_syntax, unsafe_destructor)]
 #![feature(box_syntax)]
+#![feature(unnamed_feature)]
 #![allow(unknown_features)] #![feature(int_uint)]
 #![feature(rustc_diagnostic_macros)]
-#![allow(unstable)]
 
 extern crate arena;
 extern crate flate;
diff --git a/src/librustc/lint/builtin.rs b/src/librustc/lint/builtin.rs
index 23eda47303e..2d3e5a4604e 100644
--- a/src/librustc/lint/builtin.rs
+++ b/src/librustc/lint/builtin.rs
@@ -44,7 +44,7 @@ use std::{i8, i16, i32, i64, u8, u16, u32, u64, f32, f64};
 use syntax::{abi, ast, ast_map};
 use syntax::ast_util::is_shift_binop;
 use syntax::attr::{self, AttrMetaMethods};
-use syntax::codemap::{Span, DUMMY_SP};
+use syntax::codemap::Span;
 use syntax::parse::token;
 use syntax::ast::{TyIs, TyUs, TyI8, TyU8, TyI16, TyU16, TyI32, TyU32, TyI64, TyU64};
 use syntax::ast_util;
@@ -1628,32 +1628,15 @@ declare_lint! {
     "detects use of #[deprecated] items"
 }
 
-declare_lint! {
-    UNSTABLE,
-    Warn,
-    "detects use of #[unstable] items (incl. items with no stability attribute)"
-}
-
-/// Checks for use of items with `#[deprecated]`, `#[unstable]` and
-/// `#[unstable]` attributes, or no stability attribute.
+/// Checks for use of items with `#[deprecated]` attributes
 #[derive(Copy)]
 pub struct Stability;
 
 impl Stability {
-    fn lint(&self, cx: &Context, id: ast::DefId, span: Span) {
-
-        if !stability::is_staged_api(cx.tcx, id) { return  }
+    fn lint(&self, cx: &Context, _id: ast::DefId, span: Span, stability: &Option<attr::Stability>) {
 
-        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.
+        // deprecated attributes apply in-crate and cross-crate
         let (lint, label) = match *stability {
-            // no stability attributes == Unstable
-            None if cross_crate => (UNSTABLE, "unmarked"),
-            Some(attr::Stability { level: attr::Unstable, .. }) if cross_crate =>
-                (UNSTABLE, "unstable"),
             Some(attr::Stability { level: attr::Deprecated, .. }) =>
                 (DEPRECATED, "deprecated"),
             _ => return
@@ -1673,100 +1656,26 @@ impl Stability {
             cx.span_lint(lint, span, &msg[]);
         }
     }
-
-
-    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, UNSTABLE)
+        lint_array!(DEPRECATED)
     }
 
     fn check_view_item(&mut self, cx: &Context, item: &ast::ViewItem) {
-        // compiler-generated `extern crate` statements have a dummy span.
-        if item.span == DUMMY_SP { return }
-
-        let id = match item.node {
-            ast::ViewItemExternCrate(_, _, id) => id,
-            ast::ViewItemUse(..) => return,
-        };
-        let cnum = match cx.tcx.sess.cstore.find_extern_mod_stmt_cnum(id) {
-            Some(cnum) => cnum,
-            None => return,
-        };
-        let id = ast::DefId { krate: cnum, node: ast::CRATE_NODE_ID };
-        self.lint(cx, id, item.span);
-    }
-
-    fn check_expr(&mut self, cx: &Context, e: &ast::Expr) {
-        if self.is_internal(cx, e.span) { return; }
-
-        let mut span = e.span;
-
-        let id = match e.node {
-            ast::ExprPath(..) | ast::ExprQPath(..) | ast::ExprStruct(..) => {
-                match cx.tcx.def_map.borrow().get(&e.id) {
-                    Some(&def) => def.def_id(),
-                    None => return
-                }
-            }
-            ast::ExprMethodCall(i, _, _) => {
-                span = i.span;
-                let method_call = ty::MethodCall::expr(e.id);
-                match cx.tcx.method_map.borrow().get(&method_call) {
-                    Some(method) => {
-                        match method.origin {
-                            ty::MethodStatic(def_id) => {
-                                def_id
-                            }
-                            ty::MethodStaticUnboxedClosure(def_id) => {
-                                def_id
-                            }
-                            ty::MethodTypeParam(ty::MethodParam {
-                                ref trait_ref,
-                                method_num: index,
-                                ..
-                            }) |
-                            ty::MethodTraitObject(ty::MethodObject {
-                                ref trait_ref,
-                                method_num: index,
-                                ..
-                            }) => {
-                                ty::trait_item(cx.tcx, trait_ref.def_id, index).def_id()
-                            }
-                        }
-                    }
-                    None => return
-                }
-            }
-            _ => return
-        };
-
-        self.lint(cx, id, span);
+        stability::check_view_item(cx.tcx, item,
+                                   &mut |id, sp, stab| self.lint(cx, id, sp, stab));
     }
 
     fn check_item(&mut self, cx: &Context, item: &ast::Item) {
-        if self.is_internal(cx, item.span) { return }
+        stability::check_item(cx.tcx, item,
+                              &mut |id, sp, stab| self.lint(cx, id, sp, stab));
+    }
 
-        match item.node {
-            ast::ItemTrait(_, _, ref supertraits, _) => {
-                for t in supertraits.iter() {
-                    if let ast::TraitTyParamBound(ref t, _) = *t {
-                        let id = ty::trait_ref_to_def_id(cx.tcx, &t.trait_ref);
-                        self.lint(cx, id, t.trait_ref.path.span);
-                    }
-                }
-            }
-            ast::ItemImpl(_, _, _, Some(ref t), _, _) => {
-                let id = ty::trait_ref_to_def_id(cx.tcx, t);
-                self.lint(cx, id, t.path.span);
-            }
-            _ => (/* pass */)
-        }
+    fn check_expr(&mut self, cx: &Context, e: &ast::Expr) {
+        stability::check_expr(cx.tcx, e,
+                              &mut |id, sp, stab| self.lint(cx, id, sp, stab));
     }
 }
 
diff --git a/src/librustc/lint/context.rs b/src/librustc/lint/context.rs
index 17d4e059509..1d27352a6e3 100644
--- a/src/librustc/lint/context.rs
+++ b/src/librustc/lint/context.rs
@@ -316,15 +316,6 @@ impl LintStore {
             },
             None => unreachable!()
         }
-        match self.by_name.get("unstable") {
-            Some(&Id(lint_id)) => if self.get_level_source(lint_id).0 != Forbid {
-                self.set_level(lint_id, (lvl, ReleaseChannel))
-            },
-            Some(&Renamed(_, lint_id)) => if self.get_level_source(lint_id).0 != Forbid {
-                self.set_level(lint_id, (lvl, ReleaseChannel))
-            },
-            None => unreachable!()
-        }
     }
 }
 
diff --git a/src/librustc/middle/stability.rs b/src/librustc/middle/stability.rs
index 9f12d849e74..4d69be7cbc2 100644
--- a/src/librustc/middle/stability.rs
+++ b/src/librustc/middle/stability.rs
@@ -14,7 +14,8 @@
 use session::Session;
 use middle::ty;
 use metadata::csearch;
-use syntax::codemap::Span;
+use syntax::parse::token::InternedString;
+use syntax::codemap::{Span, DUMMY_SP};
 use syntax::{attr, visit};
 use syntax::ast;
 use syntax::ast::{Attribute, Block, Crate, DefId, FnDecl, NodeId, Variant};
@@ -23,7 +24,8 @@ use syntax::ast::{TypeMethod, Method, Generics, StructField, TypeTraitItem};
 use syntax::ast_util::is_local;
 use syntax::attr::{Stability, AttrMetaMethods};
 use syntax::visit::{FnKind, FkMethod, Visitor};
-use util::nodemap::{NodeMap, DefIdMap};
+use syntax::feature_gate::emit_feature_err;
+use util::nodemap::{NodeMap, DefIdMap, FnvHashSet};
 use util::ppaux::Repr;
 
 use std::mem::replace;
@@ -174,6 +176,207 @@ impl Index {
     }
 }
 
+/// Cross-references the feature names of unstable APIs with enabled
+/// features and possibly prints errors. Returns a list of all
+/// features used.
+pub fn check_unstable_api_usage(tcx: &ty::ctxt) -> FnvHashSet<InternedString> {
+    let ref active_lib_features = tcx.sess.features.borrow().lib_features;
+
+    // Put the active features into a map for quick lookup
+    let active_features = active_lib_features.iter().map(|&(ref s, _)| s.clone()).collect();
+
+    let mut checker = Checker {
+        tcx: tcx,
+        active_features: active_features,
+        used_features: FnvHashSet()
+    };
+
+    let krate = tcx.map.krate();
+    visit::walk_crate(&mut checker, krate);
+
+    let used_features = checker.used_features;
+    return used_features;
+}
+
+struct Checker<'a, 'tcx: 'a> {
+    tcx: &'a ty::ctxt<'tcx>,
+    active_features: FnvHashSet<InternedString>,
+    used_features: FnvHashSet<InternedString>
+}
+
+impl<'a, 'tcx> Checker<'a, 'tcx> {
+    fn check(&mut self, id: ast::DefId, span: Span, stab: &Option<Stability>) {
+        // Only the cross-crate scenario matters when checking unstable APIs
+        let cross_crate = !is_local(id);
+        if !cross_crate { return }
+
+        match *stab {
+            Some(Stability { level: attr::Unstable, ref feature, ref reason, .. }) => {
+                self.used_features.insert(feature.clone());
+
+                if !self.active_features.contains(feature) {
+                    let msg = match *reason {
+                        Some(ref r) => format!("use of unstable library feature '{}': {}",
+                                               feature.get(), r.get()),
+                        None => format!("use of unstable library feature '{}'", feature.get())
+                    };
+
+                    emit_feature_err(&self.tcx.sess.parse_sess.span_diagnostic,
+                                     feature.get(), span, &msg[]);
+                }
+            }
+            Some(..) => {
+                // Stable APIs are always ok to call and deprecated APIs are
+                // handled by a lint.
+            }
+            None => {
+                // This is an 'unmarked' API, which should not exist
+                // in the standard library.
+                self.tcx.sess.span_err(span, "use of unmarked staged library feature");
+                self.tcx.sess.span_note(span, "this is either a bug in the library you are \
+                                               using or a bug in the compiler - there is \
+                                               no way to use this feature");
+            }
+        }
+    }
+}
+
+impl<'a, 'v, 'tcx> Visitor<'v> for Checker<'a, 'tcx> {
+    fn visit_view_item(&mut self, item: &ast::ViewItem) {
+        check_view_item(self.tcx, item,
+                        &mut |id, sp, stab| self.check(id, sp, stab));
+        visit::walk_view_item(self, item)
+    }
+
+    fn visit_item(&mut self, item: &ast::Item) {
+        check_item(self.tcx, item,
+                   &mut |id, sp, stab| self.check(id, sp, stab));
+        visit::walk_item(self, item);
+    }
+
+    fn visit_expr(&mut self, ex: &ast::Expr) {
+        check_expr(self.tcx, ex,
+                   &mut |id, sp, stab| self.check(id, sp, stab));
+        visit::walk_expr(self, ex);
+    }
+}
+
+/// Helper for discovering nodes to check for stability
+pub fn check_view_item(tcx: &ty::ctxt, item: &ast::ViewItem,
+                       cb: &mut FnMut(ast::DefId, Span, &Option<Stability>)) {
+    // compiler-generated `extern crate` statements have a dummy span.
+    if item.span == DUMMY_SP { return }
+
+    let id = match item.node {
+        ast::ViewItemExternCrate(_, _, id) => id,
+        ast::ViewItemUse(..) => return,
+    };
+    let cnum = match tcx.sess.cstore.find_extern_mod_stmt_cnum(id) {
+        Some(cnum) => cnum,
+        None => return,
+    };
+    let id = ast::DefId { krate: cnum, node: ast::CRATE_NODE_ID };
+
+    maybe_do_stability_check(tcx, id, item.span, cb);
+}
+
+/// Helper for discovering nodes to check for stability
+pub fn check_expr(tcx: &ty::ctxt, e: &ast::Expr,
+                  cb: &mut FnMut(ast::DefId, Span, &Option<Stability>)) {
+    if is_internal(tcx, e.span) { return; }
+
+    let mut span = e.span;
+
+    let id = match e.node {
+        ast::ExprPath(..) | ast::ExprQPath(..) | ast::ExprStruct(..) => {
+            match tcx.def_map.borrow().get(&e.id) {
+                Some(&def) => def.def_id(),
+                None => return
+            }
+        }
+        ast::ExprMethodCall(i, _, _) => {
+            span = i.span;
+            let method_call = ty::MethodCall::expr(e.id);
+            match tcx.method_map.borrow().get(&method_call) {
+                Some(method) => {
+                    match method.origin {
+                        ty::MethodStatic(def_id) => {
+                            def_id
+                        }
+                        ty::MethodStaticUnboxedClosure(def_id) => {
+                            def_id
+                        }
+                        ty::MethodTypeParam(ty::MethodParam {
+                            ref trait_ref,
+                            method_num: index,
+                            ..
+                        }) |
+                        ty::MethodTraitObject(ty::MethodObject {
+                            ref trait_ref,
+                            method_num: index,
+                            ..
+                        }) => {
+                            ty::trait_item(tcx, trait_ref.def_id, index).def_id()
+                        }
+                    }
+                }
+                None => return
+            }
+        }
+        _ => return
+    };
+
+    maybe_do_stability_check(tcx, id, span, cb);
+}
+
+/// Helper for discovering nodes to check for stability
+pub fn check_item(tcx: &ty::ctxt, item: &ast::Item,
+                  cb: &mut FnMut(ast::DefId, Span, &Option<Stability>)) {
+    if is_internal(tcx, item.span) { return }
+
+    match item.node {
+        ast::ItemTrait(_, _, ref supertraits, _) => {
+            for t in supertraits.iter() {
+                if let ast::TraitTyParamBound(ref t, _) = *t {
+                    let id = ty::trait_ref_to_def_id(tcx, &t.trait_ref);
+                    maybe_do_stability_check(tcx, id, t.trait_ref.path.span, cb);
+                }
+            }
+        }
+        ast::ItemImpl(_, _, _, Some(ref t), _, _) => {
+            let id = ty::trait_ref_to_def_id(tcx, t);
+            maybe_do_stability_check(tcx, id, t.path.span, cb);
+        }
+        _ => (/* pass */)
+    }
+}
+
+fn maybe_do_stability_check(tcx: &ty::ctxt, id: ast::DefId, span: Span,
+                            cb: &mut FnMut(ast::DefId, Span, &Option<Stability>)) {
+    if !is_staged_api(tcx, id) { return  }
+    let ref stability = lookup(tcx, id);
+    cb(id, span, stability);
+}
+
+fn is_internal(tcx: &ty::ctxt, span: Span) -> bool {
+    tcx.sess.codemap().span_is_internal(span)
+}
+
+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) => {
+            tcx.stability.borrow().staged_api
+        }
+        _ => {
+            csearch::is_staged_api(&tcx.sess.cstore, id)
+        }
+    }
+}
+
 /// Lookup the stability for a node, loading external crate
 /// metadata as necessary.
 pub fn lookup(tcx: &ty::ctxt, id: DefId) -> Option<Stability> {
@@ -212,17 +415,16 @@ 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) => {
-            tcx.stability.borrow().staged_api
-        }
-        _ => {
-            csearch::is_staged_api(&tcx.sess.cstore, id)
-        }
-    }
+/// Given the list of enabled features that were not language features (i.e. that
+/// were expected to be library features), and the list of features used from
+/// libraries, identify activated features that don't exist and error about them.
+pub fn check_unknown_features(sess: &Session,
+                              _used_lib_features: &FnvHashSet<InternedString>) {
+    let ref _lib_features = sess.features.borrow().lib_features;
+    // TODO
+
+    //sess.add_lint(lint::builtin::UNKNOWN_FEATURES,
+    //              ast::CRATE_NODE_ID,
+    //              *uf,
+    //              "unknown feature".to_string());
 }
diff --git a/src/librustc_back/lib.rs b/src/librustc_back/lib.rs
index 3e33dfcef5a..323aea893e4 100644
--- a/src/librustc_back/lib.rs
+++ b/src/librustc_back/lib.rs
@@ -31,8 +31,8 @@
       html_root_url = "http://doc.rust-lang.org/nightly/")]
 #![allow(unknown_features)]
 #![feature(slicing_syntax, box_syntax)]
+#![feature(unnamed_feature)]
 #![allow(unknown_features)] #![feature(int_uint)]
-#![allow(unstable)]
 
 extern crate syntax;
 extern crate serialize;
diff --git a/src/librustc_borrowck/lib.rs b/src/librustc_borrowck/lib.rs
index 4c7454bca7b..585aaf8968f 100644
--- a/src/librustc_borrowck/lib.rs
+++ b/src/librustc_borrowck/lib.rs
@@ -21,9 +21,9 @@
 #![feature(quote)]
 #![feature(slicing_syntax, unsafe_destructor)]
 #![feature(rustc_diagnostic_macros)]
+#![feature(unnamed_feature)]
 #![allow(unknown_features)] #![feature(int_uint)]
 #![allow(non_camel_case_types)]
-#![allow(unstable)]
 
 #[macro_use] extern crate log;
 #[macro_use] extern crate syntax;
diff --git a/src/librustc_driver/driver.rs b/src/librustc_driver/driver.rs
index 9c5756f8095..384f5af6819 100644
--- a/src/librustc_driver/driver.rs
+++ b/src/librustc_driver/driver.rs
@@ -390,16 +390,10 @@ pub fn phase_2_configure_and_expand(sess: &Session,
     // baz! should not use this definition unless foo is enabled.
 
     time(time_passes, "gated macro checking", (), |_| {
-        let (features, unknown_features) =
+        let features =
             syntax::feature_gate::check_crate_macros(sess.codemap(),
                                                      &sess.parse_sess.span_diagnostic,
                                                      &krate);
-        for uf in unknown_features.iter() {
-            sess.add_lint(lint::builtin::UNKNOWN_FEATURES,
-                          ast::CRATE_NODE_ID,
-                          *uf,
-                          "unknown feature".to_string());
-        }
 
         // these need to be set "early" so that expansion sees `quote` if enabled.
         *sess.features.borrow_mut() = features;
@@ -492,9 +486,11 @@ pub fn phase_2_configure_and_expand(sess: &Session,
 
     // Needs to go *after* expansion to be able to check the results of macro expansion.
     time(time_passes, "complete gated feature checking", (), |_| {
-        syntax::feature_gate::check_crate(sess.codemap(),
+        let features = 
+            syntax::feature_gate::check_crate(sess.codemap(),
                                           &sess.parse_sess.span_diagnostic,
                                           &krate);
+        *sess.features.borrow_mut() = features;
         sess.abort_if_errors();
     });
 
@@ -668,9 +664,20 @@ pub fn phase_3_run_analysis_passes<'tcx>(sess: Session,
                                   &reachable_map)
     });
 
+    let ref lib_features_used =
+        time(time_passes, "stability checking", (), |_|
+             stability::check_unstable_api_usage(&ty_cx));
+
+    time(time_passes, "unknown feature checking", (), |_|
+         stability::check_unknown_features(
+             &ty_cx.sess, lib_features_used));
+
     time(time_passes, "lint checking", (), |_|
          lint::check_crate(&ty_cx, &exported_items));
 
+    // Some of the above passes generate errors
+    ty_cx.sess.abort_if_errors();
+
     ty::CrateAnalysis {
         export_map: export_map,
         ty_cx: ty_cx,
diff --git a/src/librustc_driver/lib.rs b/src/librustc_driver/lib.rs
index e35bc807d28..a5fff5484f7 100644
--- a/src/librustc_driver/lib.rs
+++ b/src/librustc_driver/lib.rs
@@ -28,8 +28,8 @@
 #![feature(slicing_syntax, unsafe_destructor)]
 #![feature(box_syntax)]
 #![feature(rustc_diagnostic_macros)]
+#![feature(unnamed_feature)]
 #![allow(unknown_features)] #![feature(int_uint)]
-#![allow(unstable)]
 
 extern crate arena;
 extern crate flate;
diff --git a/src/librustc_llvm/lib.rs b/src/librustc_llvm/lib.rs
index 93568f73f9d..3a74e2d255e 100644
--- a/src/librustc_llvm/lib.rs
+++ b/src/librustc_llvm/lib.rs
@@ -25,8 +25,8 @@
 #![allow(unknown_features)]
 #![feature(link_args)]
 #![feature(box_syntax)]
+#![feature(unnamed_feature)]
 #![allow(unknown_features)] #![feature(int_uint)]
-#![allow(unstable)]
 
 extern crate libc;
 #[macro_use] #[no_link] extern crate rustc_bitflags;
diff --git a/src/librustc_privacy/lib.rs b/src/librustc_privacy/lib.rs
index 28841fc0076..bc2f69f62fb 100644
--- a/src/librustc_privacy/lib.rs
+++ b/src/librustc_privacy/lib.rs
@@ -18,8 +18,8 @@
       html_root_url = "http://doc.rust-lang.org/nightly/")]
 
 #![feature(rustc_diagnostic_macros)]
+#![feature(unnamed_feature)]
 #![allow(unknown_features)] #![feature(int_uint)]
-#![allow(unstable)]
 
 #[macro_use] extern crate log;
 #[macro_use] extern crate syntax;
diff --git a/src/librustc_resolve/lib.rs b/src/librustc_resolve/lib.rs
index 31a4cdfcae8..6f9907853b7 100644
--- a/src/librustc_resolve/lib.rs
+++ b/src/librustc_resolve/lib.rs
@@ -19,8 +19,8 @@
 
 #![feature(slicing_syntax)]
 #![feature(rustc_diagnostic_macros)]
+#![feature(unnamed_feature)]
 #![allow(unknown_features)] #![feature(int_uint)]
-#![allow(unstable)]
 
 #[macro_use] extern crate log;
 #[macro_use] extern crate syntax;
diff --git a/src/librustc_trans/lib.rs b/src/librustc_trans/lib.rs
index 4ee2cf92e3d..a92d85673d9 100644
--- a/src/librustc_trans/lib.rs
+++ b/src/librustc_trans/lib.rs
@@ -28,8 +28,8 @@
 #![feature(slicing_syntax, unsafe_destructor)]
 #![feature(box_syntax)]
 #![feature(rustc_diagnostic_macros)]
+#![feature(unnamed_feature)]
 #![allow(unknown_features)] #![feature(int_uint)]
-#![allow(unstable)]
 
 extern crate arena;
 extern crate flate;
diff --git a/src/librustc_typeck/lib.rs b/src/librustc_typeck/lib.rs
index 5022e301c2a..fa90ad88c19 100644
--- a/src/librustc_typeck/lib.rs
+++ b/src/librustc_typeck/lib.rs
@@ -77,9 +77,9 @@ This API is completely unstable and subject to change.
 #![feature(slicing_syntax, unsafe_destructor)]
 #![feature(box_syntax)]
 #![feature(rustc_diagnostic_macros)]
+#![feature(unnamed_feature)]
 #![allow(unknown_features)] #![feature(int_uint)]
 #![allow(non_camel_case_types)]
-#![allow(unstable)]
 
 #[macro_use] extern crate log;
 #[macro_use] extern crate syntax;
diff --git a/src/librustdoc/lib.rs b/src/librustdoc/lib.rs
index c362376620a..fa5110454a1 100644
--- a/src/librustdoc/lib.rs
+++ b/src/librustdoc/lib.rs
@@ -19,8 +19,8 @@
        html_playground_url = "http://play.rust-lang.org/")]
 #![feature(slicing_syntax)]
 #![feature(box_syntax)]
+#![feature(unnamed_feature)]
 #![allow(unknown_features)] #![feature(int_uint)]
-#![allow(unstable)]
 
 extern crate arena;
 extern crate getopts;
diff --git a/src/libserialize/lib.rs b/src/libserialize/lib.rs
index 1fd2b6b5d9a..b662ba638a7 100644
--- a/src/libserialize/lib.rs
+++ b/src/libserialize/lib.rs
@@ -28,8 +28,8 @@ Core encoding and decoding interfaces.
 #![feature(box_syntax)]
 #![feature(old_impl_check)]
 #![feature(slicing_syntax)]
+#![feature(unnamed_feature)]
 #![allow(unknown_features)] #![feature(int_uint)]
-#![allow(unstable)]
 
 // test harness access
 #[cfg(test)] extern crate test;
diff --git a/src/libstd/collections/hash/table.rs b/src/libstd/collections/hash/table.rs
index d810460a7d4..9e6a45d8bf0 100644
--- a/src/libstd/collections/hash/table.rs
+++ b/src/libstd/collections/hash/table.rs
@@ -629,7 +629,6 @@ impl<K, V> RawTable<K, V> {
 
     /// Creates a new raw table from a given capacity. All buckets are
     /// initially empty.
-    #[allow(unstable)]
     pub fn new(capacity: uint) -> RawTable<K, V> {
         unsafe {
             let ret = RawTable::new_uninitialized(capacity);
diff --git a/src/libstd/io/mod.rs b/src/libstd/io/mod.rs
index f680f896238..012728be56a 100644
--- a/src/libstd/io/mod.rs
+++ b/src/libstd/io/mod.rs
@@ -1703,7 +1703,6 @@ pub enum FileType {
 /// # Examples
 ///
 /// ```no_run
-/// # #![allow(unstable)]
 ///
 /// use std::io::fs::PathExtensions;
 ///
diff --git a/src/libstd/io/net/tcp.rs b/src/libstd/io/net/tcp.rs
index 180deae6a25..88d74c5c288 100644
--- a/src/libstd/io/net/tcp.rs
+++ b/src/libstd/io/net/tcp.rs
@@ -376,7 +376,6 @@ impl TcpAcceptor {
     /// # Example
     ///
     /// ```no_run
-    /// # #![allow(unstable)]
     /// use std::io::TcpListener;
     /// use std::io::{Listener, Acceptor, TimedOut};
     ///
@@ -421,7 +420,6 @@ impl TcpAcceptor {
     /// # Example
     ///
     /// ```
-    /// # #![allow(unstable)]
     /// use std::io::{TcpListener, Listener, Acceptor, EndOfFile};
     /// use std::thread::Thread;
     ///
@@ -485,7 +483,6 @@ impl sys_common::AsInner<TcpAcceptorImp> for TcpAcceptor {
 }
 
 #[cfg(test)]
-#[allow(unstable)]
 mod test {
     use prelude::v1::*;
 
diff --git a/src/libstd/io/net/udp.rs b/src/libstd/io/net/udp.rs
index a3e4eca10bc..9920e002795 100644
--- a/src/libstd/io/net/udp.rs
+++ b/src/libstd/io/net/udp.rs
@@ -179,7 +179,6 @@ impl sys_common::AsInner<UdpSocketImp> for UdpSocket {
 }
 
 #[cfg(test)]
-#[allow(unstable)]
 mod test {
     use prelude::v1::*;
 
diff --git a/src/libstd/io/process.rs b/src/libstd/io/process.rs
index 4762719a04e..dc15eb1302f 100644
--- a/src/libstd/io/process.rs
+++ b/src/libstd/io/process.rs
@@ -10,7 +10,6 @@
 
 //! Bindings for executing child processes
 
-#![allow(unstable)]
 #![allow(non_upper_case_globals)]
 
 pub use self::StdioContainer::*;
@@ -663,7 +662,6 @@ impl Process {
     /// # Example
     ///
     /// ```no_run
-    /// # #![allow(unstable)]
     /// use std::io::{Command, IoResult};
     /// use std::io::process::ProcessExit;
     ///
diff --git a/src/libstd/lib.rs b/src/libstd/lib.rs
index a86a6eb4bfe..6760640d33a 100644
--- a/src/libstd/lib.rs
+++ b/src/libstd/lib.rs
@@ -113,7 +113,7 @@
 #![feature(optin_builtin_traits)]
 #![feature(int_uint)]
 #![feature(int_uint)]
-#![allow(unstable)]
+#![feature(unnamed_feature)]
 
 // Don't link to std. We are std.
 #![no_std]
diff --git a/src/libstd/thunk.rs b/src/libstd/thunk.rs
index 1830a4df54a..94c86fcf1c8 100644
--- a/src/libstd/thunk.rs
+++ b/src/libstd/thunk.rs
@@ -10,6 +10,7 @@
 
 // Because this module is temporary...
 #![allow(missing_docs)]
+#![unstable(feature = "unnamed_feature", since = "1.0.0")]
 
 use alloc::boxed::Box;
 use core::marker::Send;
diff --git a/src/libsyntax/feature_gate.rs b/src/libsyntax/feature_gate.rs
index 13b7944998a..a5a2935d808 100644
--- a/src/libsyntax/feature_gate.rs
+++ b/src/libsyntax/feature_gate.rs
@@ -28,7 +28,7 @@ use codemap::{CodeMap, Span};
 use diagnostic::SpanHandler;
 use visit;
 use visit::Visitor;
-use parse::token;
+use parse::token::{self, InternedString};
 
 use std::slice;
 use std::ascii::AsciiExt;
@@ -123,7 +123,6 @@ enum Status {
 }
 
 /// A set of features to be used by later passes.
-#[derive(Copy)]
 pub struct Features {
     pub unboxed_closures: bool,
     pub rustc_diagnostic_macros: bool,
@@ -132,6 +131,7 @@ pub struct Features {
     pub quote: bool,
     pub old_orphan_check: bool,
     pub simd_ffi: bool,
+    pub lib_features: Vec<(InternedString, Span)>
 }
 
 impl Features {
@@ -144,6 +144,7 @@ impl Features {
             quote: false,
             old_orphan_check: false,
             simd_ffi: false,
+            lib_features: Vec::new()
         }
     }
 }
@@ -157,10 +158,7 @@ struct Context<'a> {
 impl<'a> Context<'a> {
     fn gate_feature(&self, feature: &str, span: Span, explain: &str) {
         if !self.has_feature(feature) {
-            self.span_handler.span_err(span, explain);
-            self.span_handler.span_help(span, &format!("add #![feature({})] to the \
-                                                       crate attributes to enable",
-                                                      feature)[]);
+            emit_feature_err(self.span_handler, feature, span, explain);
         }
     }
 
@@ -177,6 +175,13 @@ impl<'a> Context<'a> {
     }
 }
 
+pub fn emit_feature_err(diag: &SpanHandler, feature: &str, span: Span, explain: &str) {
+    diag.span_err(span, explain);
+    diag.span_help(span, &format!("add #![feature({})] to the \
+                                   crate attributes to enable",
+                                  feature)[]);
+}
+
 struct MacroVisitor<'a> {
     context: &'a Context<'a>
 }
@@ -472,7 +477,7 @@ impl<'a, 'v> Visitor<'v> for PostExpansionVisitor<'a> {
 
 fn check_crate_inner<F>(cm: &CodeMap, span_handler: &SpanHandler, krate: &ast::Crate,
                         check: F)
-                       -> (Features, Vec<Span>)
+                       -> Features
     where F: FnOnce(&mut Context, &ast::Crate)
 {
     let mut cx = Context {
@@ -524,7 +529,7 @@ fn check_crate_inner<F>(cm: &CodeMap, span_handler: &SpanHandler, krate: &ast::C
                                                              directive not necessary");
                         }
                         None => {
-                            unknown_features.push(mi.span);
+                            unknown_features.push((name, mi.span));
                         }
                     }
                 }
@@ -534,7 +539,7 @@ fn check_crate_inner<F>(cm: &CodeMap, span_handler: &SpanHandler, krate: &ast::C
 
     check(&mut cx, krate);
 
-    (Features {
+    Features {
         unboxed_closures: cx.has_feature("unboxed_closures"),
         rustc_diagnostic_macros: cx.has_feature("rustc_diagnostic_macros"),
         import_shadowing: cx.has_feature("import_shadowing"),
@@ -542,19 +547,20 @@ fn check_crate_inner<F>(cm: &CodeMap, span_handler: &SpanHandler, krate: &ast::C
         quote: cx.has_feature("quote"),
         old_orphan_check: cx.has_feature("old_orphan_check"),
         simd_ffi: cx.has_feature("simd_ffi"),
-    },
-    unknown_features)
+        lib_features: unknown_features
+    }
 }
 
 pub fn check_crate_macros(cm: &CodeMap, span_handler: &SpanHandler, krate: &ast::Crate)
--> (Features, Vec<Span>) {
+-> Features {
     check_crate_inner(cm, span_handler, krate,
                       |ctx, krate| visit::walk_crate(&mut MacroVisitor { context: ctx }, krate))
 }
 
 pub fn check_crate(cm: &CodeMap, span_handler: &SpanHandler, krate: &ast::Crate)
--> (Features, Vec<Span>) {
+-> Features {
     check_crate_inner(cm, span_handler, krate,
                       |ctx, krate| visit::walk_crate(&mut PostExpansionVisitor { context: ctx },
                                                      krate))
 }
+
diff --git a/src/libsyntax/lib.rs b/src/libsyntax/lib.rs
index d8a0c51b5ab..4d533590dd6 100644
--- a/src/libsyntax/lib.rs
+++ b/src/libsyntax/lib.rs
@@ -27,8 +27,8 @@
 #![feature(slicing_syntax)]
 #![feature(box_syntax)]
 #![feature(quote, unsafe_destructor)]
+#![feature(unnamed_feature)]
 #![allow(unknown_features)] #![feature(int_uint)]
-#![allow(unstable)]
 
 extern crate arena;
 extern crate fmt_macros;
diff --git a/src/libterm/lib.rs b/src/libterm/lib.rs
index a6ec16445c2..d14aad40bf0 100644
--- a/src/libterm/lib.rs
+++ b/src/libterm/lib.rs
@@ -52,8 +52,8 @@
 #![allow(unknown_features)]
 #![feature(slicing_syntax)]
 #![feature(box_syntax)]
+#![feature(unnamed_feature)]
 #![allow(unknown_features)] #![feature(int_uint)]
-#![allow(unstable)]
 #![deny(missing_docs)]
 
 #[macro_use] extern crate log;
diff --git a/src/libtest/lib.rs b/src/libtest/lib.rs
index be7410d901a..fbdfce0eddf 100644
--- a/src/libtest/lib.rs
+++ b/src/libtest/lib.rs
@@ -34,8 +34,8 @@
 #![allow(unknown_features)]
 #![feature(asm, slicing_syntax)]
 #![feature(box_syntax)]
+#![feature(unnamed_feature)]
 #![allow(unknown_features)] #![feature(int_uint)]
-#![allow(unstable)]
 
 extern crate getopts;
 extern crate regex;
diff --git a/src/libunicode/lib.rs b/src/libunicode/lib.rs
index 6fc6f614308..f47530a408f 100644
--- a/src/libunicode/lib.rs
+++ b/src/libunicode/lib.rs
@@ -30,8 +30,8 @@
        html_playground_url = "http://play.rust-lang.org/")]
 #![no_std]
 #![feature(slicing_syntax)]
+#![feature(unnamed_feature)]
 #![allow(unknown_features)] #![feature(int_uint)]
-#![allow(unstable)]
 
 extern crate core;
 
diff --git a/src/rustbook/main.rs b/src/rustbook/main.rs
index ea72c653087..1e5c571888e 100644
--- a/src/rustbook/main.rs
+++ b/src/rustbook/main.rs
@@ -9,7 +9,7 @@
 // except according to those terms.
 
 #![feature(slicing_syntax, box_syntax)]
-#![allow(unstable)]
+#![feature(unnamed_feature)]
 
 extern crate regex;
 
diff --git a/src/test/bench/shootout-mandelbrot.rs b/src/test/bench/shootout-mandelbrot.rs
index cf1264ff5d6..0e80cdca9f8 100644
--- a/src/test/bench/shootout-mandelbrot.rs
+++ b/src/test/bench/shootout-mandelbrot.rs
@@ -39,7 +39,6 @@
 // OF THE POSSIBILITY OF SUCH DAMAGE.
 
 #![feature(simd)]
-#![allow(unstable)]
 
 // ignore-pretty very bad with line comments
 
diff --git a/src/test/compile-fail/lint-dead-code-1.rs b/src/test/compile-fail/lint-dead-code-1.rs
index ceba33360d9..34c79be7118 100644
--- a/src/test/compile-fail/lint-dead-code-1.rs
+++ b/src/test/compile-fail/lint-dead-code-1.rs
@@ -13,7 +13,6 @@
 #![allow(non_camel_case_types)]
 #![allow(non_upper_case_globals)]
 #![allow(missing_copy_implementations)]
-#![allow(unstable)]
 #![deny(dead_code)]
 
 #![crate_type="lib"]
diff --git a/src/test/compile-fail/lint-dead-code-3.rs b/src/test/compile-fail/lint-dead-code-3.rs
index 89ab78968d0..03b89c522ce 100644
--- a/src/test/compile-fail/lint-dead-code-3.rs
+++ b/src/test/compile-fail/lint-dead-code-3.rs
@@ -10,7 +10,6 @@
 
 #![allow(unused_variables)]
 #![allow(non_camel_case_types)]
-#![allow(unstable)]
 #![deny(dead_code)]
 
 #![crate_type="lib"]
diff --git a/src/test/compile-fail/lint-dead-code-4.rs b/src/test/compile-fail/lint-dead-code-4.rs
index 3221be220d9..ac8f158f8fb 100644
--- a/src/test/compile-fail/lint-dead-code-4.rs
+++ b/src/test/compile-fail/lint-dead-code-4.rs
@@ -10,7 +10,6 @@
 
 #![allow(unused_variables)]
 #![allow(non_camel_case_types)]
-#![allow(unstable)]
 #![deny(dead_code)]
 
 extern crate libc;
diff --git a/src/test/compile-fail/lint-exceeding-bitshifts.rs b/src/test/compile-fail/lint-exceeding-bitshifts.rs
index 4c880eda099..91a4d0fea0a 100644
--- a/src/test/compile-fail/lint-exceeding-bitshifts.rs
+++ b/src/test/compile-fail/lint-exceeding-bitshifts.rs
@@ -10,7 +10,6 @@
 
 #![deny(exceeding_bitshifts)]
 #![allow(unused_variables)]
-#![allow(unstable)]
 #![allow(dead_code)]
 
 fn main() {
diff --git a/src/test/compile-fail/lint-uppercase-variables.rs b/src/test/compile-fail/lint-uppercase-variables.rs
index d9f899ede04..9317e465a7a 100644
--- a/src/test/compile-fail/lint-uppercase-variables.rs
+++ b/src/test/compile-fail/lint-uppercase-variables.rs
@@ -11,7 +11,6 @@
 // ignore-tidy-linelength
 
 #![allow(dead_code)]
-#![allow(unstable)]
 #![deny(non_snake_case)]
 
 use std::io::File;
diff --git a/src/test/compile-fail/liveness-unused.rs b/src/test/compile-fail/liveness-unused.rs
index f27ee376f52..c9f8230b6c5 100644
--- a/src/test/compile-fail/liveness-unused.rs
+++ b/src/test/compile-fail/liveness-unused.rs
@@ -10,7 +10,6 @@
 
 #![deny(unused_variables)]
 #![deny(unused_assignments)]
-#![allow(unstable)]
 #![allow(dead_code, non_camel_case_types)]
 
 fn f1(x: isize) {
diff --git a/src/test/compile-fail/simd-binop.rs b/src/test/compile-fail/simd-binop.rs
index 0c2d8972ce7..f028c9af462 100644
--- a/src/test/compile-fail/simd-binop.rs
+++ b/src/test/compile-fail/simd-binop.rs
@@ -10,7 +10,6 @@
 
 // ignore-tidy-linelength
 
-#![allow(unstable)]
 
 use std::simd::f32x4;
 
diff --git a/src/test/debuginfo/simd.rs b/src/test/debuginfo/simd.rs
index 4aaa3e0b75f..578ea4479ec 100644
--- a/src/test/debuginfo/simd.rs
+++ b/src/test/debuginfo/simd.rs
@@ -41,7 +41,6 @@
 
 // gdb-command:continue
 
-#![allow(unstable)]
 #![allow(unused_variables)]
 #![omit_gdb_pretty_printer_section]
 
diff --git a/src/test/run-pass/associated-types-normalize-unifield-struct.rs b/src/test/run-pass/associated-types-normalize-unifield-struct.rs
index c517f61de0c..5aafe93067c 100644
--- a/src/test/run-pass/associated-types-normalize-unifield-struct.rs
+++ b/src/test/run-pass/associated-types-normalize-unifield-struct.rs
@@ -11,7 +11,6 @@
 // Regression test for issue #21010: Normalize associated types in
 // various special paths in the `type_is_immediate` function.
 
-#![allow(unstable)]
 
 pub trait OffsetState: Sized {}
 pub trait Offset { type State: OffsetState; }
diff --git a/src/test/run-pass/ifmt.rs b/src/test/run-pass/ifmt.rs
index c22fb811a7b..dbc23a63bba 100644
--- a/src/test/run-pass/ifmt.rs
+++ b/src/test/run-pass/ifmt.rs
@@ -14,7 +14,6 @@
 #![deny(warnings)]
 #![allow(unused_must_use)]
 #![allow(unknown_features)]
-#![allow(unstable)]
 #![feature(box_syntax)]
 
 use std::fmt;
diff --git a/src/test/run-pass/issue-11958.rs b/src/test/run-pass/issue-11958.rs
index f557f662e81..13177880c5a 100644
--- a/src/test/run-pass/issue-11958.rs
+++ b/src/test/run-pass/issue-11958.rs
@@ -12,7 +12,6 @@
 
 // Pretty printing tests complain about `use std::predule::*`
 #![allow(unused_imports)]
-#![allow(unstable)]
 
 // We shouldn't need to rebind a moved upvar as mut if it's already
 // marked as mut
diff --git a/src/test/run-pass/issue-16671.rs b/src/test/run-pass/issue-16671.rs
index 4c72e4fdb73..e25b3e8e89c 100644
--- a/src/test/run-pass/issue-16671.rs
+++ b/src/test/run-pass/issue-16671.rs
@@ -14,7 +14,6 @@
 
 // Pretty printing tests complain about `use std::predule::*`
 #![allow(unused_imports)]
-#![allow(unstable)]
 
 // A var moved into a proc, that has a mutable loan path should
 // not trigger a misleading unused_mut warning.
diff --git a/src/test/run-pass/issue-21058.rs b/src/test/run-pass/issue-21058.rs
index cbce577451f..044d43a57fa 100644
--- a/src/test/run-pass/issue-21058.rs
+++ b/src/test/run-pass/issue-21058.rs
@@ -8,7 +8,6 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-#![allow(unstable)]
 
 struct NT(str);
 struct DST { a: u32, b: str }
diff --git a/src/test/run-pass/simd-binop.rs b/src/test/run-pass/simd-binop.rs
index 690ad351247..482eea19823 100644
--- a/src/test/run-pass/simd-binop.rs
+++ b/src/test/run-pass/simd-binop.rs
@@ -8,7 +8,6 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-#![allow(unstable)]
 
 use std::simd::{i32x4, f32x4, u32x4};
 
diff --git a/src/test/run-pass/simd-issue-10604.rs b/src/test/run-pass/simd-issue-10604.rs
index 6f0db23e2a6..7f1be4b7d70 100644
--- a/src/test/run-pass/simd-issue-10604.rs
+++ b/src/test/run-pass/simd-issue-10604.rs
@@ -9,7 +9,6 @@
 // except according to those terms.
 
 
-#![allow(unstable)]
 #![feature(simd)]
 
 pub fn main() {
diff --git a/src/test/run-pass/tcp-connect-timeouts.rs b/src/test/run-pass/tcp-connect-timeouts.rs
index 56044289fba..17a4b91467c 100644
--- a/src/test/run-pass/tcp-connect-timeouts.rs
+++ b/src/test/run-pass/tcp-connect-timeouts.rs
@@ -16,7 +16,6 @@
 // one test task to ensure that errors are timeouts, not file descriptor
 // exhaustion.
 
-#![allow(unstable)]
 #![reexport_test_harness_main = "test_main"]
 
 #![allow(unused_imports)]