about summary refs log tree commit diff
path: root/src/libsyntax
diff options
context:
space:
mode:
authorManish Goregaokar <manishsmail@gmail.com>2015-01-28 23:03:36 +0530
committerManish Goregaokar <manishsmail@gmail.com>2015-01-28 23:31:03 +0530
commitc709ed2faf4ea28df1395a924453b5298b87fa57 (patch)
tree9567cea197e37b96607f471b18dd1c77908c8965 /src/libsyntax
parent249c29fe2746d251dc8aab63cd8730df9ff8434c (diff)
parenta45e117733b866302fa99390553d1c548508dcca (diff)
downloadrust-c709ed2faf4ea28df1395a924453b5298b87fa57.tar.gz
rust-c709ed2faf4ea28df1395a924453b5298b87fa57.zip
Merge remote-tracking branch 'origin/master' into rollup
Conflicts:
	src/libcollections/slice.rs
	src/libcore/nonzero.rs
	src/libcore/ops.rs
Diffstat (limited to 'src/libsyntax')
-rw-r--r--src/libsyntax/ast.rs3
-rw-r--r--src/libsyntax/attr.rs156
-rw-r--r--src/libsyntax/diagnostic.rs12
-rw-r--r--src/libsyntax/ext/base.rs4
-rw-r--r--src/libsyntax/ext/tt/macro_parser.rs14
-rw-r--r--src/libsyntax/ext/tt/macro_rules.rs2
-rw-r--r--src/libsyntax/feature_gate.rs183
-rw-r--r--src/libsyntax/fold.rs5
-rw-r--r--src/libsyntax/lib.rs14
-rw-r--r--src/libsyntax/parse/lexer/mod.rs2
-rw-r--r--src/libsyntax/parse/mod.rs2
-rw-r--r--src/libsyntax/parse/parser.rs7
-rw-r--r--src/libsyntax/test.rs95
-rw-r--r--src/libsyntax/util/small_vector.rs3
14 files changed, 363 insertions, 139 deletions
diff --git a/src/libsyntax/ast.rs b/src/libsyntax/ast.rs
index 4f6cd8ad356..4dada5bc81e 100644
--- a/src/libsyntax/ast.rs
+++ b/src/libsyntax/ast.rs
@@ -347,6 +347,9 @@ impl AngleBracketedParameterData {
 /// A path like `Foo(A,B) -> C`
 #[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Show)]
 pub struct ParenthesizedParameterData {
+    /// Overall span
+    pub span: Span,
+
     /// `(A,B)`
     pub inputs: Vec<P<Ty>>,
 
diff --git a/src/libsyntax/attr.rs b/src/libsyntax/attr.rs
index 59471488af9..061600d9420 100644
--- a/src/libsyntax/attr.rs
+++ b/src/libsyntax/attr.rs
@@ -21,7 +21,7 @@ use codemap::{Span, Spanned, spanned, dummy_spanned};
 use codemap::BytePos;
 use diagnostic::SpanHandler;
 use parse::lexer::comments::{doc_comment_style, strip_doc_comment_decoration};
-use parse::token::InternedString;
+use parse::token::{InternedString, intern_and_get_ident};
 use parse::token;
 use ptr::P;
 
@@ -56,6 +56,8 @@ pub trait AttrMetaMethods {
     fn value_str(&self) -> Option<InternedString>;
     /// Gets a list of inner meta items from a list MetaItem type.
     fn meta_item_list<'a>(&'a self) -> Option<&'a [P<MetaItem>]>;
+
+    fn span(&self) -> Span;
 }
 
 impl AttrMetaMethods for Attribute {
@@ -73,6 +75,7 @@ impl AttrMetaMethods for Attribute {
     fn meta_item_list<'a>(&'a self) -> Option<&'a [P<MetaItem>]> {
         self.node.value.meta_item_list()
     }
+    fn span(&self) -> Span { self.meta().span }
 }
 
 impl AttrMetaMethods for MetaItem {
@@ -102,6 +105,7 @@ impl AttrMetaMethods for MetaItem {
             _ => None
         }
     }
+    fn span(&self) -> Span { self.span }
 }
 
 // Annoying, but required to get test_cfg to work
@@ -111,6 +115,7 @@ impl AttrMetaMethods for P<MetaItem> {
     fn meta_item_list<'a>(&'a self) -> Option<&'a [P<MetaItem>]> {
         (**self).meta_item_list()
     }
+    fn span(&self) -> Span { (**self).span() }
 }
 
 
@@ -340,22 +345,23 @@ pub fn cfg_matches(diagnostic: &SpanHandler, cfgs: &[P<MetaItem>], cfg: &ast::Me
     }
 }
 
-/// Represents the #[deprecated="foo"] and friends attributes.
+/// Represents the #[deprecated] and friends attributes.
 #[derive(RustcEncodable,RustcDecodable,Clone,Show)]
 pub struct Stability {
     pub level: StabilityLevel,
-    pub text: Option<InternedString>
+    pub feature: InternedString,
+    pub since: Option<InternedString>,
+    pub deprecated_since: Option<InternedString>,
+    // The reason for the current stability level. If deprecated, the
+    // reason for deprecation.
+    pub reason: Option<InternedString>,
 }
 
 /// The available stability levels.
 #[derive(RustcEncodable,RustcDecodable,PartialEq,PartialOrd,Clone,Show,Copy)]
 pub enum StabilityLevel {
-    Deprecated,
-    Experimental,
     Unstable,
     Stable,
-    Frozen,
-    Locked
 }
 
 impl fmt::Display for StabilityLevel {
@@ -364,36 +370,128 @@ impl fmt::Display for StabilityLevel {
     }
 }
 
-pub fn find_stability_generic<'a,
+fn find_stability_generic<'a,
                               AM: AttrMetaMethods,
                               I: Iterator<Item=&'a AM>>
-                             (mut attrs: I)
-                             -> Option<(Stability, &'a AM)> {
-    for attr in attrs {
-        let level = match attr.name().get() {
-            "deprecated" => Deprecated,
-            "experimental" => Experimental,
-            "unstable" => Unstable,
-            "stable" => Stable,
-            "frozen" => Frozen,
-            "locked" => Locked,
-            _ => continue // not a stability level
+                             (diagnostic: &SpanHandler, mut attrs: I, item_sp: Span)
+                             -> (Option<Stability>, Vec<&'a AM>) {
+
+    let mut stab: Option<Stability> = None;
+    let mut deprecated: Option<(InternedString, Option<InternedString>)> = None;
+    let mut used_attrs: Vec<&'a AM> = vec![];
+
+    'outer: for attr in attrs {
+        let tag = attr.name();
+        let tag = tag.get();
+        if tag != "deprecated" && tag != "unstable" && tag != "stable" {
+            continue // not a stability level
+        }
+
+        used_attrs.push(attr);
+
+        let (feature, since, reason) = match attr.meta_item_list() {
+            Some(metas) => {
+                let mut feature = None;
+                let mut since = None;
+                let mut reason = None;
+                for meta in metas.iter() {
+                    if meta.name().get() == "feature" {
+                        match meta.value_str() {
+                            Some(v) => feature = Some(v),
+                            None => {
+                                diagnostic.span_err(meta.span, "incorrect meta item");
+                                continue 'outer;
+                            }
+                        }
+                    }
+                    if meta.name().get() == "since" {
+                        match meta.value_str() {
+                            Some(v) => since = Some(v),
+                            None => {
+                                diagnostic.span_err(meta.span, "incorrect meta item");
+                                continue 'outer;
+                            }
+                        }
+                    }
+                    if meta.name().get() == "reason" {
+                        match meta.value_str() {
+                            Some(v) => reason = Some(v),
+                            None => {
+                                diagnostic.span_err(meta.span, "incorrect meta item");
+                                continue 'outer;
+                            }
+                        }
+                    }
+                }
+                (feature, since, reason)
+            }
+            None => {
+                diagnostic.span_err(attr.span(), "incorrect stability attribute type");
+                continue
+            }
         };
 
-        return Some((Stability {
-            level: level,
-                text: attr.value_str()
-            }, attr));
+        // Deprecated tags don't require feature names
+        if feature == None && tag != "deprecated" {
+            diagnostic.span_err(attr.span(), "missing 'feature'");
+        }
+
+        // Unstable tags don't require a version
+        if since == None && tag != "unstable" {
+            diagnostic.span_err(attr.span(), "missing 'since'");
+        }
+
+        if tag == "unstable" || tag == "stable" {
+            if stab.is_some() {
+                diagnostic.span_err(item_sp, "multiple stability levels");
+            }
+
+            let level = match tag {
+                "unstable" => Unstable,
+                "stable" => Stable,
+                _ => unreachable!()
+            };
+
+            stab = Some(Stability {
+                level: level,
+                feature: feature.unwrap_or(intern_and_get_ident("bogus")),
+                since: since,
+                deprecated_since: None,
+                reason: reason
+            });
+        } else { // "deprecated"
+            if deprecated.is_some() {
+                diagnostic.span_err(item_sp, "multiple deprecated attributes");
+            }
+
+            deprecated = Some((since.unwrap_or(intern_and_get_ident("bogus")), reason));
+        }
     }
-    None
+
+    // Merge the deprecation info into the stability info
+    if deprecated.is_some() {
+        match stab {
+            Some(ref mut s) => {
+                let (since, reason) = deprecated.unwrap();
+                s.deprecated_since = Some(since);
+                s.reason = reason;
+            }
+            None => {
+                diagnostic.span_err(item_sp, "deprecated attribute must be paired with \
+                                              either stable or unstable attribute");
+            }
+        }
+    }
+
+    (stab, used_attrs)
 }
 
 /// Find the first stability attribute. `None` if none exists.
-pub fn find_stability(attrs: &[Attribute]) -> Option<Stability> {
-    find_stability_generic(attrs.iter()).map(|(s, attr)| {
-        mark_used(attr);
-        s
-    })
+pub fn find_stability(diagnostic: &SpanHandler, attrs: &[Attribute],
+                      item_sp: Span) -> Option<Stability> {
+    let (s, used) = find_stability_generic(diagnostic, attrs.iter(), item_sp);
+    for used in used.into_iter() { mark_used(used) }
+    return s;
 }
 
 pub fn require_unique_names(diagnostic: &SpanHandler, metas: &[P<MetaItem>]) {
diff --git a/src/libsyntax/diagnostic.rs b/src/libsyntax/diagnostic.rs
index 5b79cb7b5dd..f3e66897316 100644
--- a/src/libsyntax/diagnostic.rs
+++ b/src/libsyntax/diagnostic.rs
@@ -143,6 +143,7 @@ impl SpanHandler {
 pub struct Handler {
     err_count: Cell<usize>,
     emit: RefCell<Box<Emitter + Send>>,
+    pub can_emit_warnings: bool
 }
 
 impl Handler {
@@ -195,6 +196,7 @@ impl Handler {
                 cmsp: Option<(&codemap::CodeMap, Span)>,
                 msg: &str,
                 lvl: Level) {
+        if lvl == Warning && !self.can_emit_warnings { return }
         self.emit.borrow_mut().emit(cmsp, msg, None, lvl);
     }
     pub fn emit_with_code(&self,
@@ -202,10 +204,12 @@ impl Handler {
                           msg: &str,
                           code: &str,
                           lvl: Level) {
+        if lvl == Warning && !self.can_emit_warnings { return }
         self.emit.borrow_mut().emit(cmsp, msg, Some(code), lvl);
     }
     pub fn custom_emit(&self, cm: &codemap::CodeMap,
                        sp: RenderSpan, msg: &str, lvl: Level) {
+        if lvl == Warning && !self.can_emit_warnings { return }
         self.emit.borrow_mut().custom_emit(cm, sp, msg, lvl);
     }
 }
@@ -218,14 +222,16 @@ pub fn mk_span_handler(handler: Handler, cm: codemap::CodeMap) -> SpanHandler {
 }
 
 pub fn default_handler(color_config: ColorConfig,
-                       registry: Option<diagnostics::registry::Registry>) -> Handler {
-    mk_handler(box EmitterWriter::stderr(color_config, registry))
+                       registry: Option<diagnostics::registry::Registry>,
+                       can_emit_warnings: bool) -> Handler {
+    mk_handler(can_emit_warnings, box EmitterWriter::stderr(color_config, registry))
 }
 
-pub fn mk_handler(e: Box<Emitter + Send>) -> Handler {
+pub fn mk_handler(can_emit_warnings: bool, e: Box<Emitter + Send>) -> Handler {
     Handler {
         err_count: Cell::new(0),
         emit: RefCell::new(e),
+        can_emit_warnings: can_emit_warnings
     }
 }
 
diff --git a/src/libsyntax/ext/base.rs b/src/libsyntax/ext/base.rs
index ef8010927dc..dd89153d497 100644
--- a/src/libsyntax/ext/base.rs
+++ b/src/libsyntax/ext/base.rs
@@ -570,7 +570,9 @@ impl<'a> ExtCtxt<'a> {
         }
     }
 
-    #[deprecated = "Replaced with `expander().fold_expr()`"]
+    #[unstable(feature = "rustc_private")]
+    #[deprecated(since = "1.0.0",
+                 reason = "Replaced with `expander().fold_expr()`")]
     pub fn expand_expr(&mut self, e: P<ast::Expr>) -> P<ast::Expr> {
         self.expander().fold_expr(e)
     }
diff --git a/src/libsyntax/ext/tt/macro_parser.rs b/src/libsyntax/ext/tt/macro_parser.rs
index d115f2ed620..9d5be3fff61 100644
--- a/src/libsyntax/ext/tt/macro_parser.rs
+++ b/src/libsyntax/ext/tt/macro_parser.rs
@@ -83,7 +83,7 @@ use self::TokenTreeOrTokenTreeVec::*;
 use ast;
 use ast::{TokenTree, Ident};
 use ast::{TtDelimited, TtSequence, TtToken};
-use codemap::{BytePos, mk_sp};
+use codemap::{BytePos, mk_sp, Span};
 use codemap;
 use parse::lexer::*; //resolve bug?
 use parse::ParseSess;
@@ -483,11 +483,11 @@ pub fn parse(sess: &ParseSess,
 
                 let mut ei = bb_eis.pop().unwrap();
                 match ei.top_elts.get_tt(ei.idx) {
-                  TtToken(_, MatchNt(_, name, _, _)) => {
+                  TtToken(span, MatchNt(_, name, _, _)) => {
                     let name_string = token::get_ident(name);
                     let match_cur = ei.match_cur;
                     (&mut ei.matches[match_cur]).push(Rc::new(MatchedNonterminal(
-                        parse_nt(&mut rust_parser, name_string.get()))));
+                        parse_nt(&mut rust_parser, span, name_string.get()))));
                     ei.idx += 1us;
                     ei.match_cur += 1;
                   }
@@ -505,7 +505,7 @@ pub fn parse(sess: &ParseSess,
     }
 }
 
-pub fn parse_nt(p: &mut Parser, name: &str) -> Nonterminal {
+pub fn parse_nt(p: &mut Parser, sp: Span, name: &str) -> Nonterminal {
     match name {
         "tt" => {
             p.quote_depth += 1us; //but in theory, non-quoted tts might be useful
@@ -541,7 +541,11 @@ pub fn parse_nt(p: &mut Parser, name: &str) -> Nonterminal {
       }
       "meta" => token::NtMeta(p.parse_meta_item()),
       _ => {
-          p.fatal(&format!("unsupported builtin nonterminal parser: {}", name)[])
+          p.span_fatal_help(sp,
+                            &format!("invalid fragment specifier `{}`", name)[],
+                            "valid fragment specifiers are `ident`, `block`, \
+                             `stmt`, `expr`, `pat`, `ty`, `path`, `meta`, `tt` \
+                             and `item`")
       }
     }
 }
diff --git a/src/libsyntax/ext/tt/macro_rules.rs b/src/libsyntax/ext/tt/macro_rules.rs
index 8350e0222ef..666281ac6b6 100644
--- a/src/libsyntax/ext/tt/macro_rules.rs
+++ b/src/libsyntax/ext/tt/macro_rules.rs
@@ -457,7 +457,7 @@ fn is_in_follow(_: &ExtCtxt, tok: &Token, frag: &str) -> Result<bool, String> {
                 // harmless
                 Ok(true)
             },
-            _ => Err(format!("unrecognized builtin nonterminal `{}`", frag))
+            _ => Err(format!("invalid fragment specifier `{}`", frag))
         }
     }
 }
diff --git a/src/libsyntax/feature_gate.rs b/src/libsyntax/feature_gate.rs
index 762a1dcbfc3..6e797844c18 100644
--- a/src/libsyntax/feature_gate.rs
+++ b/src/libsyntax/feature_gate.rs
@@ -17,6 +17,10 @@
 //!
 //! Features are enabled in programs via the crate-level attributes of
 //! `#![feature(...)]` with a comma-separated list of features.
+//!
+//! For the purpose of future feature-tracking, once code for detection of feature
+//! gate usage is added, *do not remove it again* even once the feature
+//! becomes stable.
 use self::Status::*;
 
 use abi::RustIntrinsic;
@@ -28,82 +32,90 @@ 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;
 
-
-// if you change this list without updating src/doc/reference.md, @cmr will be sad
-static KNOWN_FEATURES: &'static [(&'static str, Status)] = &[
-    ("globs", Accepted),
-    ("macro_rules", Accepted),
-    ("struct_variant", Accepted),
-    ("asm", Active),
-    ("managed_boxes", Removed),
-    ("non_ascii_idents", Active),
-    ("thread_local", Active),
-    ("link_args", Active),
-    ("phase", Removed),
-    ("plugin_registrar", Active),
-    ("log_syntax", Active),
-    ("trace_macros", Active),
-    ("concat_idents", Active),
-    ("unsafe_destructor", Active),
-    ("intrinsics", Active),
-    ("lang_items", Active),
-
-    ("simd", Active),
-    ("default_type_params", Accepted),
-    ("quote", Active),
-    ("link_llvm_intrinsics", Active),
-    ("linkage", Active),
-    ("struct_inherit", Removed),
-
-    ("quad_precision_float", Removed),
-
-    ("rustc_diagnostic_macros", Active),
-    ("unboxed_closures", Active),
-    ("import_shadowing", Removed),
-    ("advanced_slice_patterns", Active),
-    ("tuple_indexing", Accepted),
-    ("associated_types", Accepted),
-    ("visible_private_types", Active),
-    ("slicing_syntax", Active),
-    ("box_syntax", Active),
-    ("on_unimplemented", Active),
-    ("simd_ffi", Active),
-
-    ("if_let", Accepted),
-    ("while_let", Accepted),
-
-    ("plugin", Active),
-    ("start", Active),
-    ("main", Active),
+// If you change this list without updating src/doc/reference.md, @cmr will be sad
+// Don't ever remove anything from this list; set them to 'Removed'.
+// The version numbers here correspond to the version in which the current status
+// was set. This is most important for knowing when a particular feature became
+// stable (active).
+// NB: The featureck.py script parses this information directly out of the source
+// so take care when modifying it.
+static KNOWN_FEATURES: &'static [(&'static str, &'static str, Status)] = &[
+    ("globs", "1.0.0", Accepted),
+    ("macro_rules", "1.0.0", Accepted),
+    ("struct_variant", "1.0.0", Accepted),
+    ("asm", "1.0.0", Active),
+    ("managed_boxes", "1.0.0", Removed),
+    ("non_ascii_idents", "1.0.0", Active),
+    ("thread_local", "1.0.0", Active),
+    ("link_args", "1.0.0", Active),
+    ("phase", "1.0.0", Removed),
+    ("plugin_registrar", "1.0.0", Active),
+    ("log_syntax", "1.0.0", Active),
+    ("trace_macros", "1.0.0", Active),
+    ("concat_idents", "1.0.0", Active),
+    ("unsafe_destructor", "1.0.0", Active),
+    ("intrinsics", "1.0.0", Active),
+    ("lang_items", "1.0.0", Active),
+
+    ("simd", "1.0.0", Active),
+    ("default_type_params", "1.0.0", Accepted),
+    ("quote", "1.0.0", Active),
+    ("link_llvm_intrinsics", "1.0.0", Active),
+    ("linkage", "1.0.0", Active),
+    ("struct_inherit", "1.0.0", Removed),
+
+    ("quad_precision_float", "1.0.0", Removed),
+
+    ("rustc_diagnostic_macros", "1.0.0", Active),
+    ("unboxed_closures", "1.0.0", Active),
+    ("import_shadowing", "1.0.0", Removed),
+    ("advanced_slice_patterns", "1.0.0", Active),
+    ("tuple_indexing", "1.0.0", Accepted),
+    ("associated_types", "1.0.0", Accepted),
+    ("visible_private_types", "1.0.0", Active),
+    ("slicing_syntax", "1.0.0", Active),
+    ("box_syntax", "1.0.0", Active),
+    ("on_unimplemented", "1.0.0", Active),
+    ("simd_ffi", "1.0.0", Active),
+
+    ("if_let", "1.0.0", Accepted),
+    ("while_let", "1.0.0", Accepted),
+
+    ("plugin", "1.0.0", Active),
+    ("start", "1.0.0", Active),
+    ("main", "1.0.0", Active),
 
     // A temporary feature gate used to enable parser extensions needed
     // to bootstrap fix for #5723.
-    ("issue_5723_bootstrap", Accepted),
+    ("issue_5723_bootstrap", "1.0.0", Accepted),
 
     // A way to temporarily opt out of opt in copy. This will *never* be accepted.
-    ("opt_out_copy", Removed),
+    ("opt_out_copy", "1.0.0", Removed),
 
     // A way to temporarily opt out of the new orphan rules. This will *never* be accepted.
-    ("old_orphan_check", Deprecated),
+    ("old_orphan_check", "1.0.0", Deprecated),
 
     // A way to temporarily opt out of the new impl rules. This will *never* be accepted.
-    ("old_impl_check", Deprecated),
+    ("old_impl_check", "1.0.0", Deprecated),
 
     // OIBIT specific features
-    ("optin_builtin_traits", Active),
+    ("optin_builtin_traits", "1.0.0", Active),
 
     // int and uint are now deprecated
-    ("int_uint", Active),
+    ("int_uint", "1.0.0", Active),
 
     // These are used to test this portion of the compiler, they don't actually
     // mean anything
-    ("test_accepted_feature", Accepted),
-    ("test_removed_feature", Removed),
+    ("test_accepted_feature", "1.0.0", Accepted),
+    ("test_removed_feature", "1.0.0", Removed),
+
+    // Allows use of #[staged_api]
+    ("staged_api", "1.0.0", Active),
 ];
 
 enum Status {
@@ -123,7 +135,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,
@@ -131,6 +142,7 @@ pub struct Features {
     pub quote: bool,
     pub old_orphan_check: bool,
     pub simd_ffi: bool,
+    pub lib_features: Vec<(InternedString, Span)>
 }
 
 impl Features {
@@ -142,6 +154,7 @@ impl Features {
             quote: false,
             old_orphan_check: false,
             simd_ffi: false,
+            lib_features: Vec::new()
         }
     }
 }
@@ -155,19 +168,13 @@ 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);
         }
     }
 
     fn warn_feature(&self, feature: &str, span: Span, explain: &str) {
         if !self.has_feature(feature) {
-            self.span_handler.span_warn(span, explain);
-            self.span_handler.span_help(span, &format!("add #![feature({})] to the \
-                                                       crate attributes to silence this warning",
-                                                      feature)[]);
+            emit_feature_warn(self.span_handler, feature, span, explain);
         }
     }
     fn has_feature(&self, feature: &str) -> bool {
@@ -175,6 +182,22 @@ 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)[]);
+}
+
+pub fn emit_feature_warn(diag: &SpanHandler, feature: &str, span: Span, explain: &str) {
+    diag.span_warn(span, explain);
+    if diag.handler.can_emit_warnings {
+        diag.span_help(span, &format!("add #![feature({})] to the \
+                                       crate attributes to silence this warning",
+                                      feature)[]);
+    }
+}
+
 struct MacroVisitor<'a> {
     context: &'a Context<'a>
 }
@@ -416,6 +439,11 @@ impl<'a, 'v> Visitor<'v> for PostExpansionVisitor<'a> {
     }
 
     fn visit_attribute(&mut self, attr: &ast::Attribute) {
+        if attr.check_name("staged_api") {
+            self.gate_feature("staged_api", attr.span,
+                              "staged_api is for use by rustc only");
+        }
+
         if attr::contains_name(slice::ref_slice(attr), "lang") {
             self.gate_feature("lang_items",
                               attr.span,
@@ -462,7 +490,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 {
@@ -495,26 +523,26 @@ fn check_crate_inner<F>(cm: &CodeMap, span_handler: &SpanHandler, krate: &ast::C
                         }
                     };
                     match KNOWN_FEATURES.iter()
-                                        .find(|& &(n, _)| name == n) {
-                        Some(&(name, Active)) => {
+                                        .find(|& &(n, _, _)| name == n) {
+                        Some(&(name, _, Active)) => {
                             cx.features.push(name);
                         }
-                        Some(&(name, Deprecated)) => {
+                        Some(&(name, _, Deprecated)) => {
                             cx.features.push(name);
                             span_handler.span_warn(
                                 mi.span,
                                 "feature is deprecated and will only be available \
                                  for a limited time, please rewrite code that relies on it");
                         }
-                        Some(&(_, Removed)) => {
+                        Some(&(_, _, Removed)) => {
                             span_handler.span_err(mi.span, "feature has been removed");
                         }
-                        Some(&(_, Accepted)) => {
+                        Some(&(_, _, Accepted)) => {
                             span_handler.span_warn(mi.span, "feature has been added to Rust, \
                                                              directive not necessary");
                         }
                         None => {
-                            unknown_features.push(mi.span);
+                            unknown_features.push((name, mi.span));
                         }
                     }
                 }
@@ -524,26 +552,27 @@ 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"),
         visible_private_types: cx.has_feature("visible_private_types"),
         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/fold.rs b/src/libsyntax/fold.rs
index bf822599a88..a1362f5382c 100644
--- a/src/libsyntax/fold.rs
+++ b/src/libsyntax/fold.rs
@@ -536,9 +536,10 @@ pub fn noop_fold_parenthesized_parameter_data<T: Folder>(data: ParenthesizedPara
                                                          fld: &mut T)
                                                          -> ParenthesizedParameterData
 {
-    let ParenthesizedParameterData { inputs, output } = data;
+    let ParenthesizedParameterData { inputs, output, span } = data;
     ParenthesizedParameterData { inputs: inputs.move_map(|ty| fld.fold_ty(ty)),
-                                 output: output.map(|ty| fld.fold_ty(ty)) }
+                                 output: output.map(|ty| fld.fold_ty(ty)),
+                                 span: fld.new_span(span) }
 }
 
 pub fn noop_fold_local<T: Folder>(l: P<Local>, fld: &mut T) -> P<Local> {
diff --git a/src/libsyntax/lib.rs b/src/libsyntax/lib.rs
index fa675a9fcaa..ff4c7b565cb 100644
--- a/src/libsyntax/lib.rs
+++ b/src/libsyntax/lib.rs
@@ -15,7 +15,8 @@
 //! This API is completely unstable and subject to change.
 
 #![crate_name = "syntax"]
-#![unstable]
+#![unstable(feature = "rustc_private")]
+#![feature(staged_api)]
 #![staged_api]
 #![crate_type = "dylib"]
 #![crate_type = "rlib"]
@@ -28,7 +29,16 @@
 #![feature(box_syntax)]
 #![feature(quote, unsafe_destructor)]
 #![allow(unknown_features)] #![feature(int_uint)]
-#![allow(unstable)]
+#![feature(collections)]
+#![feature(core)]
+#![feature(hash)]
+#![feature(io)]
+#![feature(libc)]
+#![feature(os)]
+#![feature(path)]
+#![feature(rustc_private)]
+#![feature(std_misc)]
+#![feature(unicode)]
 
 extern crate arena;
 extern crate fmt_macros;
diff --git a/src/libsyntax/parse/lexer/mod.rs b/src/libsyntax/parse/lexer/mod.rs
index 92a89c17579..99be1b11b11 100644
--- a/src/libsyntax/parse/lexer/mod.rs
+++ b/src/libsyntax/parse/lexer/mod.rs
@@ -1486,7 +1486,7 @@ mod test {
 
     fn mk_sh() -> diagnostic::SpanHandler {
         let emitter = diagnostic::EmitterWriter::new(box util::NullWriter, None);
-        let handler = diagnostic::mk_handler(box emitter);
+        let handler = diagnostic::mk_handler(true, box emitter);
         diagnostic::mk_span_handler(handler, CodeMap::new())
     }
 
diff --git a/src/libsyntax/parse/mod.rs b/src/libsyntax/parse/mod.rs
index 2b4087dba58..4bd476885a0 100644
--- a/src/libsyntax/parse/mod.rs
+++ b/src/libsyntax/parse/mod.rs
@@ -45,7 +45,7 @@ pub struct ParseSess {
 
 pub fn new_parse_sess() -> ParseSess {
     ParseSess {
-        span_diagnostic: mk_span_handler(default_handler(Auto, None), CodeMap::new()),
+        span_diagnostic: mk_span_handler(default_handler(Auto, None, true), CodeMap::new()),
         included_mod_stack: RefCell::new(Vec::new()),
         node_id: Cell::new(1),
     }
diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs
index fbea265597c..4c1ae532d13 100644
--- a/src/libsyntax/parse/parser.rs
+++ b/src/libsyntax/parse/parser.rs
@@ -1796,6 +1796,8 @@ impl<'a> Parser<'a> {
                     bindings: OwnedSlice::from_vec(bindings),
                 })
             } else if self.eat(&token::OpenDelim(token::Paren)) {
+                let lo = self.last_span.lo;
+
                 let inputs = self.parse_seq_to_end(
                     &token::CloseDelim(token::Paren),
                     seq_sep_trailing_allowed(token::Comma),
@@ -1807,9 +1809,12 @@ impl<'a> Parser<'a> {
                     None
                 };
 
+                let hi = self.last_span.hi;
+
                 ast::ParenthesizedParameters(ast::ParenthesizedParameterData {
+                    span: mk_sp(lo, hi),
                     inputs: inputs,
-                    output: output_ty
+                    output: output_ty,
                 })
             } else {
                 ast::PathParameters::none()
diff --git a/src/libsyntax/test.rs b/src/libsyntax/test.rs
index 8933d3a9669..a7679adca2e 100644
--- a/src/libsyntax/test.rs
+++ b/src/libsyntax/test.rs
@@ -279,6 +279,24 @@ fn strip_test_functions(krate: ast::Crate) -> ast::Crate {
     })
 }
 
+/// Craft a span that will be ignored by the stability lint's
+/// call to codemap's is_internal check.
+/// The expanded code calls some unstable functions in the test crate.
+fn ignored_span(cx: &TestCtxt, sp: Span) -> Span {
+    let info = ExpnInfo {
+        call_site: DUMMY_SP,
+        callee: NameAndSpan {
+            name: "test".to_string(),
+            format: MacroAttribute,
+            span: None
+        }
+    };
+    let expn_id = cx.sess.span_diagnostic.cm.record_expansion(info);
+    let mut sp = sp;
+    sp.expn_id = expn_id;
+    return sp;
+}
+
 #[derive(PartialEq)]
 enum HasTestSignature {
     Yes,
@@ -407,6 +425,65 @@ fn mk_std(cx: &TestCtxt) -> P<ast::Item> {
     })
 }
 
+fn mk_main(cx: &mut TestCtxt) -> P<ast::Item> {
+    // Writing this out by hand with 'ignored_span':
+    //        pub fn main() {
+    //            #![main]
+    //            use std::slice::AsSlice;
+    //            test::test_main_static(::std::os::args().as_slice(), TESTS);
+    //        }
+
+    let sp = ignored_span(cx, DUMMY_SP);
+    let ecx = &cx.ext_cx;
+
+    // std::slice::AsSlice
+    let as_slice_path = ecx.path(sp, vec![token::str_to_ident("std"),
+                                          token::str_to_ident("slice"),
+                                          token::str_to_ident("AsSlice")]);
+    // test::test_main_static
+    let test_main_path = ecx.path(sp, vec![token::str_to_ident("test"),
+                                           token::str_to_ident("test_main_static")]);
+    // ::std::os::args
+    let os_args_path = ecx.path_global(sp, vec![token::str_to_ident("std"),
+                                                token::str_to_ident("os"),
+                                                token::str_to_ident("args")]);
+    // use std::slice::AsSlice
+    let as_slice_path = P(nospan(ast::ViewPathSimple(token::str_to_ident("AsSlice"),
+                                                     as_slice_path)));
+    let use_as_slice = ecx.item_use(sp, ast::Inherited, as_slice_path);
+    let use_as_slice = ecx.stmt_item(sp, use_as_slice);
+    // ::std::os::args()
+    let os_args_path_expr = ecx.expr_path(os_args_path);
+    let call_os_args = ecx.expr_call(sp, os_args_path_expr, vec![]);
+    // ::std::os::args().as_slice()
+    let call_as_slice = ecx.expr_method_call(sp, call_os_args,
+                                             token::str_to_ident("as_slice"), vec![]);
+    // test::test_main_static(...)
+    let test_main_path_expr = ecx.expr_path(test_main_path);
+    let tests_ident_expr = ecx.expr_ident(sp, token::str_to_ident("TESTS"));
+    let call_test_main = ecx.expr_call(sp, test_main_path_expr,
+                                       vec![call_as_slice, tests_ident_expr]);
+    let call_test_main = ecx.stmt_expr(call_test_main);
+    // #![main]
+    let main_meta = ecx.meta_word(sp, token::intern_and_get_ident("main"));
+    let main_attr = ecx.attribute(sp, main_meta);
+    // pub fn main() { ... }
+    let main_ret_ty = ecx.ty(sp, ast::TyTup(vec![]));
+    let main_body = ecx.block_all(sp, vec![use_as_slice, call_test_main], None);
+    let main = ast::ItemFn(ecx.fn_decl(vec![], main_ret_ty),
+                           ast::Unsafety::Normal, ::abi::Rust, empty_generics(), main_body);
+    let main = P(ast::Item {
+        ident: token::str_to_ident("main"),
+        attrs: vec![main_attr],
+        id: ast::DUMMY_NODE_ID,
+        node: main,
+        vis: ast::Public,
+        span: sp
+    });
+
+    return main;
+}
+
 fn mk_test_module(cx: &mut TestCtxt) -> (P<ast::Item>, Option<P<ast::Item>>) {
     // Link to test crate
     let import = mk_std(cx);
@@ -416,13 +493,7 @@ fn mk_test_module(cx: &mut TestCtxt) -> (P<ast::Item>, Option<P<ast::Item>>) {
 
     // The synthesized main function which will call the console test runner
     // with our list of tests
-    let mainfn = (quote_item!(&mut cx.ext_cx,
-        pub fn main() {
-            #![main]
-            use std::slice::AsSlice;
-            test::test_main_static(::std::os::args().as_slice(), TESTS);
-        }
-    )).unwrap();
+    let mainfn = mk_main(cx);
 
     let testmod = ast::Mod {
         inner: DUMMY_SP,
@@ -431,16 +502,10 @@ fn mk_test_module(cx: &mut TestCtxt) -> (P<ast::Item>, Option<P<ast::Item>>) {
     let item_ = ast::ItemMod(testmod);
 
     let mod_ident = token::gensym_ident("__test");
-    let allow_unstable = {
-        let unstable = P(nospan(ast::MetaWord(InternedString::new("unstable"))));
-        let allow = P(nospan(ast::MetaList(InternedString::new("allow"),
-                                           vec![unstable])));
-        attr::mk_attr_inner(attr::mk_attr_id(), allow)
-    };
     let item = P(ast::Item {
         id: ast::DUMMY_NODE_ID,
         ident: mod_ident,
-        attrs: vec![allow_unstable],
+        attrs: vec![],
         node: item_,
         vis: ast::Public,
         span: DUMMY_SP,
@@ -537,7 +602,7 @@ fn mk_test_desc_and_fn_rec(cx: &TestCtxt, test: &Test) -> P<ast::Expr> {
     // __test_reexports, causing it to be reinterned, losing the
     // gensym information.
 
-    let span = test.span;
+    let span = ignored_span(cx, test.span);
     let path = test.path.clone();
     let ecx = &cx.ext_cx;
     let self_id = ecx.ident_of("self");
diff --git a/src/libsyntax/util/small_vector.rs b/src/libsyntax/util/small_vector.rs
index d8bac19805b..21a7d680847 100644
--- a/src/libsyntax/util/small_vector.rs
+++ b/src/libsyntax/util/small_vector.rs
@@ -112,7 +112,8 @@ impl<T> SmallVector<T> {
     }
 
     /// Deprecated: use `into_iter`.
-    #[deprecated = "use into_iter"]
+    #[unstable(feature = "rustc_private")]
+    #[deprecated(since = "1.0.0", reason = "use into_iter")]
     pub fn move_iter(self) -> IntoIter<T> {
         self.into_iter()
     }