about summary refs log tree commit diff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/librustc/front/test.rs9
-rw-r--r--src/librustc/middle/resolve.rs56
-rw-r--r--src/librustc/middle/trans/base.rs10
-rw-r--r--src/test/compile-fail/multiple-main-2.rs17
-rw-r--r--src/test/compile-fail/multiple-main-3.rs19
-rw-r--r--src/test/run-pass/attr-main-2.rs17
-rw-r--r--src/test/run-pass/attr-main.rs13
7 files changed, 127 insertions, 14 deletions
diff --git a/src/librustc/front/test.rs b/src/librustc/front/test.rs
index 870a7d6c593..0c4b9635a36 100644
--- a/src/librustc/front/test.rs
+++ b/src/librustc/front/test.rs
@@ -25,6 +25,7 @@ use syntax::codemap::span;
 use syntax::fold;
 use syntax::print::pprust;
 use syntax::{ast, ast_util};
+use syntax::attr::attrs_contains_name;
 
 export modify_for_testing;
 
@@ -88,13 +89,11 @@ fn fold_mod(cx: test_ctxt, m: ast::_mod, fld: fold::ast_fold) -> ast::_mod {
     // Remove any defined main function from the AST so it doesn't clash with
     // the one we're going to add. Only if compiling an executable.
 
-    // FIXME (#2403): This is sloppy. Instead we should have some mechanism to
-    // indicate to the translation pass which function we want to be main.
     fn nomain(cx: test_ctxt, item: @ast::item) -> Option<@ast::item> {
         match item.node {
           ast::item_fn(*) => {
-            if item.ident == cx.sess.ident_of(~"main")
-                && !cx.sess.building_library {
+            if attrs_contains_name(item.attrs, ~"main")
+                    && !cx.sess.building_library {
                 option::None
             } else { option::Some(item) }
           }
@@ -498,7 +497,7 @@ fn mk_main(cx: test_ctxt) -> @ast::item {
     let item_ = ast::item_fn(decl, ast::impure_fn, ~[], body);
     let item: ast::item =
         {ident: cx.sess.ident_of(~"main"),
-         attrs: ~[],
+         attrs: ~[attr::mk_attr(attr::mk_word_item(~"main"))],
          id: cx.sess.next_node_id(),
          node: item_,
          vis: ast::public,
diff --git a/src/librustc/middle/resolve.rs b/src/librustc/middle/resolve.rs
index a7c579127f9..e5d3eb558b3 100644
--- a/src/librustc/middle/resolve.rs
+++ b/src/librustc/middle/resolve.rs
@@ -59,7 +59,7 @@ use syntax::ast_util::{def_id_of_def, dummy_sp, local_def};
 use syntax::ast_util::{path_to_ident, walk_pat, trait_method_to_ty_method};
 use syntax::ast_util::{Privacy, Public, Private, visibility_to_privacy};
 use syntax::ast_util::has_legacy_export_attr;
-use syntax::attr::{attr_metas, contains_name};
+use syntax::attr::{attr_metas, contains_name, attrs_contains_name};
 use syntax::parse::token::ident_interner;
 use syntax::parse::token::special_idents;
 use syntax::print::pprust::{pat_to_str, path_to_str};
@@ -857,6 +857,9 @@ fn Resolver(session: Session, lang_items: LanguageItems,
 
         namespaces: ~[ TypeNS, ValueNS ],
 
+        attr_main_fn: None,
+        main_fns: ~[],
+
         def_map: HashMap(),
         export_map2: HashMap(),
         trait_map: @HashMap(),
@@ -916,6 +919,11 @@ struct Resolver {
     // The four namespaces.
     namespaces: ~[Namespace],
 
+    // The function that has attribute named 'main'
+    mut attr_main_fn: Option<(node_id, span)>,
+    // The functions named 'main'
+    mut main_fns: ~[Option<(node_id, span)>],
+
     def_map: DefMap,
     export_map2: ExportMap2,
     trait_map: TraitMap,
@@ -937,6 +945,7 @@ impl Resolver {
         self.resolve_crate();
         self.session.abort_if_errors();
 
+        self.check_duplicate_main();
         self.check_for_unused_imports_if_necessary();
     }
 
@@ -3923,15 +3932,22 @@ impl Resolver {
             item_fn(ref fn_decl, _, ref ty_params, ref block) => {
                 // If this is the main function, we must record it in the
                 // session.
-                //
-                // For speed, we put the string comparison last in this chain
-                // of conditionals.
+                if !self.session.building_library {
+                    if self.attr_main_fn.is_none() &&
+                           item.ident == special_idents::main {
 
-                if !self.session.building_library &&
-                    is_none(&self.session.main_fn) &&
-                    item.ident == special_idents::main {
+                        self.main_fns.push(Some((item.id, item.span)));
+                    }
 
-                    self.session.main_fn = Some((item.id, item.span));
+                    if attrs_contains_name(item.attrs, ~"main") {
+                        if self.attr_main_fn.is_none() {
+                            self.attr_main_fn = Some((item.id, item.span));
+                        } else {
+                            self.session.span_err(
+                                    item.span,
+                                    ~"multiple 'main' functions");
+                        }
+                    }
                 }
 
                 self.resolve_function(OpaqueFunctionRibKind,
@@ -5354,6 +5370,30 @@ impl Resolver {
     }
 
     //
+    // main function checking
+    //
+    // be sure that there is only one main function
+    //
+    fn check_duplicate_main() {
+        if self.attr_main_fn.is_none() {
+            if self.main_fns.len() >= 1u {
+                let mut i = 1u;
+                while i < self.main_fns.len() {
+                    let (_, dup_main_span) =
+                            option::unwrap(self.main_fns[i]);
+                    self.session.span_err(
+                        dup_main_span,
+                        ~"multiple 'main' functions");
+                    i += 1;
+                }
+                self.session.main_fn = self.main_fns[0];
+            }
+        } else {
+            self.session.main_fn = self.attr_main_fn;
+        }
+    }
+
+    //
     // Unused import checking
     //
     // Although this is a lint pass, it lives in here because it depends on
diff --git a/src/librustc/middle/trans/base.rs b/src/librustc/middle/trans/base.rs
index 40740be54cf..5a3046ac248 100644
--- a/src/librustc/middle/trans/base.rs
+++ b/src/librustc/middle/trans/base.rs
@@ -2153,13 +2153,21 @@ fn register_fn_fuller(ccx: @crate_ctxt,
     ccx.item_symbols.insert(node_id, ps);
 
     // FIXME #4404 android JNI hacks
-    let is_main = is_main_name(path) && (!ccx.sess.building_library ||
+    let is_main = is_main_fn(&ccx.sess, node_id) &&
+                     (!ccx.sess.building_library ||
                       (ccx.sess.building_library &&
                        ccx.sess.targ_cfg.os == session::os_android));
     if is_main { create_main_wrapper(ccx, sp, llfn); }
     llfn
 }
 
+fn is_main_fn(sess: &Session, node_id: ast::node_id) -> bool {
+    match sess.main_fn {
+        Some((main_id, _)) => node_id == main_id,
+        None => false
+    }
+}
+
 // Create a _rust_main(args: ~[str]) function which will be called from the
 // runtime rust_start function
 fn create_main_wrapper(ccx: @crate_ctxt, sp: span, main_llfn: ValueRef) {
diff --git a/src/test/compile-fail/multiple-main-2.rs b/src/test/compile-fail/multiple-main-2.rs
new file mode 100644
index 00000000000..723aefb91cb
--- /dev/null
+++ b/src/test/compile-fail/multiple-main-2.rs
@@ -0,0 +1,17 @@
+// 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.
+
+#[main]
+fn bar() {
+}
+
+#[main]
+fn foo() { //~ ERROR multiple 'main' functions
+}
diff --git a/src/test/compile-fail/multiple-main-3.rs b/src/test/compile-fail/multiple-main-3.rs
new file mode 100644
index 00000000000..36da3e6e84a
--- /dev/null
+++ b/src/test/compile-fail/multiple-main-3.rs
@@ -0,0 +1,19 @@
+// 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.
+
+#[main]
+fn main1() {
+}
+
+mod foo {
+    #[main]
+    fn main2() { //~ ERROR multiple 'main' functions
+    }
+}
diff --git a/src/test/run-pass/attr-main-2.rs b/src/test/run-pass/attr-main-2.rs
new file mode 100644
index 00000000000..78fb9d3e39a
--- /dev/null
+++ b/src/test/run-pass/attr-main-2.rs
@@ -0,0 +1,17 @@
+// 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.
+
+fn main() {
+    fail
+}
+
+#[main]
+fn foo() {
+}
diff --git a/src/test/run-pass/attr-main.rs b/src/test/run-pass/attr-main.rs
new file mode 100644
index 00000000000..782240fd982
--- /dev/null
+++ b/src/test/run-pass/attr-main.rs
@@ -0,0 +1,13 @@
+// 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.
+
+#[main]
+fn foo() {
+}