diff options
| author | bors <bors@rust-lang.org> | 2015-01-28 03:59:14 +0000 |
|---|---|---|
| committer | bors <bors@rust-lang.org> | 2015-01-28 03:59:14 +0000 |
| commit | a530cc9706324ad44dba464d541a807eb5afdb08 (patch) | |
| tree | a8f9e5444cf2378b9c3d5a193484a3f6c9873a06 /src/libsyntax | |
| parent | 92ff8ea52816982ad4cbfac8168e216d32d74c77 (diff) | |
| parent | 71223050538939ed758fcd3b9114f71abff20bb2 (diff) | |
| download | rust-a530cc9706324ad44dba464d541a807eb5afdb08.tar.gz rust-a530cc9706324ad44dba464d541a807eb5afdb08.zip | |
Auto merge of #21248 - brson:feature-staging, r=alexcrichton
This implements the remaining bits of 'feature staging', as described in [RFC 507](https://github.com/rust-lang/rfcs/blob/master/text/0507-release-channels.md).
This is not quite done, but the substance of the work is complete so submitting for early review.
Key changes:
* `unstable`, `stable` and `deprecated` attributes all require 'feature' and 'since', and support an optional 'reason'.
* The `unstable` lint is removed.
* A new 'stability checking' pass warns when a used unstable library feature has not been activated with the `feature` attribute. At 1.0 beta this will become an error.
* A new 'unused feature checking' pass emits a lint ('unused_feature', renamed from 'unknown_feature') for any features that were activated but not used.
* A new tidy script `featureck.py` performs some global sanity checking, particularly that 'since' numbers agree, and also prints out a summary of features.
Differences from RFC:
* As implemented `unstable` requires a `since` attribute. I do not know if this is useful. I included it in the original sed script and just left it.
* RFC didn't specify the name of the optional 'reason' attribute.
* This continues to use 'unstable', 'stable' and 'deprecated' names (the 'nice' names) instead of 'staged_unstable', but only activates them with the crate-level 'staged_api' attribute.
I intend to update the RFC based on the outcome of this PR.
Issues:
* The unused feature check doesn't account for language features - i.e. you can activate a language feature, not use it, and not get the error.
Open questions:
* All unstable and deprecated features are named 'unnamed_feature', which i picked just because it is uniquely greppable. This is the 'catch-all' feature. What should it be?
* All stable features are named 'grandfathered'. What should this be?
TODO:
* Add check that all `deprecated` attributes are paired with a `stable` attribute in order to preserve the knowledge about when a feature became stable.
* Update rustdoc in various ways.
* Remove obsolete stability discussion from reference.
* Add features for 'path', 'io', 'os', 'hash' and 'rand'.
cc #20445 @alexcrichton @aturon
Diffstat (limited to 'src/libsyntax')
| -rw-r--r-- | src/libsyntax/attr.rs | 156 | ||||
| -rw-r--r-- | src/libsyntax/diagnostic.rs | 12 | ||||
| -rw-r--r-- | src/libsyntax/ext/base.rs | 4 | ||||
| -rw-r--r-- | src/libsyntax/feature_gate.rs | 183 | ||||
| -rw-r--r-- | src/libsyntax/lib.rs | 14 | ||||
| -rw-r--r-- | src/libsyntax/parse/lexer/mod.rs | 2 | ||||
| -rw-r--r-- | src/libsyntax/parse/mod.rs | 2 | ||||
| -rw-r--r-- | src/libsyntax/test.rs | 95 | ||||
| -rw-r--r-- | src/libsyntax/util/small_vector.rs | 3 |
9 files changed, 341 insertions, 130 deletions
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/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/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/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() } |
