about summary refs log tree commit diff
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2015-08-26 18:29:02 +0000
committerbors <bors@rust-lang.org>2015-08-26 18:29:02 +0000
commita48c29dcea0d0107c3e0bf761f97d65941a3d73d (patch)
tree6bffc8db76aa3507e6d9a8e860411a9fd1b4e408
parent685332c8d3c5d4c8fd26503b6ea5d9a00c838feb (diff)
parent8320a3a048717f2a09ba5e5cddb2b634047da647 (diff)
downloadrust-a48c29dcea0d0107c3e0bf761f97d65941a3d73d.tar.gz
rust-a48c29dcea0d0107c3e0bf761f97d65941a3d73d.zip
Auto merge of #27992 - wthrowe:dead-main-2, r=alexcrichton
* Suppresses warnings that main is unused when testing (#12327)
* Makes `--test` work with explicit `#[start]` (#11766)
* Fixes some cases where the normal main would not be disabled by `--test`, resulting in compilation failures.
-rw-r--r--src/librustc/middle/entry.rs81
-rw-r--r--src/libsyntax/entry.rs42
-rw-r--r--src/libsyntax/lib.rs1
-rw-r--r--src/libsyntax/test.rs77
-rw-r--r--src/test/compile-fail/test-warns-dead-code.rs17
-rw-r--r--src/test/run-pass/test-main-not-dead-attr.rs18
-rw-r--r--src/test/run-pass/test-main-not-dead.rs15
-rw-r--r--src/test/run-pass/test-runner-hides-buried-main.rs24
-rw-r--r--src/test/run-pass/test-runner-hides-start.rs16
9 files changed, 224 insertions, 67 deletions
diff --git a/src/librustc/middle/entry.rs b/src/librustc/middle/entry.rs
index c6e5b654f9a..8cdd4f7fe74 100644
--- a/src/librustc/middle/entry.rs
+++ b/src/librustc/middle/entry.rs
@@ -11,20 +11,19 @@
 
 use ast_map;
 use session::{config, Session};
-use syntax::ast::{Name, NodeId, Item, ItemFn};
+use syntax;
+use syntax::ast::{NodeId, Item};
 use syntax::attr;
 use syntax::codemap::Span;
-use syntax::parse::token;
+use syntax::entry::EntryPointType;
 use syntax::visit;
 use syntax::visit::Visitor;
 
-struct EntryContext<'a, 'ast: 'a> {
+struct EntryContext<'a> {
     session: &'a Session,
 
-    ast_map: &'a ast_map::Map<'ast>,
-
-    // The interned Name for "main".
-    main_name: Name,
+    // The current depth in the ast
+    depth: usize,
 
     // The top-level function called 'main'
     main_fn: Option<(NodeId, Span)>,
@@ -40,9 +39,11 @@ struct EntryContext<'a, 'ast: 'a> {
     non_main_fns: Vec<(NodeId, Span)> ,
 }
 
-impl<'a, 'ast, 'v> Visitor<'v> for EntryContext<'a, 'ast> {
+impl<'a, 'v> Visitor<'v> for EntryContext<'a> {
     fn visit_item(&mut self, item: &Item) {
+        self.depth += 1;
         find_item(item, self);
+        self.depth -= 1;
     }
 }
 
@@ -63,8 +64,7 @@ pub fn find_entry_point(session: &Session, ast_map: &ast_map::Map) {
 
     let mut ctxt = EntryContext {
         session: session,
-        main_name: token::intern("main"),
-        ast_map: ast_map,
+        depth: 0,
         main_fn: None,
         attr_main_fn: None,
         start_fn: None,
@@ -77,44 +77,35 @@ pub fn find_entry_point(session: &Session, ast_map: &ast_map::Map) {
 }
 
 fn find_item(item: &Item, ctxt: &mut EntryContext) {
-    match item.node {
-        ItemFn(..) => {
-            if item.ident.name == ctxt.main_name {
-                 ctxt.ast_map.with_path(item.id, |path| {
-                        if path.count() == 1 {
-                            // This is a top-level function so can be 'main'
-                            if ctxt.main_fn.is_none() {
-                                ctxt.main_fn = Some((item.id, item.span));
-                            } else {
-                                span_err!(ctxt.session, item.span, E0136,
-                                          "multiple 'main' functions");
-                            }
-                        } else {
-                            // This isn't main
-                            ctxt.non_main_fns.push((item.id, item.span));
-                        }
-                });
+    match syntax::entry::entry_point_type(item, ctxt.depth) {
+        EntryPointType::MainNamed => {
+            if ctxt.main_fn.is_none() {
+                ctxt.main_fn = Some((item.id, item.span));
+            } else {
+                span_err!(ctxt.session, item.span, E0136,
+                          "multiple 'main' functions");
             }
-
-            if attr::contains_name(&item.attrs, "main") {
-                if ctxt.attr_main_fn.is_none() {
-                    ctxt.attr_main_fn = Some((item.id, item.span));
-                } else {
-                    span_err!(ctxt.session, item.span, E0137,
-                              "multiple functions with a #[main] attribute");
-                }
+        },
+        EntryPointType::OtherMain => {
+            ctxt.non_main_fns.push((item.id, item.span));
+        },
+        EntryPointType::MainAttr => {
+            if ctxt.attr_main_fn.is_none() {
+                ctxt.attr_main_fn = Some((item.id, item.span));
+            } else {
+                span_err!(ctxt.session, item.span, E0137,
+                          "multiple functions with a #[main] attribute");
             }
-
-            if attr::contains_name(&item.attrs, "start") {
-                if ctxt.start_fn.is_none() {
-                    ctxt.start_fn = Some((item.id, item.span));
-                } else {
-                    span_err!(ctxt.session, item.span, E0138,
-                              "multiple 'start' functions");
-                }
+        },
+        EntryPointType::Start => {
+            if ctxt.start_fn.is_none() {
+                ctxt.start_fn = Some((item.id, item.span));
+            } else {
+                span_err!(ctxt.session, item.span, E0138,
+                          "multiple 'start' functions");
             }
-        }
-        _ => ()
+        },
+        EntryPointType::None => ()
     }
 
     visit::walk_item(ctxt, item);
diff --git a/src/libsyntax/entry.rs b/src/libsyntax/entry.rs
new file mode 100644
index 00000000000..b6c5d0066a2
--- /dev/null
+++ b/src/libsyntax/entry.rs
@@ -0,0 +1,42 @@
+// Copyright 2012-2015 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 attr;
+use ast::{Item, ItemFn};
+
+pub enum EntryPointType {
+    None,
+    MainNamed,
+    MainAttr,
+    Start,
+    OtherMain, // Not an entry point, but some other function named main
+}
+
+pub fn entry_point_type(item: &Item, depth: usize) -> EntryPointType {
+    match item.node {
+        ItemFn(..) => {
+            if attr::contains_name(&item.attrs, "start") {
+                EntryPointType::Start
+            } else if attr::contains_name(&item.attrs, "main") {
+                EntryPointType::MainAttr
+            } else if item.ident.name == "main" {
+                if depth == 1 {
+                    // This is a top-level function so can be 'main'
+                    EntryPointType::MainNamed
+                } else {
+                    EntryPointType::OtherMain
+                }
+            } else {
+                EntryPointType::None
+            }
+        }
+        _ => EntryPointType::None,
+    }
+}
diff --git a/src/libsyntax/lib.rs b/src/libsyntax/lib.rs
index 0d1fa6dd726..d1c862ad40b 100644
--- a/src/libsyntax/lib.rs
+++ b/src/libsyntax/lib.rs
@@ -90,6 +90,7 @@ pub mod attr;
 pub mod codemap;
 pub mod config;
 pub mod diagnostic;
+pub mod entry;
 pub mod feature_gate;
 pub mod fold;
 pub mod owned_slice;
diff --git a/src/libsyntax/test.rs b/src/libsyntax/test.rs
index 26fb287ce35..7fb8cdde311 100644
--- a/src/libsyntax/test.rs
+++ b/src/libsyntax/test.rs
@@ -14,6 +14,7 @@
 #![allow(unused_imports)]
 use self::HasTestSignature::*;
 
+use std::iter;
 use std::slice;
 use std::mem;
 use std::vec;
@@ -24,6 +25,7 @@ use codemap::{DUMMY_SP, Span, ExpnInfo, NameAndSpan, MacroAttribute};
 use codemap;
 use diagnostic;
 use config;
+use entry::{self, EntryPointType};
 use ext::base::ExtCtxt;
 use ext::build::AstBuilder;
 use ext::expand::ExpansionConfig;
@@ -173,28 +175,6 @@ impl<'a> fold::Folder for TestHarnessGenerator<'a> {
         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);
@@ -211,6 +191,55 @@ impl<'a> fold::Folder for TestHarnessGenerator<'a> {
     }
 }
 
+struct EntryPointCleaner {
+    // Current depth in the ast
+    depth: usize,
+}
+
+impl fold::Folder for EntryPointCleaner {
+    fn fold_item(&mut self, i: P<ast::Item>) -> SmallVector<P<ast::Item>> {
+        self.depth += 1;
+        let folded = fold::noop_fold_item(i, self).expect_one("noop did something");
+        self.depth -= 1;
+
+        // Remove any #[main] or #[start] from the AST so it doesn't
+        // clash with the one we're going to add, but mark it as
+        // #[allow(dead_code)] to avoid printing warnings.
+        let folded = match entry::entry_point_type(&*folded, self.depth) {
+            EntryPointType::MainNamed |
+            EntryPointType::MainAttr |
+            EntryPointType::Start =>
+                folded.map(|ast::Item {id, ident, attrs, node, vis, span}| {
+                    let allow_str = InternedString::new("allow");
+                    let dead_code_str = InternedString::new("dead_code");
+                    let allow_dead_code_item =
+                        attr::mk_list_item(allow_str,
+                                           vec![attr::mk_word_item(dead_code_str)]);
+                    let allow_dead_code = attr::mk_attr_outer(attr::mk_attr_id(),
+                                                              allow_dead_code_item);
+
+                    ast::Item {
+                        id: id,
+                        ident: ident,
+                        attrs: attrs.into_iter()
+                            .filter(|attr| {
+                                !attr.check_name("main") && !attr.check_name("start")
+                            })
+                            .chain(iter::once(allow_dead_code))
+                            .collect(),
+                        node: node,
+                        vis: vis,
+                        span: span
+                    }
+                }),
+            EntryPointType::None |
+            EntryPointType::OtherMain => folded,
+        };
+
+        SmallVector::one(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 super_ = token::str_to_ident("super");
@@ -246,6 +275,10 @@ fn generate_test_harness(sess: &ParseSess,
                          krate: ast::Crate,
                          cfg: &ast::CrateConfig,
                          sd: &diagnostic::SpanHandler) -> ast::Crate {
+    // Remove the entry points
+    let mut cleaner = EntryPointCleaner { depth: 0 };
+    let krate = cleaner.fold_crate(krate);
+
     let mut feature_gated_cfgs = vec![];
     let mut cx: TestCtxt = TestCtxt {
         sess: sess,
diff --git a/src/test/compile-fail/test-warns-dead-code.rs b/src/test/compile-fail/test-warns-dead-code.rs
new file mode 100644
index 00000000000..0e25f1e965a
--- /dev/null
+++ b/src/test/compile-fail/test-warns-dead-code.rs
@@ -0,0 +1,17 @@
+// Copyright 2015 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.
+
+// compile-flags: --test
+
+#![deny(dead_code)]
+
+fn dead() {} //~ error: function is never used: `dead`
+
+fn main() {}
diff --git a/src/test/run-pass/test-main-not-dead-attr.rs b/src/test/run-pass/test-main-not-dead-attr.rs
new file mode 100644
index 00000000000..295559b6ddb
--- /dev/null
+++ b/src/test/run-pass/test-main-not-dead-attr.rs
@@ -0,0 +1,18 @@
+// Copyright 2015 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.
+
+// compile-flags: --test
+
+#![feature(main)]
+
+#![deny(dead_code)]
+
+#[main]
+fn foo() { panic!(); }
diff --git a/src/test/run-pass/test-main-not-dead.rs b/src/test/run-pass/test-main-not-dead.rs
new file mode 100644
index 00000000000..7de3ca74796
--- /dev/null
+++ b/src/test/run-pass/test-main-not-dead.rs
@@ -0,0 +1,15 @@
+// Copyright 2015 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.
+
+// compile-flags: --test
+
+#![deny(dead_code)]
+
+fn main() { panic!(); }
diff --git a/src/test/run-pass/test-runner-hides-buried-main.rs b/src/test/run-pass/test-runner-hides-buried-main.rs
new file mode 100644
index 00000000000..7ba10850403
--- /dev/null
+++ b/src/test/run-pass/test-runner-hides-buried-main.rs
@@ -0,0 +1,24 @@
+// Copyright 2015 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.
+
+// compile-flags: --test
+
+#![feature(main)]
+
+#![allow(dead_code)]
+
+mod a {
+    fn b() {
+        || {
+            #[main]
+            fn c() { panic!(); }
+        };
+    }
+}
diff --git a/src/test/run-pass/test-runner-hides-start.rs b/src/test/run-pass/test-runner-hides-start.rs
new file mode 100644
index 00000000000..fc94b19ada1
--- /dev/null
+++ b/src/test/run-pass/test-runner-hides-start.rs
@@ -0,0 +1,16 @@
+// Copyright 2015 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.
+
+// compile-flags: --test
+
+#![feature(start)]
+
+#[start]
+fn start(_: isize, _: *const *const u8) -> isize { panic!(); }