]> git.lizzy.rs Git - rust.git/commitdiff
rollup merge of #17226 : P1start/rustdoc-colour
authorAlex Crichton <alex@alexcrichton.com>
Wed, 17 Sep 2014 15:48:53 +0000 (08:48 -0700)
committerAlex Crichton <alex@alexcrichton.com>
Wed, 17 Sep 2014 15:48:53 +0000 (08:48 -0700)
30 files changed:
src/doc/guide.md
src/libcore/str.rs
src/libcoretest/str.rs
src/librustc/driver/driver.rs
src/librustc/driver/session.rs
src/librustc/front/config.rs [deleted file]
src/librustc/front/feature_gate.rs [deleted file]
src/librustc/front/show_span.rs [deleted file]
src/librustc/front/std_inject.rs [deleted file]
src/librustc/front/test.rs [deleted file]
src/librustc/lib.rs
src/librustc/lint/builtin.rs
src/librustc/lint/context.rs
src/librustc/middle/resolve.rs
src/librustc/middle/trans/controlflow.rs
src/librustc/middle/ty.rs
src/librustc/middle/typeck/astconv.rs
src/librustc/middle/typeck/check/mod.rs
src/librustdoc/html/static/main.js
src/libstd/bitflags.rs
src/libsyntax/config.rs [new file with mode: 0644]
src/libsyntax/feature_gate.rs [new file with mode: 0644]
src/libsyntax/lib.rs
src/libsyntax/parse/mod.rs
src/libsyntax/show_span.rs [new file with mode: 0644]
src/libsyntax/std_inject.rs [new file with mode: 0644]
src/libsyntax/test.rs [new file with mode: 0644]
src/test/compile-fail/array-not-vector.rs [new file with mode: 0644]
src/test/compile-fail/lint-unnecessary-import-braces.rs [new file with mode: 0644]
src/test/run-pass/issue-17216.rs [new file with mode: 0644]

index 41a0e9abf6c02944b66deff5f3a0556af2c2f8f2..cf97cc3ab64089daf57c43393711b3d5f1b36435 100644 (file)
@@ -4273,7 +4273,7 @@ very common with iterators: we can ignore unnecessary bounds checks, but still
 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:
 
index 6837f3b9af7fa80521c3c00f02f52084f83bec12..7e399902a4b5ebd367959b982dfa62877ea4b50c 100644 (file)
@@ -419,8 +419,76 @@ struct TwoWaySearcher {
     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);
@@ -436,15 +504,19 @@ fn new(needle: &[u8]) -> TwoWaySearcher {
             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,
@@ -466,6 +538,11 @@ fn new(needle: &[u8]) -> TwoWaySearcher {
         }
     }
 
+    // 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 {
@@ -479,6 +556,9 @@ fn next(&mut self, haystack: &[u8], needle: &[u8], long_period: bool) -> Option<
                     ((haystack[self.position + needle.len() - 1] & 0x3f)
                      as uint)) & 1 == 0 {
                 self.position += needle.len();
+                if !long_period {
+                    self.memory = 0;
+                }
                 continue 'search;
             }
 
@@ -517,9 +597,9 @@ fn next(&mut self, haystack: &[u8], needle: &[u8], long_period: bool) -> Option<
         }
     }
 
-    // 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
index be2275dcd4a0266ba277cf7065347262abacdbac..51bd72ec0148a5ff72253133321bb5b8c5f40e6a 100644 (file)
@@ -26,6 +26,12 @@ fn strslice_issue_16589() {
     check_contains_all_substrings("012345678901234567890123456789bcdabcdabcd");
 }
 
+#[test]
+fn strslice_issue_16878() {
+    assert!(!"1234567ah012345678901ah".contains("hah"));
+    assert!(!"00abc01234567890123456789abc".contains("bcabc"));
+}
+
 
 #[test]
 fn test_strslice_contains() {
index 2f252fc042a21588c43020d944f1469a8fbcd614..20371f63a3427d7fe9e45dc35b1bbf86a7bccfee 100644 (file)
@@ -13,7 +13,6 @@
 use back::write;
 use driver::session::Session;
 use driver::config;
-use front;
 use lint;
 use llvm::{ContextRef, ModuleRef};
 use metadata::common::LinkMeta;
@@ -166,7 +165,7 @@ pub fn phase_1_parse_input(sess: &Session, cfg: ast::CrateConfig, input: &Input)
     }
 
     if sess.show_span() {
-        front::show_span::run(sess, &krate);
+        syntax::show_span::run(sess.diagnostic(), &krate);
     }
 
     krate
@@ -194,11 +193,29 @@ pub fn phase_2_configure_and_expand(sess: &Session,
     *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
@@ -209,7 +226,7 @@ pub fn phase_2_configure_and_expand(sess: &Session,
     // 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 }
@@ -219,7 +236,7 @@ pub fn phase_2_configure_and_expand(sess: &Session,
     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",
@@ -271,7 +288,7 @@ pub fn phase_2_configure_and_expand(sess: &Session,
                 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,
@@ -290,13 +307,16 @@ pub fn phase_2_configure_and_expand(sess: &Session,
 
     // 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));
index 6f020184b336d8a3d92a4f7a81d260b4d5aad3d5..d7ed5d3e1ffa446f005d46bf201a5083640b0061 100644 (file)
@@ -11,7 +11,6 @@
 
 use driver::config;
 use driver::driver;
-use front;
 use metadata::cstore::CStore;
 use metadata::filesearch;
 use lint;
@@ -21,6 +20,7 @@
 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;
@@ -47,10 +47,9 @@ pub struct Session {
     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.
@@ -129,17 +128,10 @@ pub fn add_lint(&self,
         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
@@ -251,10 +243,9 @@ pub fn build_session_(sopts: config::Options,
         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),
     };
 
diff --git a/src/librustc/front/config.rs b/src/librustc/front/config.rs
deleted file mode 100644 (file)
index 2e05cb0..0000000
+++ /dev/null
@@ -1,253 +0,0 @@
-// 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())
-}
-
diff --git a/src/librustc/front/feature_gate.rs b/src/librustc/front/feature_gate.rs
deleted file mode 100644 (file)
index 13a40ab..0000000
+++ /dev/null
@@ -1,465 +0,0 @@
-// 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 &quote 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"));
-}
-
diff --git a/src/librustc/front/show_span.rs b/src/librustc/front/show_span.rs
deleted file mode 100644 (file)
index df0b022..0000000
+++ /dev/null
@@ -1,40 +0,0 @@
-// 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);
-}
diff --git a/src/librustc/front/std_inject.rs b/src/librustc/front/std_inject.rs
deleted file mode 100644 (file)
index 748641b..0000000
+++ /dev/null
@@ -1,237 +0,0 @@
-// 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)
-}
diff --git a/src/librustc/front/test.rs b/src/librustc/front/test.rs
deleted file mode 100644 (file)
index 737fe74..0000000
+++ /dev/null
@@ -1,568 +0,0 @@
-// 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)])
-}
index af3d19c4d2d4004b3ccbaac7fdd0c2dc76963644..81234f36ade50b32b375fa0d3e1694322e7c7ea6 100644 (file)
@@ -116,14 +116,6 @@ pub mod middle {
     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;
index eed41edac9d6c2dda244b4c8c52c2fcd941b84cd..edca4ce317da6f3598249e4debb13fa4bf75dbf7 100644 (file)
@@ -1107,6 +1107,41 @@ fn check_stmt(&mut self, cx: &Context, s: &ast::Stmt) {
     }
 }
 
+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")
 
index c75b57dcafae061e8e0386bf6355d31a1bf40863..e39685705dfe0624342726b164b4f9bb5cfd2576 100644 (file)
@@ -183,6 +183,7 @@ macro_rules! add_lint_group ( ( $sess:ident, $name:expr, $($lint:ident),* ) => (
                      NonSnakeCase,
                      NonUppercaseStatics,
                      UnnecessaryParens,
+                     UnnecessaryImportBraces,
                      UnusedUnsafe,
                      UnsafeBlock,
                      UnusedMut,
index 191f7113cc90d05a904053baad03401d136a832c..861ac2ffe60d7b60422dce2c916ba299bd753b58 100644 (file)
@@ -2811,7 +2811,7 @@ fn check_for_conflicting_import(&mut self,
                                     import_span: Span,
                                     name: Name,
                                     namespace: Namespace) {
-        if self.session.features.import_shadowing.get() {
+        if self.session.features.borrow().import_shadowing {
             return
         }
 
@@ -2837,7 +2837,7 @@ fn check_for_conflicts_between_imports_and_items(&mut self,
                                                      &mut ImportResolution,
                                                      import_span: Span,
                                                      name: Name) {
-        if self.session.features.import_shadowing.get() {
+        if self.session.features.borrow().import_shadowing {
             return
         }
 
@@ -2919,7 +2919,7 @@ fn check_for_conflicts_between_external_crates(&self,
                                                    module: &Module,
                                                    name: Name,
                                                    span: Span) {
-        if self.session.features.import_shadowing.get() {
+        if self.session.features.borrow().import_shadowing {
             return
         }
 
@@ -2937,7 +2937,7 @@ fn check_for_conflicts_between_external_crates_and_items(&self,
                                                              module: &Module,
                                                              name: Name,
                                                              span: Span) {
-        if self.session.features.import_shadowing.get() {
+        if self.session.features.borrow().import_shadowing {
             return
         }
 
index fb12520741bcf5656d884b60d295839d8b89c850..5bba188fac7bfbac5aae15b3bc0c1d0ac6b35bb6 100644 (file)
@@ -355,7 +355,10 @@ pub fn trans_for<'blk, 'tcx>(mut bcx: Block<'blk, 'tcx>,
 
     // 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,
index bd472195b958cd8f5ca6c8b9f76963e9db73e387..535294a70a062f7ccfe7185de930954075c85009 100644 (file)
@@ -3789,7 +3789,8 @@ pub fn ty_sort_string(cx: &ctxt, t: t) -> String {
         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(),
index a9b633d483b6a72c47178166335d828cce447e12..00678eb6380cae7b4821775e62c99cd584ecb44c 100644 (file)
@@ -235,7 +235,7 @@ fn ast_path_substs<'tcx, AC: AstConv<'tcx>, RS: RegionScope>(
     }
 
     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,
index 3bda07e92070e33fb7eac6e0dfc5f593e7ec5666..0af20cf2bcced305bef8bb90a32a1f37628d2765 100644 (file)
@@ -2131,7 +2131,7 @@ fn try_overloaded_call(fcx: &FnCtxt,
         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,
index dc18a08a4f862efdea2da621d3fad98e2baa31fa..6992a9665929586b553d9d851ef7af72a01f0155 100644 (file)
 
         $(".method").each(function() {
            if ($(this).next().is(".docblock")) {
-               $(this).children().first().after(toggle[0]);
+               $(this).children().first().after(toggle.clone());
            }
         });
 
index 3d1bc20cca49ecd0870bab4346977e0260b370b0..8af88b4fe7247a5257f241006af027eb23efc870 100644 (file)
@@ -170,6 +170,7 @@ pub fn intersects(&self, other: $BitFlags) -> bool {
             }
 
             /// Returns `true` all of the flags in `other` are contained within `self`.
+            #[inline]
             pub fn contains(&self, other: $BitFlags) -> bool {
                 (self & other) == other
             }
diff --git a/src/libsyntax/config.rs b/src/libsyntax/config.rs
new file mode 100644 (file)
index 0000000..cb96cd9
--- /dev/null
@@ -0,0 +1,253 @@
+// 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())
+}
+
diff --git a/src/libsyntax/feature_gate.rs b/src/libsyntax/feature_gate.rs
new file mode 100644 (file)
index 0000000..e22e551
--- /dev/null
@@ -0,0 +1,461 @@
+// 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 &quote 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)
+}
+
index 146b5a5b34865670df3437d7fc281a9d7bd3a80d..457d77efb708e2846d2ac5c8af602046650aee79 100644 (file)
@@ -59,12 +59,17 @@ pub mod syntax {
 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 {
index e5b6359000b6c1647dc69d6395e51be1f12ec8c0..d73cb2116941a4e2151d4aba256585bb9c1a038f 100644 (file)
@@ -17,7 +17,7 @@
 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;
@@ -37,12 +37,14 @@ pub struct ParseSess {
     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),
     }
 }
 
@@ -50,6 +52,23 @@ pub fn new_parse_sess_special_handler(sh: SpanHandler) -> ParseSess {
     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
     }
 }
 
diff --git a/src/libsyntax/show_span.rs b/src/libsyntax/show_span.rs
new file mode 100644 (file)
index 0000000..354ba85
--- /dev/null
@@ -0,0 +1,39 @@
+// 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);
+}
diff --git a/src/libsyntax/std_inject.rs b/src/libsyntax/std_inject.rs
new file mode 100644 (file)
index 0000000..8a7e146
--- /dev/null
@@ -0,0 +1,235 @@
+// 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)
+}
diff --git a/src/libsyntax/test.rs b/src/libsyntax/test.rs
new file mode 100644 (file)
index 0000000..f0e6971
--- /dev/null
@@ -0,0 +1,573 @@
+// 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)])
+}
diff --git a/src/test/compile-fail/array-not-vector.rs b/src/test/compile-fail/array-not-vector.rs
new file mode 100644 (file)
index 0000000..79d4ada
--- /dev/null
@@ -0,0 +1,16 @@
+// 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
+}
diff --git a/src/test/compile-fail/lint-unnecessary-import-braces.rs b/src/test/compile-fail/lint-unnecessary-import-braces.rs
new file mode 100644 (file)
index 0000000..c44918d
--- /dev/null
@@ -0,0 +1,21 @@
+// 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() {}
diff --git a/src/test/run-pass/issue-17216.rs b/src/test/run-pass/issue-17216.rs
new file mode 100644 (file)
index 0000000..538b837
--- /dev/null
@@ -0,0 +1,32 @@
+// 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);
+}