know that we're safe.
There's another detail here that's not 100% clear because of how `println!`
-works. `num` is actually of type `&int`, that is, it's a reference to an `int`,
+works. `num` is actually of type `&int`. That is, it's a reference to an `int`,
not an `int` itself. `println!` handles the dereferencing for us, so we don't
see it. This code works fine too:
memory: uint
}
-// This is the Two-Way search algorithm, which was introduced in the paper:
-// Crochemore, M., Perrin, D., 1991, Two-way string-matching, Journal of the ACM 38(3):651-675.
+/*
+ This is the Two-Way search algorithm, which was introduced in the paper:
+ Crochemore, M., Perrin, D., 1991, Two-way string-matching, Journal of the ACM 38(3):651-675.
+
+ Here's some background information.
+
+ A *word* is a string of symbols. The *length* of a word should be a familiar
+ notion, and here we denote it for any word x by |x|.
+ (We also allow for the possibility of the *empty word*, a word of length zero).
+
+ If x is any non-empty word, then an integer p with 0 < p <= |x| is said to be a
+ *period* for x iff for all i with 0 <= i <= |x| - p - 1, we have x[i] == x[i+p].
+ For example, both 1 and 2 are periods for the string "aa". As another example,
+ the only period of the string "abcd" is 4.
+
+ We denote by period(x) the *smallest* period of x (provided that x is non-empty).
+ This is always well-defined since every non-empty word x has at least one period,
+ |x|. We sometimes call this *the period* of x.
+
+ If u, v and x are words such that x = uv, where uv is the concatenation of u and
+ v, then we say that (u, v) is a *factorization* of x.
+
+ Let (u, v) be a factorization for a word x. Then if w is a non-empty word such
+ that both of the following hold
+
+ - either w is a suffix of u or u is a suffix of w
+ - either w is a prefix of v or v is a prefix of w
+
+ then w is said to be a *repetition* for the factorization (u, v).
+
+ Just to unpack this, there are four possibilities here. Let w = "abc". Then we
+ might have:
+
+ - w is a suffix of u and w is a prefix of v. ex: ("lolabc", "abcde")
+ - w is a suffix of u and v is a prefix of w. ex: ("lolabc", "ab")
+ - u is a suffix of w and w is a prefix of v. ex: ("bc", "abchi")
+ - u is a suffix of w and v is a prefix of w. ex: ("bc", "a")
+
+ Note that the word vu is a repetition for any factorization (u,v) of x = uv,
+ so every factorization has at least one repetition.
+
+ If x is a string and (u, v) is a factorization for x, then a *local period* for
+ (u, v) is an integer r such that there is some word w such that |w| = r and w is
+ a repetition for (u, v).
+
+ We denote by local_period(u, v) the smallest local period of (u, v). We sometimes
+ call this *the local period* of (u, v). Provided that x = uv is non-empty, this
+ is well-defined (because each non-empty word has at least one factorization, as
+ noted above).
+
+ It can be proven that the following is an equivalent definition of a local period
+ for a factorization (u, v): any positive integer r such that x[i] == x[i+r] for
+ all i such that |u| - r <= i <= |u| - 1 and such that both x[i] and x[i+r] are
+ defined. (i.e. i > 0 and i + r < |x|).
+
+ Using the above reformulation, it is easy to prove that
+
+ 1 <= local_period(u, v) <= period(uv)
+
+ A factorization (u, v) of x such that local_period(u,v) = period(x) is called a
+ *critical factorization*.
+
+ The algorithm hinges on the following theorem, which is stated without proof:
+
+ **Critical Factorization Theorem** Any word x has at least one critical
+ factorization (u, v) such that |u| < period(x).
+
+ The purpose of maximal_suffix is to find such a critical factorization.
+
+*/
impl TwoWaySearcher {
fn new(needle: &[u8]) -> TwoWaySearcher {
let (crit_pos1, period1) = TwoWaySearcher::maximal_suffix(needle, false);
period = period2;
}
+ // This isn't in the original algorithm, as far as I'm aware.
let byteset = needle.iter()
.fold(0, |a, &b| (1 << ((b & 0x3f) as uint)) | a);
- // The logic here (calculating crit_pos and period, the final if statement to see which
- // period to use for the TwoWaySearcher) is essentially an implementation of the
- // "small-period" function from the paper (p. 670)
+ // A particularly readable explanation of what's going on here can be found
+ // in Crochemore and Rytter's book "Text Algorithms", ch 13. Specifically
+ // see the code for "Algorithm CP" on p. 323.
//
- // In the paper they check whether `needle.slice_to(crit_pos)` is a suffix of
- // `needle.slice(crit_pos, crit_pos + period)`, which is precisely what this does
+ // What's going on is we have some critical factorization (u, v) of the
+ // needle, and we want to determine whether u is a suffix of
+ // v.slice_to(period). If it is, we use "Algorithm CP1". Otherwise we use
+ // "Algorithm CP2", which is optimized for when the period of the needle
+ // is large.
if needle.slice_to(crit_pos) == needle.slice(period, period + crit_pos) {
TwoWaySearcher {
crit_pos: crit_pos,
}
}
+ // One of the main ideas of Two-Way is that we factorize the needle into
+ // two halves, (u, v), and begin trying to find v in the haystack by scanning
+ // left to right. If v matches, we try to match u by scanning right to left.
+ // How far we can jump when we encounter a mismatch is all based on the fact
+ // that (u, v) is a critical factorization for the needle.
#[inline]
fn next(&mut self, haystack: &[u8], needle: &[u8], long_period: bool) -> Option<(uint, uint)> {
'search: loop {
((haystack[self.position + needle.len() - 1] & 0x3f)
as uint)) & 1 == 0 {
self.position += needle.len();
+ if !long_period {
+ self.memory = 0;
+ }
continue 'search;
}
}
}
- // returns (i, p) where i is the "critical position", the starting index of
- // of maximal suffix, and p is the period of the suffix
- // see p. 668 of the paper
+ // Computes a critical factorization (u, v) of `arr`.
+ // Specifically, returns (i, p), where i is the starting index of v in some
+ // critical factorization (u, v) and p = period(v)
#[inline]
fn maximal_suffix(arr: &[u8], reversed: bool) -> (uint, uint) {
let mut left = -1; // Corresponds to i in the paper
check_contains_all_substrings("012345678901234567890123456789bcdabcdabcd");
}
+#[test]
+fn strslice_issue_16878() {
+ assert!(!"1234567ah012345678901ah".contains("hah"));
+ assert!(!"00abc01234567890123456789abc".contains("bcabc"));
+}
+
#[test]
fn test_strslice_contains() {
use back::write;
use driver::session::Session;
use driver::config;
-use front;
use lint;
use llvm::{ContextRef, ModuleRef};
use metadata::common::LinkMeta;
}
if sess.show_span() {
- front::show_span::run(sess, &krate);
+ syntax::show_span::run(sess.diagnostic(), &krate);
}
krate
*sess.crate_metadata.borrow_mut() =
collect_crate_metadata(sess, krate.attrs.as_slice());
- time(time_passes, "gated feature checking", (), |_|
- front::feature_gate::check_crate(sess, &krate));
+ time(time_passes, "gated feature checking", (), |_| {
+ let (features, unknown_features) =
+ syntax::feature_gate::check_crate(&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());
+ }
+
+ sess.abort_if_errors();
+ *sess.features.borrow_mut() = features;
+ });
+
+ let any_exe = sess.crate_types.borrow().iter().any(|ty| {
+ *ty == config::CrateTypeExecutable
+ });
krate = time(time_passes, "crate injection", krate, |krate|
- front::std_inject::maybe_inject_crates_ref(sess, krate));
+ syntax::std_inject::maybe_inject_crates_ref(krate,
+ sess.opts.alt_std_name.clone(),
+ any_exe));
// strip before expansion to allow macros to depend on
// configuration variables e.g/ in
// baz! should not use this definition unless foo is enabled.
krate = time(time_passes, "configuration 1", krate, |krate|
- front::config::strip_unconfigured_items(krate));
+ syntax::config::strip_unconfigured_items(krate));
let mut addl_plugins = Some(addl_plugins);
let Plugins { macros, registrars }
let mut registry = Registry::new(&krate);
time(time_passes, "plugin registration", (), |_| {
- if sess.features.rustc_diagnostic_macros.get() {
+ if sess.features.borrow().rustc_diagnostic_macros {
registry.register_macro("__diagnostic_used",
diagnostics::plugin::expand_diagnostic_used);
registry.register_macro("__register_diagnostic",
os::setenv("PATH", os::join_paths(new_path.as_slice()).unwrap());
}
let cfg = syntax::ext::expand::ExpansionConfig {
- deriving_hash_type_parameter: sess.features.default_type_params.get(),
+ deriving_hash_type_parameter: sess.features.borrow().default_type_params,
crate_name: crate_name.to_string(),
};
let ret = syntax::ext::expand::expand_crate(&sess.parse_sess,
// strip again, in case expansion added anything with a #[cfg].
krate = time(time_passes, "configuration 2", krate, |krate|
- front::config::strip_unconfigured_items(krate));
+ syntax::config::strip_unconfigured_items(krate));
krate = time(time_passes, "maybe building test harness", krate, |krate|
- front::test::modify_for_testing(sess, krate));
+ syntax::test::modify_for_testing(&sess.parse_sess,
+ &sess.opts.cfg,
+ krate,
+ sess.diagnostic()));
krate = time(time_passes, "prelude injection", krate, |krate|
- front::std_inject::maybe_inject_prelude(sess, krate));
+ syntax::std_inject::maybe_inject_prelude(krate));
time(time_passes, "checking that all macro invocations are gone", &krate, |krate|
syntax::ext::expand::check_for_macros(&sess.parse_sess, krate));
use driver::config;
use driver::driver;
-use front;
use metadata::cstore::CStore;
use metadata::filesearch;
use lint;
use syntax::codemap::Span;
use syntax::diagnostic;
use syntax::diagnostics;
+use syntax::feature_gate;
use syntax::parse;
use syntax::parse::token;
use syntax::parse::ParseSess;
pub working_dir: Path,
pub lint_store: RefCell<lint::LintStore>,
pub lints: RefCell<NodeMap<Vec<(lint::LintId, codemap::Span, String)>>>,
- pub node_id: Cell<ast::NodeId>,
pub crate_types: RefCell<Vec<config::CrateType>>,
pub crate_metadata: RefCell<Vec<String>>,
- pub features: front::feature_gate::Features,
+ pub features: RefCell<feature_gate::Features>,
/// The maximum recursion limit for potentially infinitely recursive
/// operations such as auto-dereference and monomorphization.
lints.insert(id, vec!((lint_id, sp, msg)));
}
pub fn next_node_id(&self) -> ast::NodeId {
- self.reserve_node_ids(1)
+ self.parse_sess.next_node_id()
}
pub fn reserve_node_ids(&self, count: ast::NodeId) -> ast::NodeId {
- let v = self.node_id.get();
-
- match v.checked_add(&count) {
- Some(next) => { self.node_id.set(next); }
- None => self.bug("Input too large, ran out of node ids!")
- }
-
- v
+ self.parse_sess.reserve_node_ids(count)
}
pub fn diagnostic<'a>(&'a self) -> &'a diagnostic::SpanHandler {
&self.parse_sess.span_diagnostic
working_dir: os::getcwd(),
lint_store: RefCell::new(lint::LintStore::new()),
lints: RefCell::new(NodeMap::new()),
- node_id: Cell::new(1),
crate_types: RefCell::new(Vec::new()),
crate_metadata: RefCell::new(Vec::new()),
- features: front::feature_gate::Features::new(),
+ features: RefCell::new(feature_gate::Features::new()),
recursion_limit: Cell::new(64),
};
+++ /dev/null
-// Copyright 2012-2014 The Rust Project Developers. See the COPYRIGHT
-// file at the top-level directory of this distribution and at
-// http://rust-lang.org/COPYRIGHT.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-use syntax::fold::Folder;
-use syntax::{ast, fold, attr};
-use syntax::codemap::Spanned;
-use syntax::ptr::P;
-
-/// A folder that strips out items that do not belong in the current
-/// configuration.
-struct Context<'a> {
- in_cfg: |attrs: &[ast::Attribute]|: 'a -> bool,
-}
-
-// Support conditional compilation by transforming the AST, stripping out
-// any items that do not belong in the current configuration
-pub fn strip_unconfigured_items(krate: ast::Crate) -> ast::Crate {
- let config = krate.config.clone();
- strip_items(krate, |attrs| in_cfg(config.as_slice(), attrs))
-}
-
-impl<'a> fold::Folder for Context<'a> {
- fn fold_mod(&mut self, module: ast::Mod) -> ast::Mod {
- fold_mod(self, module)
- }
- fn fold_block(&mut self, block: P<ast::Block>) -> P<ast::Block> {
- fold_block(self, block)
- }
- fn fold_foreign_mod(&mut self, foreign_mod: ast::ForeignMod) -> ast::ForeignMod {
- fold_foreign_mod(self, foreign_mod)
- }
- fn fold_item_underscore(&mut self, item: ast::Item_) -> ast::Item_ {
- fold_item_underscore(self, item)
- }
- fn fold_expr(&mut self, expr: P<ast::Expr>) -> P<ast::Expr> {
- fold_expr(self, expr)
- }
- fn fold_mac(&mut self, mac: ast::Mac) -> ast::Mac {
- fold::noop_fold_mac(mac, self)
- }
-}
-
-pub fn strip_items(krate: ast::Crate,
- in_cfg: |attrs: &[ast::Attribute]| -> bool)
- -> ast::Crate {
- let mut ctxt = Context {
- in_cfg: in_cfg,
- };
- ctxt.fold_crate(krate)
-}
-
-fn filter_view_item(cx: &mut Context, view_item: ast::ViewItem) -> Option<ast::ViewItem> {
- if view_item_in_cfg(cx, &view_item) {
- Some(view_item)
- } else {
- None
- }
-}
-
-fn fold_mod(cx: &mut Context, ast::Mod {inner, view_items, items}: ast::Mod) -> ast::Mod {
- ast::Mod {
- inner: inner,
- view_items: view_items.into_iter().filter_map(|a| {
- filter_view_item(cx, a).map(|x| cx.fold_view_item(x))
- }).collect(),
- items: items.into_iter().filter_map(|a| {
- if item_in_cfg(cx, &*a) {
- Some(cx.fold_item(a))
- } else {
- None
- }
- }).flat_map(|x| x.into_iter()).collect()
- }
-}
-
-fn filter_foreign_item(cx: &mut Context, item: P<ast::ForeignItem>)
- -> Option<P<ast::ForeignItem>> {
- if foreign_item_in_cfg(cx, &*item) {
- Some(item)
- } else {
- None
- }
-}
-
-fn fold_foreign_mod(cx: &mut Context, ast::ForeignMod {abi, view_items, items}: ast::ForeignMod)
- -> ast::ForeignMod {
- ast::ForeignMod {
- abi: abi,
- view_items: view_items.into_iter().filter_map(|a| {
- filter_view_item(cx, a).map(|x| cx.fold_view_item(x))
- }).collect(),
- items: items.into_iter()
- .filter_map(|a| filter_foreign_item(cx, a))
- .collect()
- }
-}
-
-fn fold_item_underscore(cx: &mut Context, item: ast::Item_) -> ast::Item_ {
- let item = match item {
- ast::ItemImpl(a, b, c, impl_items) => {
- let impl_items = impl_items.into_iter()
- .filter(|ii| impl_item_in_cfg(cx, ii))
- .collect();
- ast::ItemImpl(a, b, c, impl_items)
- }
- ast::ItemTrait(a, b, c, methods) => {
- let methods = methods.into_iter()
- .filter(|m| trait_method_in_cfg(cx, m))
- .collect();
- ast::ItemTrait(a, b, c, methods)
- }
- ast::ItemStruct(def, generics) => {
- ast::ItemStruct(fold_struct(cx, def), generics)
- }
- ast::ItemEnum(def, generics) => {
- let mut variants = def.variants.into_iter().filter_map(|v| {
- if !(cx.in_cfg)(v.node.attrs.as_slice()) {
- None
- } else {
- Some(v.map(|Spanned {node: ast::Variant_ {id, name, attrs, kind,
- disr_expr, vis}, span}| {
- Spanned {
- node: ast::Variant_ {
- id: id,
- name: name,
- attrs: attrs,
- kind: match kind {
- ast::TupleVariantKind(..) => kind,
- ast::StructVariantKind(def) => {
- ast::StructVariantKind(fold_struct(cx, def))
- }
- },
- disr_expr: disr_expr,
- vis: vis
- },
- span: span
- }
- }))
- }
- });
- ast::ItemEnum(ast::EnumDef {
- variants: variants.collect(),
- }, generics)
- }
- item => item,
- };
-
- fold::noop_fold_item_underscore(item, cx)
-}
-
-fn fold_struct(cx: &mut Context, def: P<ast::StructDef>) -> P<ast::StructDef> {
- def.map(|ast::StructDef {fields, ctor_id, super_struct, is_virtual}| {
- ast::StructDef {
- fields: fields.into_iter().filter(|m| {
- (cx.in_cfg)(m.node.attrs.as_slice())
- }).collect(),
- ctor_id: ctor_id,
- super_struct: super_struct,
- is_virtual: is_virtual,
- }
- })
-}
-
-fn retain_stmt(cx: &mut Context, stmt: &ast::Stmt) -> bool {
- match stmt.node {
- ast::StmtDecl(ref decl, _) => {
- match decl.node {
- ast::DeclItem(ref item) => {
- item_in_cfg(cx, &**item)
- }
- _ => true
- }
- }
- _ => true
- }
-}
-
-fn fold_block(cx: &mut Context, b: P<ast::Block>) -> P<ast::Block> {
- b.map(|ast::Block {id, view_items, stmts, expr, rules, span}| {
- let resulting_stmts: Vec<P<ast::Stmt>> =
- stmts.into_iter().filter(|a| retain_stmt(cx, &**a)).collect();
- let resulting_stmts = resulting_stmts.into_iter()
- .flat_map(|stmt| cx.fold_stmt(stmt).into_iter())
- .collect();
- let filtered_view_items = view_items.into_iter().filter_map(|a| {
- filter_view_item(cx, a).map(|x| cx.fold_view_item(x))
- }).collect();
- ast::Block {
- id: id,
- view_items: filtered_view_items,
- stmts: resulting_stmts,
- expr: expr.map(|x| cx.fold_expr(x)),
- rules: rules,
- span: span,
- }
- })
-}
-
-fn fold_expr(cx: &mut Context, expr: P<ast::Expr>) -> P<ast::Expr> {
- expr.map(|ast::Expr {id, span, node}| {
- fold::noop_fold_expr(ast::Expr {
- id: id,
- node: match node {
- ast::ExprMatch(m, arms) => {
- ast::ExprMatch(m, arms.into_iter()
- .filter(|a| (cx.in_cfg)(a.attrs.as_slice()))
- .collect())
- }
- _ => node
- },
- span: span
- }, cx)
- })
-}
-
-fn item_in_cfg(cx: &mut Context, item: &ast::Item) -> bool {
- return (cx.in_cfg)(item.attrs.as_slice());
-}
-
-fn foreign_item_in_cfg(cx: &mut Context, item: &ast::ForeignItem) -> bool {
- return (cx.in_cfg)(item.attrs.as_slice());
-}
-
-fn view_item_in_cfg(cx: &mut Context, item: &ast::ViewItem) -> bool {
- return (cx.in_cfg)(item.attrs.as_slice());
-}
-
-fn trait_method_in_cfg(cx: &mut Context, meth: &ast::TraitItem) -> bool {
- match *meth {
- ast::RequiredMethod(ref meth) => (cx.in_cfg)(meth.attrs.as_slice()),
- ast::ProvidedMethod(ref meth) => (cx.in_cfg)(meth.attrs.as_slice())
- }
-}
-
-fn impl_item_in_cfg(cx: &mut Context, impl_item: &ast::ImplItem) -> bool {
- match *impl_item {
- ast::MethodImplItem(ref meth) => (cx.in_cfg)(meth.attrs.as_slice()),
- }
-}
-
-// Determine if an item should be translated in the current crate
-// configuration based on the item's attributes
-fn in_cfg(cfg: &[P<ast::MetaItem>], attrs: &[ast::Attribute]) -> bool {
- attr::test_cfg(cfg, attrs.iter())
-}
-
+++ /dev/null
-// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
-// file at the top-level directory of this distribution and at
-// http://rust-lang.org/COPYRIGHT.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-//! Feature gating
-//!
-//! This modules implements the gating necessary for preventing certain compiler
-//! features from being used by default. This module will crawl a pre-expanded
-//! AST to ensure that there are no features which are used that are not
-//! enabled.
-//!
-//! Features are enabled in programs via the crate-level attributes of
-//! `#![feature(...)]` with a comma-separated list of features.
-
-use lint;
-
-use syntax::abi::RustIntrinsic;
-use syntax::ast::NodeId;
-use syntax::ast;
-use syntax::attr;
-use syntax::attr::AttrMetaMethods;
-use syntax::codemap::Span;
-use syntax::visit;
-use syntax::visit::Visitor;
-use syntax::parse::token;
-
-use driver::session::Session;
-
-use std::cell::Cell;
-use std::slice;
-
-/// This is a list of all known features since the beginning of time. This list
-/// can never shrink, it may only be expanded (in order to prevent old programs
-/// from failing to compile). The status of each feature may change, however.
-static KNOWN_FEATURES: &'static [(&'static str, Status)] = &[
- ("globs", Active),
- ("macro_rules", Active),
- ("struct_variant", Active),
- ("once_fns", Active),
- ("asm", Active),
- ("managed_boxes", Active),
- ("non_ascii_idents", Active),
- ("thread_local", Active),
- ("link_args", Active),
- ("phase", Active),
- ("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", Active),
- ("quote", Active),
- ("linkage", Active),
- ("struct_inherit", Active),
- ("overloaded_calls", Active),
- ("unboxed_closure_sugar", Active),
-
- ("quad_precision_float", Removed),
-
- ("rustc_diagnostic_macros", Active),
- ("unboxed_closures", Active),
- ("import_shadowing", Active),
- ("advanced_slice_patterns", Active),
- ("tuple_indexing", Active),
-
- // if you change this list without updating src/doc/rust.md, cmr will be sad
-
- // A temporary feature gate used to enable parser extensions needed
- // to bootstrap fix for #5723.
- ("issue_5723_bootstrap", Accepted),
-
- // These are used to test this portion of the compiler, they don't actually
- // mean anything
- ("test_accepted_feature", Accepted),
- ("test_removed_feature", Removed),
-];
-
-enum Status {
- /// Represents an active feature that is currently being implemented or
- /// currently being considered for addition/removal.
- Active,
-
- /// Represents a feature which has since been removed (it was once Active)
- Removed,
-
- /// This language feature has since been Accepted (it was once Active)
- Accepted,
-}
-
-/// A set of features to be used by later passes.
-pub struct Features {
- pub default_type_params: Cell<bool>,
- pub overloaded_calls: Cell<bool>,
- pub rustc_diagnostic_macros: Cell<bool>,
- pub import_shadowing: Cell<bool>,
-}
-
-impl Features {
- pub fn new() -> Features {
- Features {
- default_type_params: Cell::new(false),
- overloaded_calls: Cell::new(false),
- rustc_diagnostic_macros: Cell::new(false),
- import_shadowing: Cell::new(false),
- }
- }
-}
-
-struct Context<'a> {
- features: Vec<&'static str>,
- sess: &'a Session,
-}
-
-impl<'a> Context<'a> {
- fn gate_feature(&self, feature: &str, span: Span, explain: &str) {
- if !self.has_feature(feature) {
- self.sess.span_err(span, explain);
- self.sess.span_note(span, format!("add #![feature({})] to the \
- crate attributes to enable",
- feature).as_slice());
- }
- }
-
- fn gate_box(&self, span: Span) {
- self.gate_feature("managed_boxes", span,
- "The managed box syntax is being replaced by the \
- `std::gc::Gc` and `std::rc::Rc` types. Equivalent \
- functionality to managed trait objects will be \
- implemented but is currently missing.");
- }
-
- fn has_feature(&self, feature: &str) -> bool {
- self.features.iter().any(|n| n.as_slice() == feature)
- }
-}
-
-impl<'a, 'v> Visitor<'v> for Context<'a> {
- fn visit_ident(&mut self, sp: Span, id: ast::Ident) {
- if !token::get_ident(id).get().is_ascii() {
- self.gate_feature("non_ascii_idents", sp,
- "non-ascii idents are not fully supported.");
- }
- }
-
- fn visit_view_item(&mut self, i: &ast::ViewItem) {
- match i.node {
- ast::ViewItemUse(ref path) => {
- match path.node {
- ast::ViewPathGlob(..) => {
- self.gate_feature("globs", path.span,
- "glob import statements are \
- experimental and possibly buggy");
- }
- _ => {}
- }
- }
- ast::ViewItemExternCrate(..) => {
- for attr in i.attrs.iter() {
- if attr.name().get() == "phase"{
- self.gate_feature("phase", attr.span,
- "compile time crate loading is \
- experimental and possibly buggy");
- }
- }
- }
- }
- visit::walk_view_item(self, i)
- }
-
- fn visit_item(&mut self, i: &ast::Item) {
- for attr in i.attrs.iter() {
- if attr.name().equiv(&("thread_local")) {
- self.gate_feature("thread_local", i.span,
- "`#[thread_local]` is an experimental feature, and does not \
- currently handle destructors. There is no corresponding \
- `#[task_local]` mapping to the task model");
- }
- }
- match i.node {
- ast::ItemEnum(ref def, _) => {
- for variant in def.variants.iter() {
- match variant.node.kind {
- ast::StructVariantKind(..) => {
- self.gate_feature("struct_variant", variant.span,
- "enum struct variants are \
- experimental and possibly buggy");
- }
- _ => {}
- }
- }
- }
-
- ast::ItemForeignMod(ref foreign_module) => {
- if attr::contains_name(i.attrs.as_slice(), "link_args") {
- self.gate_feature("link_args", i.span,
- "the `link_args` attribute is not portable \
- across platforms, it is recommended to \
- use `#[link(name = \"foo\")]` instead")
- }
- if foreign_module.abi == RustIntrinsic {
- self.gate_feature("intrinsics",
- i.span,
- "intrinsics are subject to change")
- }
- }
-
- ast::ItemFn(..) => {
- if attr::contains_name(i.attrs.as_slice(), "plugin_registrar") {
- self.gate_feature("plugin_registrar", i.span,
- "compiler plugins are experimental and possibly buggy");
- }
- }
-
- ast::ItemStruct(ref struct_definition, _) => {
- if attr::contains_name(i.attrs.as_slice(), "simd") {
- self.gate_feature("simd", i.span,
- "SIMD types are experimental and possibly buggy");
- }
- match struct_definition.super_struct {
- Some(ref path) => self.gate_feature("struct_inherit", path.span,
- "struct inheritance is experimental \
- and possibly buggy"),
- None => {}
- }
- if struct_definition.is_virtual {
- self.gate_feature("struct_inherit", i.span,
- "struct inheritance (`virtual` keyword) is \
- experimental and possibly buggy");
- }
- }
-
- ast::ItemImpl(..) => {
- if attr::contains_name(i.attrs.as_slice(),
- "unsafe_destructor") {
- self.gate_feature("unsafe_destructor",
- i.span,
- "`#[unsafe_destructor]` allows too \
- many unsafe patterns and may be \
- removed in the future");
- }
- }
-
- _ => {}
- }
-
- visit::walk_item(self, i);
- }
-
- fn visit_mac(&mut self, macro: &ast::Mac) {
- let ast::MacInvocTT(ref path, _, _) = macro.node;
- let id = path.segments.last().unwrap().identifier;
- let quotes = ["quote_tokens", "quote_expr", "quote_ty",
- "quote_item", "quote_pat", "quote_stmt"];
- let msg = " is not stable enough for use and are subject to change";
-
-
- if id == token::str_to_ident("macro_rules") {
- self.gate_feature("macro_rules", path.span, "macro definitions are \
- not stable enough for use and are subject to change");
- }
-
- else if id == token::str_to_ident("asm") {
- self.gate_feature("asm", path.span, "inline assembly is not \
- stable enough for use and is subject to change");
- }
-
- else if id == token::str_to_ident("log_syntax") {
- self.gate_feature("log_syntax", path.span, "`log_syntax!` is not \
- stable enough for use and is subject to change");
- }
-
- else if id == token::str_to_ident("trace_macros") {
- self.gate_feature("trace_macros", path.span, "`trace_macros` is not \
- stable enough for use and is subject to change");
- }
-
- else if id == token::str_to_ident("concat_idents") {
- self.gate_feature("concat_idents", path.span, "`concat_idents` is not \
- stable enough for use and is subject to change");
- }
-
- else {
- for "e in quotes.iter() {
- if id == token::str_to_ident(quote) {
- self.gate_feature("quote",
- path.span,
- format!("{}{}", quote, msg).as_slice());
- }
- }
- }
- }
-
- fn visit_foreign_item(&mut self, i: &ast::ForeignItem) {
- if attr::contains_name(i.attrs.as_slice(), "linkage") {
- self.gate_feature("linkage", i.span,
- "the `linkage` attribute is experimental \
- and not portable across platforms")
- }
- visit::walk_foreign_item(self, i)
- }
-
- fn visit_ty(&mut self, t: &ast::Ty) {
- match t.node {
- ast::TyClosure(ref closure) if closure.onceness == ast::Once => {
- self.gate_feature("once_fns", t.span,
- "once functions are \
- experimental and likely to be removed");
-
- },
- ast::TyBox(_) => { self.gate_box(t.span); }
- ast::TyUnboxedFn(..) => {
- self.gate_feature("unboxed_closure_sugar",
- t.span,
- "unboxed closure trait sugar is experimental");
- }
- _ => {}
- }
-
- visit::walk_ty(self, t);
- }
-
- fn visit_expr(&mut self, e: &ast::Expr) {
- match e.node {
- ast::ExprUnary(ast::UnBox, _) => {
- self.gate_box(e.span);
- }
- ast::ExprUnboxedFn(..) => {
- self.gate_feature("unboxed_closures",
- e.span,
- "unboxed closures are a work-in-progress \
- feature with known bugs");
- }
- ast::ExprTupField(..) => {
- self.gate_feature("tuple_indexing",
- e.span,
- "tuple indexing is experimental");
- }
- _ => {}
- }
- visit::walk_expr(self, e);
- }
-
- fn visit_generics(&mut self, generics: &ast::Generics) {
- for type_parameter in generics.ty_params.iter() {
- match type_parameter.default {
- Some(ref ty) => {
- self.gate_feature("default_type_params", ty.span,
- "default type parameters are \
- experimental and possibly buggy");
- }
- None => {}
- }
- }
- visit::walk_generics(self, generics);
- }
-
- fn visit_attribute(&mut self, attr: &ast::Attribute) {
- if attr::contains_name(slice::ref_slice(attr), "lang") {
- self.gate_feature("lang_items",
- attr.span,
- "language items are subject to change");
- }
- }
-
- fn visit_pat(&mut self, pattern: &ast::Pat) {
- match pattern.node {
- ast::PatVec(_, Some(_), ref last) if !last.is_empty() => {
- self.gate_feature("advanced_slice_patterns",
- pattern.span,
- "multiple-element slice matches anywhere \
- but at the end of a slice (e.g. \
- `[0, ..xs, 0]` are experimental")
- }
- _ => {}
- }
- visit::walk_pat(self, pattern)
- }
-
- fn visit_fn(&mut self,
- fn_kind: visit::FnKind<'v>,
- fn_decl: &'v ast::FnDecl,
- block: &'v ast::Block,
- span: Span,
- _: NodeId) {
- match fn_kind {
- visit::FkItemFn(_, _, _, abi) if abi == RustIntrinsic => {
- self.gate_feature("intrinsics",
- span,
- "intrinsics are subject to change")
- }
- _ => {}
- }
- visit::walk_fn(self, fn_kind, fn_decl, block, span);
- }
-}
-
-pub fn check_crate(sess: &Session, krate: &ast::Crate) {
- let mut cx = Context {
- features: Vec::new(),
- sess: sess,
- };
-
- for attr in krate.attrs.iter() {
- if !attr.check_name("feature") {
- continue
- }
-
- match attr.meta_item_list() {
- None => {
- sess.span_err(attr.span, "malformed feature attribute, \
- expected #![feature(...)]");
- }
- Some(list) => {
- for mi in list.iter() {
- let name = match mi.node {
- ast::MetaWord(ref word) => (*word).clone(),
- _ => {
- sess.span_err(mi.span,
- "malformed feature, expected just \
- one word");
- continue
- }
- };
- match KNOWN_FEATURES.iter()
- .find(|& &(n, _)| name.equiv(&n)) {
- Some(&(name, Active)) => { cx.features.push(name); }
- Some(&(_, Removed)) => {
- sess.span_err(mi.span, "feature has been removed");
- }
- Some(&(_, Accepted)) => {
- sess.span_warn(mi.span, "feature has been added to Rust, \
- directive not necessary");
- }
- None => {
- sess.add_lint(lint::builtin::UNKNOWN_FEATURES,
- ast::CRATE_NODE_ID,
- mi.span,
- "unknown feature".to_string());
- }
- }
- }
- }
- }
- }
-
- visit::walk_crate(&mut cx, krate);
-
- sess.abort_if_errors();
-
- sess.features.default_type_params.set(cx.has_feature("default_type_params"));
- sess.features.overloaded_calls.set(cx.has_feature("overloaded_calls"));
- sess.features.rustc_diagnostic_macros.set(cx.has_feature("rustc_diagnostic_macros"));
- sess.features.import_shadowing.set(cx.has_feature("import_shadowing"));
-}
-
+++ /dev/null
-// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
-// file at the top-level directory of this distribution and at
-// http://rust-lang.org/COPYRIGHT.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-//! Span debugger
-//!
-//! This module shows spans for all expressions in the crate
-//! to help with compiler debugging.
-
-use syntax::ast;
-use syntax::visit;
-use syntax::visit::Visitor;
-
-use driver::session::Session;
-
-struct ShowSpanVisitor<'a> {
- sess: &'a Session
-}
-
-impl<'a, 'v> Visitor<'v> for ShowSpanVisitor<'a> {
- fn visit_expr(&mut self, e: &ast::Expr) {
- self.sess.span_note(e.span, "expression");
- visit::walk_expr(self, e);
- }
-
- fn visit_mac(&mut self, macro: &ast::Mac) {
- visit::walk_mac(self, macro);
- }
-}
-
-pub fn run(sess: &Session, krate: &ast::Crate) {
- let mut v = ShowSpanVisitor { sess: sess };
- visit::walk_crate(&mut v, krate);
-}
+++ /dev/null
-// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
-// file at the top-level directory of this distribution and at
-// http://rust-lang.org/COPYRIGHT.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-use driver::config;
-use driver::session::Session;
-
-use syntax::ast;
-use syntax::attr;
-use syntax::codemap::DUMMY_SP;
-use syntax::codemap;
-use syntax::fold::Folder;
-use syntax::fold;
-use syntax::owned_slice::OwnedSlice;
-use syntax::parse::token::InternedString;
-use syntax::parse::token::special_idents;
-use syntax::parse::token;
-use syntax::ptr::P;
-use syntax::util::small_vector::SmallVector;
-
-use std::mem;
-
-pub fn maybe_inject_crates_ref(sess: &Session, krate: ast::Crate)
- -> ast::Crate {
- if use_std(&krate) {
- inject_crates_ref(sess, krate)
- } else {
- krate
- }
-}
-
-pub fn maybe_inject_prelude(sess: &Session, krate: ast::Crate) -> ast::Crate {
- if use_std(&krate) {
- inject_prelude(sess, krate)
- } else {
- krate
- }
-}
-
-fn use_std(krate: &ast::Crate) -> bool {
- !attr::contains_name(krate.attrs.as_slice(), "no_std")
-}
-
-fn use_start(krate: &ast::Crate) -> bool {
- !attr::contains_name(krate.attrs.as_slice(), "no_start")
-}
-
-fn no_prelude(attrs: &[ast::Attribute]) -> bool {
- attr::contains_name(attrs, "no_implicit_prelude")
-}
-
-struct StandardLibraryInjector<'a> {
- sess: &'a Session,
-}
-
-impl<'a> fold::Folder for StandardLibraryInjector<'a> {
- fn fold_crate(&mut self, mut krate: ast::Crate) -> ast::Crate {
-
- // The name to use in `extern crate "name" as std;`
- let actual_crate_name = match self.sess.opts.alt_std_name {
- Some(ref s) => token::intern_and_get_ident(s.as_slice()),
- None => token::intern_and_get_ident("std"),
- };
-
- let mut vis = vec!(ast::ViewItem {
- node: ast::ViewItemExternCrate(token::str_to_ident("std"),
- Some((actual_crate_name, ast::CookedStr)),
- ast::DUMMY_NODE_ID),
- attrs: vec!(
- attr::mk_attr_outer(attr::mk_attr_id(), attr::mk_list_item(
- InternedString::new("phase"),
- vec!(
- attr::mk_word_item(InternedString::new("plugin")),
- attr::mk_word_item(InternedString::new("link")
- ))))),
- vis: ast::Inherited,
- span: DUMMY_SP
- });
-
- let any_exe = self.sess.crate_types.borrow().iter().any(|ty| {
- *ty == config::CrateTypeExecutable
- });
- if use_start(&krate) && any_exe {
- let visible_rt_name = "rt";
- let actual_rt_name = "native";
- // Gensym the ident so it can't be named
- let visible_rt_name = token::gensym_ident(visible_rt_name);
- let actual_rt_name = token::intern_and_get_ident(actual_rt_name);
-
- vis.push(ast::ViewItem {
- node: ast::ViewItemExternCrate(visible_rt_name,
- Some((actual_rt_name, ast::CookedStr)),
- ast::DUMMY_NODE_ID),
- attrs: Vec::new(),
- vis: ast::Inherited,
- span: DUMMY_SP
- });
- }
-
- // `extern crate` must be precede `use` items
- mem::swap(&mut vis, &mut krate.module.view_items);
- krate.module.view_items.push_all_move(vis);
-
- // don't add #![no_std] here, that will block the prelude injection later.
- // Add it during the prelude injection instead.
-
- // Add #![feature(phase)] here, because we use #[phase] on extern crate std.
- let feat_phase_attr = attr::mk_attr_inner(attr::mk_attr_id(),
- attr::mk_list_item(
- InternedString::new("feature"),
- vec![attr::mk_word_item(InternedString::new("phase"))],
- ));
- // std_inject runs after feature checking so manually mark this attr
- attr::mark_used(&feat_phase_attr);
- krate.attrs.push(feat_phase_attr);
-
- krate
- }
-}
-
-fn inject_crates_ref(sess: &Session, krate: ast::Crate) -> ast::Crate {
- let mut fold = StandardLibraryInjector {
- sess: sess,
- };
- fold.fold_crate(krate)
-}
-
-struct PreludeInjector<'a>;
-
-
-impl<'a> fold::Folder for PreludeInjector<'a> {
- fn fold_crate(&mut self, mut krate: ast::Crate) -> ast::Crate {
- // Add #![no_std] here, so we don't re-inject when compiling pretty-printed source.
- // This must happen here and not in StandardLibraryInjector because this
- // fold happens second.
-
- let no_std_attr = attr::mk_attr_inner(attr::mk_attr_id(),
- attr::mk_word_item(InternedString::new("no_std")));
- // std_inject runs after feature checking so manually mark this attr
- attr::mark_used(&no_std_attr);
- krate.attrs.push(no_std_attr);
-
- if !no_prelude(krate.attrs.as_slice()) {
- // only add `use std::prelude::*;` if there wasn't a
- // `#![no_implicit_prelude]` at the crate level.
- // fold_mod() will insert glob path.
- let globs_attr = attr::mk_attr_inner(attr::mk_attr_id(),
- attr::mk_list_item(
- InternedString::new("feature"),
- vec!(
- attr::mk_word_item(InternedString::new("globs")),
- )));
- // std_inject runs after feature checking so manually mark this attr
- attr::mark_used(&globs_attr);
- krate.attrs.push(globs_attr);
-
- krate.module = self.fold_mod(krate.module);
- }
- krate
- }
-
- fn fold_item(&mut self, item: P<ast::Item>) -> SmallVector<P<ast::Item>> {
- if !no_prelude(item.attrs.as_slice()) {
- // only recur if there wasn't `#![no_implicit_prelude]`
- // on this item, i.e. this means that the prelude is not
- // implicitly imported though the whole subtree
- fold::noop_fold_item(item, self)
- } else {
- SmallVector::one(item)
- }
- }
-
- fn fold_mod(&mut self, ast::Mod {inner, view_items, items}: ast::Mod) -> ast::Mod {
- let prelude_path = ast::Path {
- span: DUMMY_SP,
- global: false,
- segments: vec!(
- ast::PathSegment {
- identifier: token::str_to_ident("std"),
- lifetimes: Vec::new(),
- types: OwnedSlice::empty(),
- },
- ast::PathSegment {
- identifier: token::str_to_ident("prelude"),
- lifetimes: Vec::new(),
- types: OwnedSlice::empty(),
- }),
- };
-
- let (crates, uses) = view_items.partitioned(|x| {
- match x.node {
- ast::ViewItemExternCrate(..) => true,
- _ => false,
- }
- });
-
- // add prelude after any `extern crate` but before any `use`
- let mut view_items = crates;
- let vp = P(codemap::dummy_spanned(ast::ViewPathGlob(prelude_path, ast::DUMMY_NODE_ID)));
- view_items.push(ast::ViewItem {
- node: ast::ViewItemUse(vp),
- attrs: vec![ast::Attribute {
- span: DUMMY_SP,
- node: ast::Attribute_ {
- id: attr::mk_attr_id(),
- style: ast::AttrOuter,
- value: P(ast::MetaItem {
- span: DUMMY_SP,
- node: ast::MetaWord(token::get_name(
- special_idents::prelude_import.name)),
- }),
- is_sugared_doc: false,
- },
- }],
- vis: ast::Inherited,
- span: DUMMY_SP,
- });
- view_items.push_all_move(uses);
-
- fold::noop_fold_mod(ast::Mod {
- inner: inner,
- view_items: view_items,
- items: items
- }, self)
- }
-}
-
-fn inject_prelude(_: &Session, krate: ast::Crate) -> ast::Crate {
- let mut fold = PreludeInjector;
- fold.fold_crate(krate)
-}
+++ /dev/null
-// Copyright 2012-2014 The Rust Project Developers. See the COPYRIGHT
-// file at the top-level directory of this distribution and at
-// http://rust-lang.org/COPYRIGHT.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-// Code that generates a test runner to run all the tests in a crate
-
-#![allow(dead_code)]
-#![allow(unused_imports)]
-
-use driver::session::Session;
-use front::config;
-
-use std::slice;
-use std::mem;
-use std::vec;
-use syntax::{ast, ast_util};
-use syntax::ast_util::*;
-use syntax::attr::AttrMetaMethods;
-use syntax::attr;
-use syntax::codemap::{DUMMY_SP, Span, ExpnInfo, NameAndSpan, MacroAttribute};
-use syntax::codemap;
-use syntax::ext::base::ExtCtxt;
-use syntax::ext::build::AstBuilder;
-use syntax::ext::expand::ExpansionConfig;
-use syntax::fold::{Folder, MoveMap};
-use syntax::fold;
-use syntax::owned_slice::OwnedSlice;
-use syntax::parse::token::InternedString;
-use syntax::parse::token;
-use syntax::print::pprust;
-use syntax::ptr::P;
-use syntax::util::small_vector::SmallVector;
-
-struct Test {
- span: Span,
- path: Vec<ast::Ident> ,
- bench: bool,
- ignore: bool,
- should_fail: bool
-}
-
-struct TestCtxt<'a> {
- sess: &'a Session,
- path: Vec<ast::Ident>,
- ext_cx: ExtCtxt<'a>,
- testfns: Vec<Test>,
- reexport_test_harness_main: Option<InternedString>,
- is_test_crate: bool,
- config: ast::CrateConfig,
-
- // top-level re-export submodule, filled out after folding is finished
- toplevel_reexport: Option<ast::Ident>,
-}
-
-// Traverse the crate, collecting all the test functions, eliding any
-// existing main functions, and synthesizing a main test harness
-pub fn modify_for_testing(sess: &Session,
- krate: ast::Crate) -> ast::Crate {
- // We generate the test harness when building in the 'test'
- // configuration, either with the '--test' or '--cfg test'
- // command line options.
- let should_test = attr::contains_name(krate.config.as_slice(), "test");
-
- // Check for #[reexport_test_harness_main = "some_name"] which
- // creates a `use some_name = __test::main;`. This needs to be
- // unconditional, so that the attribute is still marked as used in
- // non-test builds.
- let reexport_test_harness_main =
- attr::first_attr_value_str_by_name(krate.attrs.as_slice(),
- "reexport_test_harness_main");
-
- if should_test {
- generate_test_harness(sess, reexport_test_harness_main, krate)
- } else {
- strip_test_functions(krate)
- }
-}
-
-struct TestHarnessGenerator<'a> {
- cx: TestCtxt<'a>,
- tests: Vec<ast::Ident>,
-
- // submodule name, gensym'd identifier for re-exports
- tested_submods: Vec<(ast::Ident, ast::Ident)>,
-}
-
-impl<'a> fold::Folder for TestHarnessGenerator<'a> {
- fn fold_crate(&mut self, c: ast::Crate) -> ast::Crate {
- let mut folded = fold::noop_fold_crate(c, self);
-
- // Add a special __test module to the crate that will contain code
- // generated for the test harness
- let (mod_, reexport) = mk_test_module(&mut self.cx);
- folded.module.items.push(mod_);
- match reexport {
- Some(re) => folded.module.view_items.push(re),
- None => {}
- }
- folded
- }
-
- fn fold_item(&mut self, i: P<ast::Item>) -> SmallVector<P<ast::Item>> {
- self.cx.path.push(i.ident);
- debug!("current path: {}",
- ast_util::path_name_i(self.cx.path.as_slice()));
-
- if is_test_fn(&self.cx, &*i) || is_bench_fn(&self.cx, &*i) {
- match i.node {
- ast::ItemFn(_, ast::UnsafeFn, _, _, _) => {
- let sess = self.cx.sess;
- sess.span_fatal(i.span,
- "unsafe functions cannot be used for \
- tests");
- }
- _ => {
- debug!("this is a test function");
- let test = Test {
- span: i.span,
- path: self.cx.path.clone(),
- bench: is_bench_fn(&self.cx, &*i),
- ignore: is_ignored(&self.cx, &*i),
- should_fail: should_fail(&*i)
- };
- self.cx.testfns.push(test);
- self.tests.push(i.ident);
- // debug!("have {} test/bench functions",
- // cx.testfns.len());
- }
- }
- }
-
- // We don't want to recurse into anything other than mods, since
- // mods or tests inside of functions will break things
- let res = match i.node {
- ast::ItemMod(..) => fold::noop_fold_item(i, self),
- _ => SmallVector::one(i),
- };
- self.cx.path.pop();
- res
- }
-
- fn fold_mod(&mut self, m: ast::Mod) -> ast::Mod {
- let tests = mem::replace(&mut self.tests, Vec::new());
- let tested_submods = mem::replace(&mut self.tested_submods, Vec::new());
- let mut mod_folded = fold::noop_fold_mod(m, self);
- let tests = mem::replace(&mut self.tests, tests);
- let tested_submods = mem::replace(&mut self.tested_submods, tested_submods);
-
- // Remove any #[main] from the AST so it doesn't clash with
- // the one we're going to add. Only if compiling an executable.
-
- mod_folded.items = mem::replace(&mut mod_folded.items, vec![]).move_map(|item| {
- item.map(|ast::Item {id, ident, attrs, node, vis, span}| {
- ast::Item {
- id: id,
- ident: ident,
- attrs: attrs.into_iter().filter_map(|attr| {
- if !attr.check_name("main") {
- Some(attr)
- } else {
- None
- }
- }).collect(),
- node: node,
- vis: vis,
- span: span
- }
- })
- });
-
- if !tests.is_empty() || !tested_submods.is_empty() {
- let (it, sym) = mk_reexport_mod(&mut self.cx, tests, tested_submods);
- mod_folded.items.push(it);
-
- if !self.cx.path.is_empty() {
- self.tested_submods.push((self.cx.path[self.cx.path.len()-1], sym));
- } else {
- debug!("pushing nothing, sym: {}", sym);
- self.cx.toplevel_reexport = Some(sym);
- }
- }
-
- mod_folded
- }
-}
-
-fn mk_reexport_mod(cx: &mut TestCtxt, tests: Vec<ast::Ident>,
- tested_submods: Vec<(ast::Ident, ast::Ident)>) -> (P<ast::Item>, ast::Ident) {
- let mut view_items = Vec::new();
- let super_ = token::str_to_ident("super");
-
- view_items.extend(tests.into_iter().map(|r| {
- cx.ext_cx.view_use_simple(DUMMY_SP, ast::Public,
- cx.ext_cx.path(DUMMY_SP, vec![super_, r]))
- }));
- view_items.extend(tested_submods.into_iter().map(|(r, sym)| {
- let path = cx.ext_cx.path(DUMMY_SP, vec![super_, r, sym]);
- cx.ext_cx.view_use_simple_(DUMMY_SP, ast::Public, r, path)
- }));
-
- let reexport_mod = ast::Mod {
- inner: DUMMY_SP,
- view_items: view_items,
- items: Vec::new(),
- };
-
- let sym = token::gensym_ident("__test_reexports");
- let it = P(ast::Item {
- ident: sym.clone(),
- attrs: Vec::new(),
- id: ast::DUMMY_NODE_ID,
- node: ast::ItemMod(reexport_mod),
- vis: ast::Public,
- span: DUMMY_SP,
- });
-
- (it, sym)
-}
-
-fn generate_test_harness(sess: &Session,
- reexport_test_harness_main: Option<InternedString>,
- krate: ast::Crate) -> ast::Crate {
- let mut cx: TestCtxt = TestCtxt {
- sess: sess,
- ext_cx: ExtCtxt::new(&sess.parse_sess, sess.opts.cfg.clone(),
- ExpansionConfig {
- deriving_hash_type_parameter: false,
- crate_name: "test".to_string(),
- }),
- path: Vec::new(),
- testfns: Vec::new(),
- reexport_test_harness_main: reexport_test_harness_main,
- is_test_crate: is_test_crate(&krate),
- config: krate.config.clone(),
- toplevel_reexport: None,
- };
-
- cx.ext_cx.bt_push(ExpnInfo {
- call_site: DUMMY_SP,
- callee: NameAndSpan {
- name: "test".to_string(),
- format: MacroAttribute,
- span: None
- }
- });
-
- let mut fold = TestHarnessGenerator {
- cx: cx,
- tests: Vec::new(),
- tested_submods: Vec::new(),
- };
- let res = fold.fold_crate(krate);
- fold.cx.ext_cx.bt_pop();
- return res;
-}
-
-fn strip_test_functions(krate: ast::Crate) -> ast::Crate {
- // When not compiling with --test we should not compile the
- // #[test] functions
- config::strip_items(krate, |attrs| {
- !attr::contains_name(attrs.as_slice(), "test") &&
- !attr::contains_name(attrs.as_slice(), "bench")
- })
-}
-
-fn is_test_fn(cx: &TestCtxt, i: &ast::Item) -> bool {
- let has_test_attr = attr::contains_name(i.attrs.as_slice(), "test");
-
- fn has_test_signature(i: &ast::Item) -> bool {
- match &i.node {
- &ast::ItemFn(ref decl, _, _, ref generics, _) => {
- let no_output = match decl.output.node {
- ast::TyNil => true,
- _ => false
- };
- decl.inputs.is_empty()
- && no_output
- && !generics.is_parameterized()
- }
- _ => false
- }
- }
-
- if has_test_attr && !has_test_signature(i) {
- let sess = cx.sess;
- sess.span_err(
- i.span,
- "functions used as tests must have signature fn() -> ()."
- );
- }
-
- return has_test_attr && has_test_signature(i);
-}
-
-fn is_bench_fn(cx: &TestCtxt, i: &ast::Item) -> bool {
- let has_bench_attr = attr::contains_name(i.attrs.as_slice(), "bench");
-
- fn has_test_signature(i: &ast::Item) -> bool {
- match i.node {
- ast::ItemFn(ref decl, _, _, ref generics, _) => {
- let input_cnt = decl.inputs.len();
- let no_output = match decl.output.node {
- ast::TyNil => true,
- _ => false
- };
- let tparm_cnt = generics.ty_params.len();
- // NB: inadequate check, but we're running
- // well before resolve, can't get too deep.
- input_cnt == 1u
- && no_output && tparm_cnt == 0u
- }
- _ => false
- }
- }
-
- if has_bench_attr && !has_test_signature(i) {
- let sess = cx.sess;
- sess.span_err(i.span, "functions used as benches must have signature \
- `fn(&mut Bencher) -> ()`");
- }
-
- return has_bench_attr && has_test_signature(i);
-}
-
-fn is_ignored(cx: &TestCtxt, i: &ast::Item) -> bool {
- i.attrs.iter().any(|attr| {
- // check ignore(cfg(foo, bar))
- attr.check_name("ignore") && match attr.meta_item_list() {
- Some(ref cfgs) => {
- attr::test_cfg(cx.config.as_slice(), cfgs.iter())
- }
- None => true
- }
- })
-}
-
-fn should_fail(i: &ast::Item) -> bool {
- attr::contains_name(i.attrs.as_slice(), "should_fail")
-}
-
-/*
-
-We're going to be building a module that looks more or less like:
-
-mod __test {
- extern crate test (name = "test", vers = "...");
- fn main() {
- test::test_main_static(::os::args().as_slice(), tests)
- }
-
- static tests : &'static [test::TestDescAndFn] = &[
- ... the list of tests in the crate ...
- ];
-}
-
-*/
-
-fn mk_std(cx: &TestCtxt) -> ast::ViewItem {
- let id_test = token::str_to_ident("test");
- let (vi, vis) = if cx.is_test_crate {
- (ast::ViewItemUse(
- P(nospan(ast::ViewPathSimple(id_test,
- path_node(vec!(id_test)),
- ast::DUMMY_NODE_ID)))),
- ast::Public)
- } else {
- (ast::ViewItemExternCrate(id_test, None, ast::DUMMY_NODE_ID),
- ast::Inherited)
- };
- ast::ViewItem {
- node: vi,
- attrs: Vec::new(),
- vis: vis,
- span: DUMMY_SP
- }
-}
-
-fn mk_test_module(cx: &mut TestCtxt) -> (P<ast::Item>, Option<ast::ViewItem>) {
- // Link to test crate
- let view_items = vec!(mk_std(cx));
-
- // A constant vector of test descriptors.
- let tests = mk_tests(cx);
-
- // 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::Slice;
- test::test_main_static(::std::os::args().as_slice(), TESTS);
- }
- )).unwrap();
-
- let testmod = ast::Mod {
- inner: DUMMY_SP,
- view_items: view_items,
- items: vec!(mainfn, tests),
- };
- let item_ = ast::ItemMod(testmod);
-
- let mod_ident = token::gensym_ident("__test");
- let item = ast::Item {
- ident: mod_ident,
- attrs: Vec::new(),
- id: ast::DUMMY_NODE_ID,
- node: item_,
- vis: ast::Public,
- span: DUMMY_SP,
- };
- let reexport = cx.reexport_test_harness_main.as_ref().map(|s| {
- // building `use <ident> = __test::main`
- let reexport_ident = token::str_to_ident(s.get());
-
- let use_path =
- nospan(ast::ViewPathSimple(reexport_ident,
- path_node(vec![mod_ident, token::str_to_ident("main")]),
- ast::DUMMY_NODE_ID));
-
- ast::ViewItem {
- node: ast::ViewItemUse(P(use_path)),
- attrs: vec![],
- vis: ast::Inherited,
- span: DUMMY_SP
- }
- });
-
- debug!("Synthetic test module:\n{}\n", pprust::item_to_string(&item));
-
- (P(item), reexport)
-}
-
-fn nospan<T>(t: T) -> codemap::Spanned<T> {
- codemap::Spanned { node: t, span: DUMMY_SP }
-}
-
-fn path_node(ids: Vec<ast::Ident> ) -> ast::Path {
- ast::Path {
- span: DUMMY_SP,
- global: false,
- segments: ids.into_iter().map(|identifier| ast::PathSegment {
- identifier: identifier,
- lifetimes: Vec::new(),
- types: OwnedSlice::empty(),
- }).collect()
- }
-}
-
-fn mk_tests(cx: &TestCtxt) -> P<ast::Item> {
- // The vector of test_descs for this crate
- let test_descs = mk_test_descs(cx);
-
- // FIXME #15962: should be using quote_item, but that stringifies
- // __test_reexports, causing it to be reinterned, losing the
- // gensym information.
- let sp = DUMMY_SP;
- let ecx = &cx.ext_cx;
- let struct_type = ecx.ty_path(ecx.path(sp, vec![ecx.ident_of("self"),
- ecx.ident_of("test"),
- ecx.ident_of("TestDescAndFn")]),
- None);
- let static_lt = ecx.lifetime(sp, token::special_idents::static_lifetime.name);
- // &'static [self::test::TestDescAndFn]
- let static_type = ecx.ty_rptr(sp,
- ecx.ty(sp, ast::TyVec(struct_type)),
- Some(static_lt),
- ast::MutImmutable);
- // static TESTS: $static_type = &[...];
- ecx.item_static(sp,
- ecx.ident_of("TESTS"),
- static_type,
- ast::MutImmutable,
- test_descs)
-}
-
-fn is_test_crate(krate: &ast::Crate) -> bool {
- match attr::find_crate_name(krate.attrs.as_slice()) {
- Some(ref s) if "test" == s.get().as_slice() => true,
- _ => false
- }
-}
-
-fn mk_test_descs(cx: &TestCtxt) -> P<ast::Expr> {
- debug!("building test vector from {} tests", cx.testfns.len());
-
- P(ast::Expr {
- id: ast::DUMMY_NODE_ID,
- node: ast::ExprAddrOf(ast::MutImmutable,
- P(ast::Expr {
- id: ast::DUMMY_NODE_ID,
- node: ast::ExprVec(cx.testfns.iter().map(|test| {
- mk_test_desc_and_fn_rec(cx, test)
- }).collect()),
- span: DUMMY_SP,
- })),
- span: DUMMY_SP,
- })
-}
-
-fn mk_test_desc_and_fn_rec(cx: &TestCtxt, test: &Test) -> P<ast::Expr> {
- // FIXME #15962: should be using quote_expr, but that stringifies
- // __test_reexports, causing it to be reinterned, losing the
- // gensym information.
-
- let span = test.span;
- let path = test.path.clone();
- let ecx = &cx.ext_cx;
- let self_id = ecx.ident_of("self");
- let test_id = ecx.ident_of("test");
-
- // creates self::test::$name
- let test_path = |name| {
- ecx.path(span, vec![self_id, test_id, ecx.ident_of(name)])
- };
- // creates $name: $expr
- let field = |name, expr| ecx.field_imm(span, ecx.ident_of(name), expr);
-
- debug!("encoding {}", ast_util::path_name_i(path.as_slice()));
-
- // path to the #[test] function: "foo::bar::baz"
- let path_string = ast_util::path_name_i(path.as_slice());
- let name_expr = ecx.expr_str(span, token::intern_and_get_ident(path_string.as_slice()));
-
- // self::test::StaticTestName($name_expr)
- let name_expr = ecx.expr_call(span,
- ecx.expr_path(test_path("StaticTestName")),
- vec![name_expr]);
-
- let ignore_expr = ecx.expr_bool(span, test.ignore);
- let fail_expr = ecx.expr_bool(span, test.should_fail);
-
- // self::test::TestDesc { ... }
- let desc_expr = ecx.expr_struct(
- span,
- test_path("TestDesc"),
- vec![field("name", name_expr),
- field("ignore", ignore_expr),
- field("should_fail", fail_expr)]);
-
-
- let mut visible_path = match cx.toplevel_reexport {
- Some(id) => vec![id],
- None => {
- cx.sess.bug(
- "expected to find top-level re-export name, but found None"
- );
- }
- };
- visible_path.extend(path.into_iter());
-
- let fn_expr = ecx.expr_path(ecx.path_global(span, visible_path));
-
- let variant_name = if test.bench { "StaticBenchFn" } else { "StaticTestFn" };
- // self::test::$variant_name($fn_expr)
- let testfn_expr = ecx.expr_call(span, ecx.expr_path(test_path(variant_name)), vec![fn_expr]);
-
- // self::test::TestDescAndFn { ... }
- ecx.expr_struct(span,
- test_path("TestDescAndFn"),
- vec![field("desc", desc_expr),
- field("testfn", testfn_expr)])
-}
pub mod weak_lang_items;
}
-pub mod front {
- pub mod config;
- pub mod test;
- pub mod std_inject;
- pub mod feature_gate;
- pub mod show_span;
-}
-
pub mod metadata;
pub mod driver;
}
}
+declare_lint!(UNNECESSARY_IMPORT_BRACES, Allow,
+ "unnecessary braces around an imported item")
+
+pub struct UnnecessaryImportBraces;
+
+impl LintPass for UnnecessaryImportBraces {
+ fn get_lints(&self) -> LintArray {
+ lint_array!(UNNECESSARY_IMPORT_BRACES)
+ }
+
+ fn check_view_item(&mut self, cx: &Context, view_item: &ast::ViewItem) {
+ match view_item.node {
+ ast::ViewItemUse(ref view_path) => {
+ match view_path.node {
+ ast::ViewPathList(_, ref items, _) => {
+ if items.len() == 1 {
+ match items[0].node {
+ ast::PathListIdent {ref name, ..} => {
+ let m = format!("braces around {} is unnecessary",
+ token::get_ident(*name).get());
+ cx.span_lint(UNNECESSARY_IMPORT_BRACES, view_item.span,
+ m.as_slice());
+ },
+ _ => ()
+ }
+ }
+ }
+ _ => ()
+ }
+ },
+ _ => ()
+ }
+ }
+}
+
declare_lint!(UNUSED_UNSAFE, Warn,
"unnecessary use of an `unsafe` block")
NonSnakeCase,
NonUppercaseStatics,
UnnecessaryParens,
+ UnnecessaryImportBraces,
UnusedUnsafe,
UnsafeBlock,
UnusedMut,
import_span: Span,
name: Name,
namespace: Namespace) {
- if self.session.features.import_shadowing.get() {
+ if self.session.features.borrow().import_shadowing {
return
}
&mut ImportResolution,
import_span: Span,
name: Name) {
- if self.session.features.import_shadowing.get() {
+ if self.session.features.borrow().import_shadowing {
return
}
module: &Module,
name: Name,
span: Span) {
- if self.session.features.import_shadowing.get() {
+ if self.session.features.borrow().import_shadowing {
return
}
module: &Module,
name: Name,
span: Span) {
- if self.session.features.import_shadowing.get() {
+ if self.session.features.borrow().import_shadowing {
return
}
// Codegen the body.
body_bcx_out = trans_block(body_bcx_out, body, expr::Ignore);
- body_bcx_out.fcx.pop_custom_cleanup_scope(binding_cleanup_scope);
+ body_bcx_out =
+ body_bcx_out.fcx
+ .pop_and_trans_custom_cleanup_scope(body_bcx_out,
+ binding_cleanup_scope);
body_bcx_out =
body_bcx_out.fcx
.pop_and_trans_custom_cleanup_scope(body_bcx_out,
ty_enum(id, _) => format!("enum {}", item_path_str(cx, id)),
ty_box(_) => "Gc-ptr".to_string(),
ty_uniq(_) => "box".to_string(),
- ty_vec(_, _) => "vector".to_string(),
+ ty_vec(_, Some(_)) => "array".to_string(),
+ ty_vec(_, None) => "unsized array".to_string(),
ty_ptr(_) => "*-ptr".to_string(),
ty_rptr(_, _) => "&-ptr".to_string(),
ty_bare_fn(_) => "extern fn".to_string(),
}
if supplied_ty_param_count > required_ty_param_count
- && !this.tcx().sess.features.default_type_params.get() {
+ && !this.tcx().sess.features.borrow().default_type_params {
span_err!(this.tcx().sess, path.span, E0108,
"default type parameters are experimental and possibly buggy");
span_note!(this.tcx().sess, path.span,
fcx.inh.method_map.borrow_mut().insert(method_call, method_callee);
write_call(fcx, call_expression, output_type);
- if !fcx.tcx().sess.features.overloaded_calls.get() {
+ if !fcx.tcx().sess.features.borrow().overloaded_calls {
span_err!(fcx.tcx().sess, call_expression.span, E0056,
"overloaded calls are experimental");
span_note!(fcx.tcx().sess, call_expression.span,
$(".method").each(function() {
if ($(this).next().is(".docblock")) {
- $(this).children().first().after(toggle[0]);
+ $(this).children().first().after(toggle.clone());
}
});
}
/// Returns `true` all of the flags in `other` are contained within `self`.
+ #[inline]
pub fn contains(&self, other: $BitFlags) -> bool {
(self & other) == other
}
--- /dev/null
+// Copyright 2012-2014 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+use fold::Folder;
+use {ast, fold, attr};
+use codemap::Spanned;
+use ptr::P;
+
+/// A folder that strips out items that do not belong in the current
+/// configuration.
+struct Context<'a> {
+ in_cfg: |attrs: &[ast::Attribute]|: 'a -> bool,
+}
+
+// Support conditional compilation by transforming the AST, stripping out
+// any items that do not belong in the current configuration
+pub fn strip_unconfigured_items(krate: ast::Crate) -> ast::Crate {
+ let config = krate.config.clone();
+ strip_items(krate, |attrs| in_cfg(config.as_slice(), attrs))
+}
+
+impl<'a> fold::Folder for Context<'a> {
+ fn fold_mod(&mut self, module: ast::Mod) -> ast::Mod {
+ fold_mod(self, module)
+ }
+ fn fold_block(&mut self, block: P<ast::Block>) -> P<ast::Block> {
+ fold_block(self, block)
+ }
+ fn fold_foreign_mod(&mut self, foreign_mod: ast::ForeignMod) -> ast::ForeignMod {
+ fold_foreign_mod(self, foreign_mod)
+ }
+ fn fold_item_underscore(&mut self, item: ast::Item_) -> ast::Item_ {
+ fold_item_underscore(self, item)
+ }
+ fn fold_expr(&mut self, expr: P<ast::Expr>) -> P<ast::Expr> {
+ fold_expr(self, expr)
+ }
+ fn fold_mac(&mut self, mac: ast::Mac) -> ast::Mac {
+ fold::noop_fold_mac(mac, self)
+ }
+}
+
+pub fn strip_items(krate: ast::Crate,
+ in_cfg: |attrs: &[ast::Attribute]| -> bool)
+ -> ast::Crate {
+ let mut ctxt = Context {
+ in_cfg: in_cfg,
+ };
+ ctxt.fold_crate(krate)
+}
+
+fn filter_view_item(cx: &mut Context, view_item: ast::ViewItem) -> Option<ast::ViewItem> {
+ if view_item_in_cfg(cx, &view_item) {
+ Some(view_item)
+ } else {
+ None
+ }
+}
+
+fn fold_mod(cx: &mut Context, ast::Mod {inner, view_items, items}: ast::Mod) -> ast::Mod {
+ ast::Mod {
+ inner: inner,
+ view_items: view_items.into_iter().filter_map(|a| {
+ filter_view_item(cx, a).map(|x| cx.fold_view_item(x))
+ }).collect(),
+ items: items.into_iter().filter_map(|a| {
+ if item_in_cfg(cx, &*a) {
+ Some(cx.fold_item(a))
+ } else {
+ None
+ }
+ }).flat_map(|x| x.into_iter()).collect()
+ }
+}
+
+fn filter_foreign_item(cx: &mut Context, item: P<ast::ForeignItem>)
+ -> Option<P<ast::ForeignItem>> {
+ if foreign_item_in_cfg(cx, &*item) {
+ Some(item)
+ } else {
+ None
+ }
+}
+
+fn fold_foreign_mod(cx: &mut Context, ast::ForeignMod {abi, view_items, items}: ast::ForeignMod)
+ -> ast::ForeignMod {
+ ast::ForeignMod {
+ abi: abi,
+ view_items: view_items.into_iter().filter_map(|a| {
+ filter_view_item(cx, a).map(|x| cx.fold_view_item(x))
+ }).collect(),
+ items: items.into_iter()
+ .filter_map(|a| filter_foreign_item(cx, a))
+ .collect()
+ }
+}
+
+fn fold_item_underscore(cx: &mut Context, item: ast::Item_) -> ast::Item_ {
+ let item = match item {
+ ast::ItemImpl(a, b, c, impl_items) => {
+ let impl_items = impl_items.into_iter()
+ .filter(|ii| impl_item_in_cfg(cx, ii))
+ .collect();
+ ast::ItemImpl(a, b, c, impl_items)
+ }
+ ast::ItemTrait(a, b, c, methods) => {
+ let methods = methods.into_iter()
+ .filter(|m| trait_method_in_cfg(cx, m))
+ .collect();
+ ast::ItemTrait(a, b, c, methods)
+ }
+ ast::ItemStruct(def, generics) => {
+ ast::ItemStruct(fold_struct(cx, def), generics)
+ }
+ ast::ItemEnum(def, generics) => {
+ let mut variants = def.variants.into_iter().filter_map(|v| {
+ if !(cx.in_cfg)(v.node.attrs.as_slice()) {
+ None
+ } else {
+ Some(v.map(|Spanned {node: ast::Variant_ {id, name, attrs, kind,
+ disr_expr, vis}, span}| {
+ Spanned {
+ node: ast::Variant_ {
+ id: id,
+ name: name,
+ attrs: attrs,
+ kind: match kind {
+ ast::TupleVariantKind(..) => kind,
+ ast::StructVariantKind(def) => {
+ ast::StructVariantKind(fold_struct(cx, def))
+ }
+ },
+ disr_expr: disr_expr,
+ vis: vis
+ },
+ span: span
+ }
+ }))
+ }
+ });
+ ast::ItemEnum(ast::EnumDef {
+ variants: variants.collect(),
+ }, generics)
+ }
+ item => item,
+ };
+
+ fold::noop_fold_item_underscore(item, cx)
+}
+
+fn fold_struct(cx: &mut Context, def: P<ast::StructDef>) -> P<ast::StructDef> {
+ def.map(|ast::StructDef {fields, ctor_id, super_struct, is_virtual}| {
+ ast::StructDef {
+ fields: fields.into_iter().filter(|m| {
+ (cx.in_cfg)(m.node.attrs.as_slice())
+ }).collect(),
+ ctor_id: ctor_id,
+ super_struct: super_struct,
+ is_virtual: is_virtual,
+ }
+ })
+}
+
+fn retain_stmt(cx: &mut Context, stmt: &ast::Stmt) -> bool {
+ match stmt.node {
+ ast::StmtDecl(ref decl, _) => {
+ match decl.node {
+ ast::DeclItem(ref item) => {
+ item_in_cfg(cx, &**item)
+ }
+ _ => true
+ }
+ }
+ _ => true
+ }
+}
+
+fn fold_block(cx: &mut Context, b: P<ast::Block>) -> P<ast::Block> {
+ b.map(|ast::Block {id, view_items, stmts, expr, rules, span}| {
+ let resulting_stmts: Vec<P<ast::Stmt>> =
+ stmts.into_iter().filter(|a| retain_stmt(cx, &**a)).collect();
+ let resulting_stmts = resulting_stmts.into_iter()
+ .flat_map(|stmt| cx.fold_stmt(stmt).into_iter())
+ .collect();
+ let filtered_view_items = view_items.into_iter().filter_map(|a| {
+ filter_view_item(cx, a).map(|x| cx.fold_view_item(x))
+ }).collect();
+ ast::Block {
+ id: id,
+ view_items: filtered_view_items,
+ stmts: resulting_stmts,
+ expr: expr.map(|x| cx.fold_expr(x)),
+ rules: rules,
+ span: span,
+ }
+ })
+}
+
+fn fold_expr(cx: &mut Context, expr: P<ast::Expr>) -> P<ast::Expr> {
+ expr.map(|ast::Expr {id, span, node}| {
+ fold::noop_fold_expr(ast::Expr {
+ id: id,
+ node: match node {
+ ast::ExprMatch(m, arms) => {
+ ast::ExprMatch(m, arms.into_iter()
+ .filter(|a| (cx.in_cfg)(a.attrs.as_slice()))
+ .collect())
+ }
+ _ => node
+ },
+ span: span
+ }, cx)
+ })
+}
+
+fn item_in_cfg(cx: &mut Context, item: &ast::Item) -> bool {
+ return (cx.in_cfg)(item.attrs.as_slice());
+}
+
+fn foreign_item_in_cfg(cx: &mut Context, item: &ast::ForeignItem) -> bool {
+ return (cx.in_cfg)(item.attrs.as_slice());
+}
+
+fn view_item_in_cfg(cx: &mut Context, item: &ast::ViewItem) -> bool {
+ return (cx.in_cfg)(item.attrs.as_slice());
+}
+
+fn trait_method_in_cfg(cx: &mut Context, meth: &ast::TraitItem) -> bool {
+ match *meth {
+ ast::RequiredMethod(ref meth) => (cx.in_cfg)(meth.attrs.as_slice()),
+ ast::ProvidedMethod(ref meth) => (cx.in_cfg)(meth.attrs.as_slice())
+ }
+}
+
+fn impl_item_in_cfg(cx: &mut Context, impl_item: &ast::ImplItem) -> bool {
+ match *impl_item {
+ ast::MethodImplItem(ref meth) => (cx.in_cfg)(meth.attrs.as_slice()),
+ }
+}
+
+// Determine if an item should be translated in the current crate
+// configuration based on the item's attributes
+fn in_cfg(cfg: &[P<ast::MetaItem>], attrs: &[ast::Attribute]) -> bool {
+ attr::test_cfg(cfg, attrs.iter())
+}
+
--- /dev/null
+// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+//! Feature gating
+//!
+//! This modules implements the gating necessary for preventing certain compiler
+//! features from being used by default. This module will crawl a pre-expanded
+//! AST to ensure that there are no features which are used that are not
+//! enabled.
+//!
+//! Features are enabled in programs via the crate-level attributes of
+//! `#![feature(...)]` with a comma-separated list of features.
+
+use abi::RustIntrinsic;
+use ast::NodeId;
+use ast;
+use attr;
+use attr::AttrMetaMethods;
+use codemap::Span;
+use diagnostic::SpanHandler;
+use visit;
+use visit::Visitor;
+use parse::token;
+
+use std::slice;
+
+/// This is a list of all known features since the beginning of time. This list
+/// can never shrink, it may only be expanded (in order to prevent old programs
+/// from failing to compile). The status of each feature may change, however.
+static KNOWN_FEATURES: &'static [(&'static str, Status)] = &[
+ ("globs", Active),
+ ("macro_rules", Active),
+ ("struct_variant", Active),
+ ("once_fns", Active),
+ ("asm", Active),
+ ("managed_boxes", Active),
+ ("non_ascii_idents", Active),
+ ("thread_local", Active),
+ ("link_args", Active),
+ ("phase", Active),
+ ("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", Active),
+ ("quote", Active),
+ ("linkage", Active),
+ ("struct_inherit", Active),
+ ("overloaded_calls", Active),
+ ("unboxed_closure_sugar", Active),
+
+ ("quad_precision_float", Removed),
+
+ ("rustc_diagnostic_macros", Active),
+ ("unboxed_closures", Active),
+ ("import_shadowing", Active),
+ ("advanced_slice_patterns", Active),
+ ("tuple_indexing", Active),
+
+ // if you change this list without updating src/doc/rust.md, cmr will be sad
+
+ // A temporary feature gate used to enable parser extensions needed
+ // to bootstrap fix for #5723.
+ ("issue_5723_bootstrap", Accepted),
+
+ // These are used to test this portion of the compiler, they don't actually
+ // mean anything
+ ("test_accepted_feature", Accepted),
+ ("test_removed_feature", Removed),
+];
+
+enum Status {
+ /// Represents an active feature that is currently being implemented or
+ /// currently being considered for addition/removal.
+ Active,
+
+ /// Represents a feature which has since been removed (it was once Active)
+ Removed,
+
+ /// This language feature has since been Accepted (it was once Active)
+ Accepted,
+}
+
+/// A set of features to be used by later passes.
+pub struct Features {
+ pub default_type_params: bool,
+ pub overloaded_calls: bool,
+ pub rustc_diagnostic_macros: bool,
+ pub import_shadowing: bool,
+}
+
+impl Features {
+ pub fn new() -> Features {
+ Features {
+ default_type_params: false,
+ overloaded_calls: false,
+ rustc_diagnostic_macros: false,
+ import_shadowing: false,
+ }
+ }
+}
+
+struct Context<'a> {
+ features: Vec<&'static str>,
+ span_handler: &'a SpanHandler,
+}
+
+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_note(span, format!("add #![feature({})] to the \
+ crate attributes to enable",
+ feature).as_slice());
+ }
+ }
+
+ fn gate_box(&self, span: Span) {
+ self.gate_feature("managed_boxes", span,
+ "The managed box syntax is being replaced by the \
+ `std::gc::Gc` and `std::rc::Rc` types. Equivalent \
+ functionality to managed trait objects will be \
+ implemented but is currently missing.");
+ }
+
+ fn has_feature(&self, feature: &str) -> bool {
+ self.features.iter().any(|n| n.as_slice() == feature)
+ }
+}
+
+impl<'a, 'v> Visitor<'v> for Context<'a> {
+ fn visit_ident(&mut self, sp: Span, id: ast::Ident) {
+ if !token::get_ident(id).get().is_ascii() {
+ self.gate_feature("non_ascii_idents", sp,
+ "non-ascii idents are not fully supported.");
+ }
+ }
+
+ fn visit_view_item(&mut self, i: &ast::ViewItem) {
+ match i.node {
+ ast::ViewItemUse(ref path) => {
+ match path.node {
+ ast::ViewPathGlob(..) => {
+ self.gate_feature("globs", path.span,
+ "glob import statements are \
+ experimental and possibly buggy");
+ }
+ _ => {}
+ }
+ }
+ ast::ViewItemExternCrate(..) => {
+ for attr in i.attrs.iter() {
+ if attr.name().get() == "phase"{
+ self.gate_feature("phase", attr.span,
+ "compile time crate loading is \
+ experimental and possibly buggy");
+ }
+ }
+ }
+ }
+ visit::walk_view_item(self, i)
+ }
+
+ fn visit_item(&mut self, i: &ast::Item) {
+ for attr in i.attrs.iter() {
+ if attr.name().equiv(&("thread_local")) {
+ self.gate_feature("thread_local", i.span,
+ "`#[thread_local]` is an experimental feature, and does not \
+ currently handle destructors. There is no corresponding \
+ `#[task_local]` mapping to the task model");
+ }
+ }
+ match i.node {
+ ast::ItemEnum(ref def, _) => {
+ for variant in def.variants.iter() {
+ match variant.node.kind {
+ ast::StructVariantKind(..) => {
+ self.gate_feature("struct_variant", variant.span,
+ "enum struct variants are \
+ experimental and possibly buggy");
+ }
+ _ => {}
+ }
+ }
+ }
+
+ ast::ItemForeignMod(ref foreign_module) => {
+ if attr::contains_name(i.attrs.as_slice(), "link_args") {
+ self.gate_feature("link_args", i.span,
+ "the `link_args` attribute is not portable \
+ across platforms, it is recommended to \
+ use `#[link(name = \"foo\")]` instead")
+ }
+ if foreign_module.abi == RustIntrinsic {
+ self.gate_feature("intrinsics",
+ i.span,
+ "intrinsics are subject to change")
+ }
+ }
+
+ ast::ItemFn(..) => {
+ if attr::contains_name(i.attrs.as_slice(), "plugin_registrar") {
+ self.gate_feature("plugin_registrar", i.span,
+ "compiler plugins are experimental and possibly buggy");
+ }
+ }
+
+ ast::ItemStruct(ref struct_definition, _) => {
+ if attr::contains_name(i.attrs.as_slice(), "simd") {
+ self.gate_feature("simd", i.span,
+ "SIMD types are experimental and possibly buggy");
+ }
+ match struct_definition.super_struct {
+ Some(ref path) => self.gate_feature("struct_inherit", path.span,
+ "struct inheritance is experimental \
+ and possibly buggy"),
+ None => {}
+ }
+ if struct_definition.is_virtual {
+ self.gate_feature("struct_inherit", i.span,
+ "struct inheritance (`virtual` keyword) is \
+ experimental and possibly buggy");
+ }
+ }
+
+ ast::ItemImpl(..) => {
+ if attr::contains_name(i.attrs.as_slice(),
+ "unsafe_destructor") {
+ self.gate_feature("unsafe_destructor",
+ i.span,
+ "`#[unsafe_destructor]` allows too \
+ many unsafe patterns and may be \
+ removed in the future");
+ }
+ }
+
+ _ => {}
+ }
+
+ visit::walk_item(self, i);
+ }
+
+ fn visit_mac(&mut self, macro: &ast::Mac) {
+ let ast::MacInvocTT(ref path, _, _) = macro.node;
+ let id = path.segments.last().unwrap().identifier;
+ let quotes = ["quote_tokens", "quote_expr", "quote_ty",
+ "quote_item", "quote_pat", "quote_stmt"];
+ let msg = " is not stable enough for use and are subject to change";
+
+
+ if id == token::str_to_ident("macro_rules") {
+ self.gate_feature("macro_rules", path.span, "macro definitions are \
+ not stable enough for use and are subject to change");
+ }
+
+ else if id == token::str_to_ident("asm") {
+ self.gate_feature("asm", path.span, "inline assembly is not \
+ stable enough for use and is subject to change");
+ }
+
+ else if id == token::str_to_ident("log_syntax") {
+ self.gate_feature("log_syntax", path.span, "`log_syntax!` is not \
+ stable enough for use and is subject to change");
+ }
+
+ else if id == token::str_to_ident("trace_macros") {
+ self.gate_feature("trace_macros", path.span, "`trace_macros` is not \
+ stable enough for use and is subject to change");
+ }
+
+ else if id == token::str_to_ident("concat_idents") {
+ self.gate_feature("concat_idents", path.span, "`concat_idents` is not \
+ stable enough for use and is subject to change");
+ }
+
+ else {
+ for "e in quotes.iter() {
+ if id == token::str_to_ident(quote) {
+ self.gate_feature("quote",
+ path.span,
+ format!("{}{}", quote, msg).as_slice());
+ }
+ }
+ }
+ }
+
+ fn visit_foreign_item(&mut self, i: &ast::ForeignItem) {
+ if attr::contains_name(i.attrs.as_slice(), "linkage") {
+ self.gate_feature("linkage", i.span,
+ "the `linkage` attribute is experimental \
+ and not portable across platforms")
+ }
+ visit::walk_foreign_item(self, i)
+ }
+
+ fn visit_ty(&mut self, t: &ast::Ty) {
+ match t.node {
+ ast::TyClosure(ref closure) if closure.onceness == ast::Once => {
+ self.gate_feature("once_fns", t.span,
+ "once functions are \
+ experimental and likely to be removed");
+
+ },
+ ast::TyBox(_) => { self.gate_box(t.span); }
+ ast::TyUnboxedFn(..) => {
+ self.gate_feature("unboxed_closure_sugar",
+ t.span,
+ "unboxed closure trait sugar is experimental");
+ }
+ _ => {}
+ }
+
+ visit::walk_ty(self, t);
+ }
+
+ fn visit_expr(&mut self, e: &ast::Expr) {
+ match e.node {
+ ast::ExprUnary(ast::UnBox, _) => {
+ self.gate_box(e.span);
+ }
+ ast::ExprUnboxedFn(..) => {
+ self.gate_feature("unboxed_closures",
+ e.span,
+ "unboxed closures are a work-in-progress \
+ feature with known bugs");
+ }
+ ast::ExprTupField(..) => {
+ self.gate_feature("tuple_indexing",
+ e.span,
+ "tuple indexing is experimental");
+ }
+ _ => {}
+ }
+ visit::walk_expr(self, e);
+ }
+
+ fn visit_generics(&mut self, generics: &ast::Generics) {
+ for type_parameter in generics.ty_params.iter() {
+ match type_parameter.default {
+ Some(ref ty) => {
+ self.gate_feature("default_type_params", ty.span,
+ "default type parameters are \
+ experimental and possibly buggy");
+ }
+ None => {}
+ }
+ }
+ visit::walk_generics(self, generics);
+ }
+
+ fn visit_attribute(&mut self, attr: &ast::Attribute) {
+ if attr::contains_name(slice::ref_slice(attr), "lang") {
+ self.gate_feature("lang_items",
+ attr.span,
+ "language items are subject to change");
+ }
+ }
+
+ fn visit_pat(&mut self, pattern: &ast::Pat) {
+ match pattern.node {
+ ast::PatVec(_, Some(_), ref last) if !last.is_empty() => {
+ self.gate_feature("advanced_slice_patterns",
+ pattern.span,
+ "multiple-element slice matches anywhere \
+ but at the end of a slice (e.g. \
+ `[0, ..xs, 0]` are experimental")
+ }
+ _ => {}
+ }
+ visit::walk_pat(self, pattern)
+ }
+
+ fn visit_fn(&mut self,
+ fn_kind: visit::FnKind<'v>,
+ fn_decl: &'v ast::FnDecl,
+ block: &'v ast::Block,
+ span: Span,
+ _: NodeId) {
+ match fn_kind {
+ visit::FkItemFn(_, _, _, abi) if abi == RustIntrinsic => {
+ self.gate_feature("intrinsics",
+ span,
+ "intrinsics are subject to change")
+ }
+ _ => {}
+ }
+ visit::walk_fn(self, fn_kind, fn_decl, block, span);
+ }
+}
+
+pub fn check_crate(span_handler: &SpanHandler, krate: &ast::Crate) -> (Features, Vec<Span>) {
+ let mut cx = Context {
+ features: Vec::new(),
+ span_handler: span_handler,
+ };
+
+ let mut unknown_features = Vec::new();
+
+ for attr in krate.attrs.iter() {
+ if !attr.check_name("feature") {
+ continue
+ }
+
+ match attr.meta_item_list() {
+ None => {
+ span_handler.span_err(attr.span, "malformed feature attribute, \
+ expected #![feature(...)]");
+ }
+ Some(list) => {
+ for mi in list.iter() {
+ let name = match mi.node {
+ ast::MetaWord(ref word) => (*word).clone(),
+ _ => {
+ span_handler.span_err(mi.span,
+ "malformed feature, expected just \
+ one word");
+ continue
+ }
+ };
+ match KNOWN_FEATURES.iter()
+ .find(|& &(n, _)| name.equiv(&n)) {
+ Some(&(name, Active)) => { cx.features.push(name); }
+ Some(&(_, Removed)) => {
+ span_handler.span_err(mi.span, "feature has been removed");
+ }
+ Some(&(_, Accepted)) => {
+ span_handler.span_warn(mi.span, "feature has been added to Rust, \
+ directive not necessary");
+ }
+ None => {
+ unknown_features.push(mi.span);
+ }
+ }
+ }
+ }
+ }
+ }
+
+ visit::walk_crate(&mut cx, krate);
+
+ (Features {
+ default_type_params: cx.has_feature("default_type_params"),
+ overloaded_calls: cx.has_feature("overloaded_calls"),
+ rustc_diagnostic_macros: cx.has_feature("rustc_diagnostic_macros"),
+ import_shadowing: cx.has_feature("import_shadowing"),
+ },
+ unknown_features)
+}
+
pub mod ast_util;
pub mod attr;
pub mod codemap;
+pub mod config;
pub mod crateid;
pub mod diagnostic;
+pub mod feature_gate;
pub mod fold;
pub mod owned_slice;
pub mod parse;
pub mod ptr;
+pub mod show_span;
+pub mod std_inject;
+pub mod test;
pub mod visit;
pub mod print {
use parse::parser::Parser;
use ptr::P;
-use std::cell::RefCell;
+use std::cell::{Cell, RefCell};
use std::io::File;
use std::rc::Rc;
use std::str;
pub span_diagnostic: SpanHandler, // better be the same as the one in the reader!
/// Used to determine and report recursive mod inclusions
included_mod_stack: RefCell<Vec<Path>>,
+ pub node_id: Cell<ast::NodeId>,
}
pub fn new_parse_sess() -> ParseSess {
ParseSess {
span_diagnostic: mk_span_handler(default_handler(Auto, None), CodeMap::new()),
included_mod_stack: RefCell::new(Vec::new()),
+ node_id: Cell::new(1),
}
}
ParseSess {
span_diagnostic: sh,
included_mod_stack: RefCell::new(Vec::new()),
+ node_id: Cell::new(1),
+ }
+}
+
+impl ParseSess {
+ pub fn next_node_id(&self) -> ast::NodeId {
+ self.reserve_node_ids(1)
+ }
+ pub fn reserve_node_ids(&self, count: ast::NodeId) -> ast::NodeId {
+ let v = self.node_id.get();
+
+ match v.checked_add(&count) {
+ Some(next) => { self.node_id.set(next); }
+ None => fail!("Input too large, ran out of node ids!")
+ }
+
+ v
}
}
--- /dev/null
+// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+//! Span debugger
+//!
+//! This module shows spans for all expressions in the crate
+//! to help with compiler debugging.
+
+use ast;
+use diagnostic;
+use visit;
+use visit::Visitor;
+
+struct ShowSpanVisitor<'a> {
+ span_diagnostic: &'a diagnostic::SpanHandler,
+}
+
+impl<'a, 'v> Visitor<'v> for ShowSpanVisitor<'a> {
+ fn visit_expr(&mut self, e: &ast::Expr) {
+ self.span_diagnostic.span_note(e.span, "expression");
+ visit::walk_expr(self, e);
+ }
+
+ fn visit_mac(&mut self, macro: &ast::Mac) {
+ visit::walk_mac(self, macro);
+ }
+}
+
+pub fn run(span_diagnostic: &diagnostic::SpanHandler, krate: &ast::Crate) {
+ let mut v = ShowSpanVisitor { span_diagnostic: span_diagnostic };
+ visit::walk_crate(&mut v, krate);
+}
--- /dev/null
+// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+use ast;
+use attr;
+use codemap::DUMMY_SP;
+use codemap;
+use fold::Folder;
+use fold;
+use owned_slice::OwnedSlice;
+use parse::token::InternedString;
+use parse::token::special_idents;
+use parse::token;
+use ptr::P;
+use util::small_vector::SmallVector;
+
+use std::mem;
+
+pub fn maybe_inject_crates_ref(krate: ast::Crate, alt_std_name: Option<String>, any_exe: bool)
+ -> ast::Crate {
+ if use_std(&krate) {
+ inject_crates_ref(krate, alt_std_name, any_exe)
+ } else {
+ krate
+ }
+}
+
+pub fn maybe_inject_prelude(krate: ast::Crate) -> ast::Crate {
+ if use_std(&krate) {
+ inject_prelude(krate)
+ } else {
+ krate
+ }
+}
+
+fn use_std(krate: &ast::Crate) -> bool {
+ !attr::contains_name(krate.attrs.as_slice(), "no_std")
+}
+
+fn use_start(krate: &ast::Crate) -> bool {
+ !attr::contains_name(krate.attrs.as_slice(), "no_start")
+}
+
+fn no_prelude(attrs: &[ast::Attribute]) -> bool {
+ attr::contains_name(attrs, "no_implicit_prelude")
+}
+
+struct StandardLibraryInjector<'a> {
+ alt_std_name: Option<String>,
+ any_exe: bool,
+}
+
+impl<'a> fold::Folder for StandardLibraryInjector<'a> {
+ fn fold_crate(&mut self, mut krate: ast::Crate) -> ast::Crate {
+
+ // The name to use in `extern crate "name" as std;`
+ let actual_crate_name = match self.alt_std_name {
+ Some(ref s) => token::intern_and_get_ident(s.as_slice()),
+ None => token::intern_and_get_ident("std"),
+ };
+
+ let mut vis = vec!(ast::ViewItem {
+ node: ast::ViewItemExternCrate(token::str_to_ident("std"),
+ Some((actual_crate_name, ast::CookedStr)),
+ ast::DUMMY_NODE_ID),
+ attrs: vec!(
+ attr::mk_attr_outer(attr::mk_attr_id(), attr::mk_list_item(
+ InternedString::new("phase"),
+ vec!(
+ attr::mk_word_item(InternedString::new("plugin")),
+ attr::mk_word_item(InternedString::new("link")
+ ))))),
+ vis: ast::Inherited,
+ span: DUMMY_SP
+ });
+
+ if use_start(&krate) && self.any_exe {
+ let visible_rt_name = "rt";
+ let actual_rt_name = "native";
+ // Gensym the ident so it can't be named
+ let visible_rt_name = token::gensym_ident(visible_rt_name);
+ let actual_rt_name = token::intern_and_get_ident(actual_rt_name);
+
+ vis.push(ast::ViewItem {
+ node: ast::ViewItemExternCrate(visible_rt_name,
+ Some((actual_rt_name, ast::CookedStr)),
+ ast::DUMMY_NODE_ID),
+ attrs: Vec::new(),
+ vis: ast::Inherited,
+ span: DUMMY_SP
+ });
+ }
+
+ // `extern crate` must be precede `use` items
+ mem::swap(&mut vis, &mut krate.module.view_items);
+ krate.module.view_items.push_all_move(vis);
+
+ // don't add #![no_std] here, that will block the prelude injection later.
+ // Add it during the prelude injection instead.
+
+ // Add #![feature(phase)] here, because we use #[phase] on extern crate std.
+ let feat_phase_attr = attr::mk_attr_inner(attr::mk_attr_id(),
+ attr::mk_list_item(
+ InternedString::new("feature"),
+ vec![attr::mk_word_item(InternedString::new("phase"))],
+ ));
+ // std_inject runs after feature checking so manually mark this attr
+ attr::mark_used(&feat_phase_attr);
+ krate.attrs.push(feat_phase_attr);
+
+ krate
+ }
+}
+
+fn inject_crates_ref(krate: ast::Crate,
+ alt_std_name: Option<String>,
+ any_exe: bool) -> ast::Crate {
+ let mut fold = StandardLibraryInjector {
+ alt_std_name: alt_std_name,
+ any_exe: any_exe,
+ };
+ fold.fold_crate(krate)
+}
+
+struct PreludeInjector<'a>;
+
+
+impl<'a> fold::Folder for PreludeInjector<'a> {
+ fn fold_crate(&mut self, mut krate: ast::Crate) -> ast::Crate {
+ // Add #![no_std] here, so we don't re-inject when compiling pretty-printed source.
+ // This must happen here and not in StandardLibraryInjector because this
+ // fold happens second.
+
+ let no_std_attr = attr::mk_attr_inner(attr::mk_attr_id(),
+ attr::mk_word_item(InternedString::new("no_std")));
+ // std_inject runs after feature checking so manually mark this attr
+ attr::mark_used(&no_std_attr);
+ krate.attrs.push(no_std_attr);
+
+ if !no_prelude(krate.attrs.as_slice()) {
+ // only add `use std::prelude::*;` if there wasn't a
+ // `#![no_implicit_prelude]` at the crate level.
+ // fold_mod() will insert glob path.
+ let globs_attr = attr::mk_attr_inner(attr::mk_attr_id(),
+ attr::mk_list_item(
+ InternedString::new("feature"),
+ vec!(
+ attr::mk_word_item(InternedString::new("globs")),
+ )));
+ // std_inject runs after feature checking so manually mark this attr
+ attr::mark_used(&globs_attr);
+ krate.attrs.push(globs_attr);
+
+ krate.module = self.fold_mod(krate.module);
+ }
+ krate
+ }
+
+ fn fold_item(&mut self, item: P<ast::Item>) -> SmallVector<P<ast::Item>> {
+ if !no_prelude(item.attrs.as_slice()) {
+ // only recur if there wasn't `#![no_implicit_prelude]`
+ // on this item, i.e. this means that the prelude is not
+ // implicitly imported though the whole subtree
+ fold::noop_fold_item(item, self)
+ } else {
+ SmallVector::one(item)
+ }
+ }
+
+ fn fold_mod(&mut self, ast::Mod {inner, view_items, items}: ast::Mod) -> ast::Mod {
+ let prelude_path = ast::Path {
+ span: DUMMY_SP,
+ global: false,
+ segments: vec!(
+ ast::PathSegment {
+ identifier: token::str_to_ident("std"),
+ lifetimes: Vec::new(),
+ types: OwnedSlice::empty(),
+ },
+ ast::PathSegment {
+ identifier: token::str_to_ident("prelude"),
+ lifetimes: Vec::new(),
+ types: OwnedSlice::empty(),
+ }),
+ };
+
+ let (crates, uses) = view_items.partitioned(|x| {
+ match x.node {
+ ast::ViewItemExternCrate(..) => true,
+ _ => false,
+ }
+ });
+
+ // add prelude after any `extern crate` but before any `use`
+ let mut view_items = crates;
+ let vp = P(codemap::dummy_spanned(ast::ViewPathGlob(prelude_path, ast::DUMMY_NODE_ID)));
+ view_items.push(ast::ViewItem {
+ node: ast::ViewItemUse(vp),
+ attrs: vec![ast::Attribute {
+ span: DUMMY_SP,
+ node: ast::Attribute_ {
+ id: attr::mk_attr_id(),
+ style: ast::AttrOuter,
+ value: P(ast::MetaItem {
+ span: DUMMY_SP,
+ node: ast::MetaWord(token::get_name(
+ special_idents::prelude_import.name)),
+ }),
+ is_sugared_doc: false,
+ },
+ }],
+ vis: ast::Inherited,
+ span: DUMMY_SP,
+ });
+ view_items.push_all_move(uses);
+
+ fold::noop_fold_mod(ast::Mod {
+ inner: inner,
+ view_items: view_items,
+ items: items
+ }, self)
+ }
+}
+
+fn inject_prelude(krate: ast::Crate) -> ast::Crate {
+ let mut fold = PreludeInjector;
+ fold.fold_crate(krate)
+}
--- /dev/null
+// Copyright 2012-2014 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// Code that generates a test runner to run all the tests in a crate
+
+#![allow(dead_code)]
+#![allow(unused_imports)]
+
+use std::gc::{Gc, GC};
+use std::slice;
+use std::mem;
+use std::vec;
+use ast_util::*;
+use attr::AttrMetaMethods;
+use attr;
+use codemap::{DUMMY_SP, Span, ExpnInfo, NameAndSpan, MacroAttribute};
+use codemap;
+use diagnostic;
+use config;
+use ext::base::ExtCtxt;
+use ext::build::AstBuilder;
+use ext::expand::ExpansionConfig;
+use fold::{Folder, MoveMap};
+use fold;
+use owned_slice::OwnedSlice;
+use parse::token::InternedString;
+use parse::{token, ParseSess};
+use print::pprust;
+use {ast, ast_util};
+use ptr::P;
+use util::small_vector::SmallVector;
+
+struct Test {
+ span: Span,
+ path: Vec<ast::Ident> ,
+ bench: bool,
+ ignore: bool,
+ should_fail: bool
+}
+
+struct TestCtxt<'a> {
+ sess: &'a ParseSess,
+ span_diagnostic: &'a diagnostic::SpanHandler,
+ path: Vec<ast::Ident>,
+ ext_cx: ExtCtxt<'a>,
+ testfns: Vec<Test>,
+ reexport_test_harness_main: Option<InternedString>,
+ is_test_crate: bool,
+ config: ast::CrateConfig,
+
+ // top-level re-export submodule, filled out after folding is finished
+ toplevel_reexport: Option<ast::Ident>,
+}
+
+// Traverse the crate, collecting all the test functions, eliding any
+// existing main functions, and synthesizing a main test harness
+pub fn modify_for_testing(sess: &ParseSess,
+ cfg: &ast::CrateConfig,
+ krate: ast::Crate,
+ span_diagnostic: &diagnostic::SpanHandler) -> ast::Crate {
+ // We generate the test harness when building in the 'test'
+ // configuration, either with the '--test' or '--cfg test'
+ // command line options.
+ let should_test = attr::contains_name(krate.config.as_slice(), "test");
+
+ // Check for #[reexport_test_harness_main = "some_name"] which
+ // creates a `use some_name = __test::main;`. This needs to be
+ // unconditional, so that the attribute is still marked as used in
+ // non-test builds.
+ let reexport_test_harness_main =
+ attr::first_attr_value_str_by_name(krate.attrs.as_slice(),
+ "reexport_test_harness_main");
+
+ if should_test {
+ generate_test_harness(sess, reexport_test_harness_main, krate, cfg, span_diagnostic)
+ } else {
+ strip_test_functions(krate)
+ }
+}
+
+struct TestHarnessGenerator<'a> {
+ cx: TestCtxt<'a>,
+ tests: Vec<ast::Ident>,
+
+ // submodule name, gensym'd identifier for re-exports
+ tested_submods: Vec<(ast::Ident, ast::Ident)>,
+}
+
+impl<'a> fold::Folder for TestHarnessGenerator<'a> {
+ fn fold_crate(&mut self, c: ast::Crate) -> ast::Crate {
+ let mut folded = fold::noop_fold_crate(c, self);
+
+ // Add a special __test module to the crate that will contain code
+ // generated for the test harness
+ let (mod_, reexport) = mk_test_module(&mut self.cx);
+ folded.module.items.push(mod_);
+ match reexport {
+ Some(re) => folded.module.view_items.push(re),
+ None => {}
+ }
+ folded
+ }
+
+ fn fold_item(&mut self, i: P<ast::Item>) -> SmallVector<P<ast::Item>> {
+ self.cx.path.push(i.ident);
+ debug!("current path: {}",
+ ast_util::path_name_i(self.cx.path.as_slice()));
+
+ if is_test_fn(&self.cx, &*i) || is_bench_fn(&self.cx, &*i) {
+ match i.node {
+ ast::ItemFn(_, ast::UnsafeFn, _, _, _) => {
+ let diag = self.cx.span_diagnostic;
+ diag.span_fatal(i.span,
+ "unsafe functions cannot be used for \
+ tests");
+ }
+ _ => {
+ debug!("this is a test function");
+ let test = Test {
+ span: i.span,
+ path: self.cx.path.clone(),
+ bench: is_bench_fn(&self.cx, &*i),
+ ignore: is_ignored(&self.cx, &*i),
+ should_fail: should_fail(&*i)
+ };
+ self.cx.testfns.push(test);
+ self.tests.push(i.ident);
+ // debug!("have {} test/bench functions",
+ // cx.testfns.len());
+ }
+ }
+ }
+
+ // We don't want to recurse into anything other than mods, since
+ // mods or tests inside of functions will break things
+ let res = match i.node {
+ ast::ItemMod(..) => fold::noop_fold_item(i, self),
+ _ => SmallVector::one(i),
+ };
+ self.cx.path.pop();
+ res
+ }
+
+ fn fold_mod(&mut self, m: ast::Mod) -> ast::Mod {
+ let tests = mem::replace(&mut self.tests, Vec::new());
+ let tested_submods = mem::replace(&mut self.tested_submods, Vec::new());
+ let mut mod_folded = fold::noop_fold_mod(m, self);
+ let tests = mem::replace(&mut self.tests, tests);
+ let tested_submods = mem::replace(&mut self.tested_submods, tested_submods);
+
+ // Remove any #[main] from the AST so it doesn't clash with
+ // the one we're going to add. Only if compiling an executable.
+
+ mod_folded.items = mem::replace(&mut mod_folded.items, vec![]).move_map(|item| {
+ item.map(|ast::Item {id, ident, attrs, node, vis, span}| {
+ ast::Item {
+ id: id,
+ ident: ident,
+ attrs: attrs.into_iter().filter_map(|attr| {
+ if !attr.check_name("main") {
+ Some(attr)
+ } else {
+ None
+ }
+ }).collect(),
+ node: node,
+ vis: vis,
+ span: span
+ }
+ })
+ });
+
+ if !tests.is_empty() || !tested_submods.is_empty() {
+ let (it, sym) = mk_reexport_mod(&mut self.cx, tests, tested_submods);
+ mod_folded.items.push(it);
+
+ if !self.cx.path.is_empty() {
+ self.tested_submods.push((self.cx.path[self.cx.path.len()-1], sym));
+ } else {
+ debug!("pushing nothing, sym: {}", sym);
+ self.cx.toplevel_reexport = Some(sym);
+ }
+ }
+
+ mod_folded
+ }
+}
+
+fn mk_reexport_mod(cx: &mut TestCtxt, tests: Vec<ast::Ident>,
+ tested_submods: Vec<(ast::Ident, ast::Ident)>) -> (P<ast::Item>, ast::Ident) {
+ let mut view_items = Vec::new();
+ let super_ = token::str_to_ident("super");
+
+ view_items.extend(tests.into_iter().map(|r| {
+ cx.ext_cx.view_use_simple(DUMMY_SP, ast::Public,
+ cx.ext_cx.path(DUMMY_SP, vec![super_, r]))
+ }));
+ view_items.extend(tested_submods.into_iter().map(|(r, sym)| {
+ let path = cx.ext_cx.path(DUMMY_SP, vec![super_, r, sym]);
+ cx.ext_cx.view_use_simple_(DUMMY_SP, ast::Public, r, path)
+ }));
+
+ let reexport_mod = ast::Mod {
+ inner: DUMMY_SP,
+ view_items: view_items,
+ items: Vec::new(),
+ };
+
+ let sym = token::gensym_ident("__test_reexports");
+ let it = P(ast::Item {
+ ident: sym.clone(),
+ attrs: Vec::new(),
+ id: ast::DUMMY_NODE_ID,
+ node: ast::ItemMod(reexport_mod),
+ vis: ast::Public,
+ span: DUMMY_SP,
+ });
+
+ (it, sym)
+}
+
+fn generate_test_harness(sess: &ParseSess,
+ reexport_test_harness_main: Option<InternedString>,
+ krate: ast::Crate,
+ cfg: &ast::CrateConfig,
+ sd: &diagnostic::SpanHandler) -> ast::Crate {
+ let mut cx: TestCtxt = TestCtxt {
+ sess: sess,
+ span_diagnostic: sd,
+ ext_cx: ExtCtxt::new(sess, cfg.clone(),
+ ExpansionConfig {
+ deriving_hash_type_parameter: false,
+ crate_name: "test".to_string(),
+ }),
+ path: Vec::new(),
+ testfns: Vec::new(),
+ reexport_test_harness_main: reexport_test_harness_main,
+ is_test_crate: is_test_crate(&krate),
+ config: krate.config.clone(),
+ toplevel_reexport: None,
+ };
+
+ cx.ext_cx.bt_push(ExpnInfo {
+ call_site: DUMMY_SP,
+ callee: NameAndSpan {
+ name: "test".to_string(),
+ format: MacroAttribute,
+ span: None
+ }
+ });
+
+ let mut fold = TestHarnessGenerator {
+ cx: cx,
+ tests: Vec::new(),
+ tested_submods: Vec::new(),
+ };
+ let res = fold.fold_crate(krate);
+ fold.cx.ext_cx.bt_pop();
+ return res;
+}
+
+fn strip_test_functions(krate: ast::Crate) -> ast::Crate {
+ // When not compiling with --test we should not compile the
+ // #[test] functions
+ config::strip_items(krate, |attrs| {
+ !attr::contains_name(attrs.as_slice(), "test") &&
+ !attr::contains_name(attrs.as_slice(), "bench")
+ })
+}
+
+fn is_test_fn(cx: &TestCtxt, i: &ast::Item) -> bool {
+ let has_test_attr = attr::contains_name(i.attrs.as_slice(), "test");
+
+ fn has_test_signature(i: &ast::Item) -> bool {
+ match &i.node {
+ &ast::ItemFn(ref decl, _, _, ref generics, _) => {
+ let no_output = match decl.output.node {
+ ast::TyNil => true,
+ _ => false
+ };
+ decl.inputs.is_empty()
+ && no_output
+ && !generics.is_parameterized()
+ }
+ _ => false
+ }
+ }
+
+ if has_test_attr && !has_test_signature(i) {
+ let diag = cx.span_diagnostic;
+ diag.span_err(
+ i.span,
+ "functions used as tests must have signature fn() -> ()."
+ );
+ }
+
+ return has_test_attr && has_test_signature(i);
+}
+
+fn is_bench_fn(cx: &TestCtxt, i: &ast::Item) -> bool {
+ let has_bench_attr = attr::contains_name(i.attrs.as_slice(), "bench");
+
+ fn has_test_signature(i: &ast::Item) -> bool {
+ match i.node {
+ ast::ItemFn(ref decl, _, _, ref generics, _) => {
+ let input_cnt = decl.inputs.len();
+ let no_output = match decl.output.node {
+ ast::TyNil => true,
+ _ => false
+ };
+ let tparm_cnt = generics.ty_params.len();
+ // NB: inadequate check, but we're running
+ // well before resolve, can't get too deep.
+ input_cnt == 1u
+ && no_output && tparm_cnt == 0u
+ }
+ _ => false
+ }
+ }
+
+ if has_bench_attr && !has_test_signature(i) {
+ let diag = cx.span_diagnostic;
+ diag.span_err(i.span, "functions used as benches must have signature \
+ `fn(&mut Bencher) -> ()`");
+ }
+
+ return has_bench_attr && has_test_signature(i);
+}
+
+fn is_ignored(cx: &TestCtxt, i: &ast::Item) -> bool {
+ i.attrs.iter().any(|attr| {
+ // check ignore(cfg(foo, bar))
+ attr.check_name("ignore") && match attr.meta_item_list() {
+ Some(ref cfgs) => {
+ attr::test_cfg(cx.config.as_slice(), cfgs.iter())
+ }
+ None => true
+ }
+ })
+}
+
+fn should_fail(i: &ast::Item) -> bool {
+ attr::contains_name(i.attrs.as_slice(), "should_fail")
+}
+
+/*
+
+We're going to be building a module that looks more or less like:
+
+mod __test {
+ extern crate test (name = "test", vers = "...");
+ fn main() {
+ test::test_main_static(::os::args().as_slice(), tests)
+ }
+
+ static tests : &'static [test::TestDescAndFn] = &[
+ ... the list of tests in the crate ...
+ ];
+}
+
+*/
+
+fn mk_std(cx: &TestCtxt) -> ast::ViewItem {
+ let id_test = token::str_to_ident("test");
+ let (vi, vis) = if cx.is_test_crate {
+ (ast::ViewItemUse(
+ P(nospan(ast::ViewPathSimple(id_test,
+ path_node(vec!(id_test)),
+ ast::DUMMY_NODE_ID)))),
+ ast::Public)
+ } else {
+ (ast::ViewItemExternCrate(id_test, None, ast::DUMMY_NODE_ID),
+ ast::Inherited)
+ };
+ ast::ViewItem {
+ node: vi,
+ attrs: Vec::new(),
+ vis: vis,
+ span: DUMMY_SP
+ }
+}
+
+fn mk_test_module(cx: &mut TestCtxt) -> (P<ast::Item>, Option<ast::ViewItem>) {
+ // Link to test crate
+ let view_items = vec!(mk_std(cx));
+
+ // A constant vector of test descriptors.
+ let tests = mk_tests(cx);
+
+ // 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::Slice;
+ test::test_main_static(::std::os::args().as_slice(), TESTS);
+ }
+ )).unwrap();
+
+ let testmod = ast::Mod {
+ inner: DUMMY_SP,
+ view_items: view_items,
+ items: vec!(mainfn, tests),
+ };
+ let item_ = ast::ItemMod(testmod);
+
+ let mod_ident = token::gensym_ident("__test");
+ let item = ast::Item {
+ ident: mod_ident,
+ attrs: Vec::new(),
+ id: ast::DUMMY_NODE_ID,
+ node: item_,
+ vis: ast::Public,
+ span: DUMMY_SP,
+ };
+ let reexport = cx.reexport_test_harness_main.as_ref().map(|s| {
+ // building `use <ident> = __test::main`
+ let reexport_ident = token::str_to_ident(s.get());
+
+ let use_path =
+ nospan(ast::ViewPathSimple(reexport_ident,
+ path_node(vec![mod_ident, token::str_to_ident("main")]),
+ ast::DUMMY_NODE_ID));
+
+ ast::ViewItem {
+ node: ast::ViewItemUse(P(use_path)),
+ attrs: vec![],
+ vis: ast::Inherited,
+ span: DUMMY_SP
+ }
+ });
+
+ debug!("Synthetic test module:\n{}\n", pprust::item_to_string(&item));
+
+ (P(item), reexport)
+}
+
+fn nospan<T>(t: T) -> codemap::Spanned<T> {
+ codemap::Spanned { node: t, span: DUMMY_SP }
+}
+
+fn path_node(ids: Vec<ast::Ident> ) -> ast::Path {
+ ast::Path {
+ span: DUMMY_SP,
+ global: false,
+ segments: ids.into_iter().map(|identifier| ast::PathSegment {
+ identifier: identifier,
+ lifetimes: Vec::new(),
+ types: OwnedSlice::empty(),
+ }).collect()
+ }
+}
+
+fn mk_tests(cx: &TestCtxt) -> P<ast::Item> {
+ // The vector of test_descs for this crate
+ let test_descs = mk_test_descs(cx);
+
+ // FIXME #15962: should be using quote_item, but that stringifies
+ // __test_reexports, causing it to be reinterned, losing the
+ // gensym information.
+ let sp = DUMMY_SP;
+ let ecx = &cx.ext_cx;
+ let struct_type = ecx.ty_path(ecx.path(sp, vec![ecx.ident_of("self"),
+ ecx.ident_of("test"),
+ ecx.ident_of("TestDescAndFn")]),
+ None);
+ let static_lt = ecx.lifetime(sp, token::special_idents::static_lifetime.name);
+ // &'static [self::test::TestDescAndFn]
+ let static_type = ecx.ty_rptr(sp,
+ ecx.ty(sp, ast::TyVec(struct_type)),
+ Some(static_lt),
+ ast::MutImmutable);
+ // static TESTS: $static_type = &[...];
+ ecx.item_static(sp,
+ ecx.ident_of("TESTS"),
+ static_type,
+ ast::MutImmutable,
+ test_descs)
+}
+
+fn is_test_crate(krate: &ast::Crate) -> bool {
+ match attr::find_crate_name(krate.attrs.as_slice()) {
+ Some(ref s) if "test" == s.get().as_slice() => true,
+ _ => false
+ }
+}
+
+fn mk_test_descs(cx: &TestCtxt) -> P<ast::Expr> {
+ debug!("building test vector from {} tests", cx.testfns.len());
+
+ P(ast::Expr {
+ id: ast::DUMMY_NODE_ID,
+ node: ast::ExprAddrOf(ast::MutImmutable,
+ P(ast::Expr {
+ id: ast::DUMMY_NODE_ID,
+ node: ast::ExprVec(cx.testfns.iter().map(|test| {
+ mk_test_desc_and_fn_rec(cx, test)
+ }).collect()),
+ span: DUMMY_SP,
+ })),
+ span: DUMMY_SP,
+ })
+}
+
+fn mk_test_desc_and_fn_rec(cx: &TestCtxt, test: &Test) -> P<ast::Expr> {
+ // FIXME #15962: should be using quote_expr, but that stringifies
+ // __test_reexports, causing it to be reinterned, losing the
+ // gensym information.
+
+ let span = test.span;
+ let path = test.path.clone();
+ let ecx = &cx.ext_cx;
+ let self_id = ecx.ident_of("self");
+ let test_id = ecx.ident_of("test");
+
+ // creates self::test::$name
+ let test_path = |name| {
+ ecx.path(span, vec![self_id, test_id, ecx.ident_of(name)])
+ };
+ // creates $name: $expr
+ let field = |name, expr| ecx.field_imm(span, ecx.ident_of(name), expr);
+
+ debug!("encoding {}", ast_util::path_name_i(path.as_slice()));
+
+ // path to the #[test] function: "foo::bar::baz"
+ let path_string = ast_util::path_name_i(path.as_slice());
+ let name_expr = ecx.expr_str(span, token::intern_and_get_ident(path_string.as_slice()));
+
+ // self::test::StaticTestName($name_expr)
+ let name_expr = ecx.expr_call(span,
+ ecx.expr_path(test_path("StaticTestName")),
+ vec![name_expr]);
+
+ let ignore_expr = ecx.expr_bool(span, test.ignore);
+ let fail_expr = ecx.expr_bool(span, test.should_fail);
+
+ // self::test::TestDesc { ... }
+ let desc_expr = ecx.expr_struct(
+ span,
+ test_path("TestDesc"),
+ vec![field("name", name_expr),
+ field("ignore", ignore_expr),
+ field("should_fail", fail_expr)]);
+
+
+ let mut visible_path = match cx.toplevel_reexport {
+ Some(id) => vec![id],
+ None => {
+ let diag = cx.span_diagnostic;
+ diag.handler.bug("expected to find top-level re-export name, but found None");
+ }
+ };
+ visible_path.extend(path.into_iter());
+
+ let fn_expr = ecx.expr_path(ecx.path_global(span, visible_path));
+
+ let variant_name = if test.bench { "StaticBenchFn" } else { "StaticTestFn" };
+ // self::test::$variant_name($fn_expr)
+ let testfn_expr = ecx.expr_call(span, ecx.expr_path(test_path(variant_name)), vec![fn_expr]);
+
+ // self::test::TestDescAndFn { ... }
+ ecx.expr_struct(span,
+ test_path("TestDescAndFn"),
+ vec![field("desc", desc_expr),
+ field("testfn", testfn_expr)])
+}
--- /dev/null
+// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+fn main() {
+ let _x: int = [1i, 2, 3]; //~ ERROR expected int, found array
+
+ let x: &[int] = &[1, 2, 3];
+ let _y: &int = x; //~ ERROR expected int, found unsized array
+}
--- /dev/null
+// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+#![deny(unnecessary_import_braces)]
+#![allow(dead_code)]
+#![allow(unused_imports)]
+
+use test::{A}; //~ ERROR braces around A is unnecessary
+
+mod test {
+ pub struct A;
+}
+
+fn main() {}
--- /dev/null
+// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+#![feature(unsafe_destructor)]
+
+struct Leak<'a> {
+ dropped: &'a mut bool
+}
+
+#[unsafe_destructor]
+impl<'a> Drop for Leak<'a> {
+ fn drop(&mut self) {
+ *self.dropped = true;
+ }
+}
+
+fn main() {
+ let mut dropped = false;
+ {
+ let leak = Leak { dropped: &mut dropped };
+ for ((), leaked) in Some(((),leak)).move_iter() {}
+ }
+
+ assert!(dropped);
+}